Model coordinates to world coordinates

Hey YAQ (Yet another Question)



Well in my old engine I would have engine blasts emerging from certain faces on my model. This I would do by reading what the center coord for that face was (can be done in wings3d) and then constantly translating that model coordnate to world by multiplying the rotation/translation matrix. with the model coord.



So to make a cool looking engine blast I could just make particles emerge from that point every frame.



Can I do something like this in jME?



PS I have looked in the tests and found something similar in particle system example usage calles Milkshape emitter, but cant find it in the jmetest package.

Its under jmetest.renderer.loader and the class is called “TestFireMilk”



However, what this does is actually obtain a random vertex from your model and just emitt from it. What you want to do is restrict this to only 2 vertices.



However, i wouldn’t go down that route if i was you…because it would mean altering the particle system to use specific vertices, when it can easily be done in another way.



The other way would be to create a node, add the spaceship there, and two particle systems in the engines’ place. Then, instead of moving the spaceship, move the newly created node. This would also move and rotate the particles. However, there is a danger that the particle’s will not become billboarded everytime.



So to compensate for the rotation, you can do two things (the first works, the second is cleaner, but untested):


  1. manager.setEmissionDirection(shipSuperNode.getLocalRotation().mult(new Vector3f(0,0,1)));



This would make the particles billboarded correctly. You have to call this every update/every movement of the particle system

2) which is the cleaner solution, and i haven't tested this yet, is to make your ship node, attach your ship, then create a "BillboardNode" (this is under com.jme.scene.BillboardNode) and attach the particles to that. This would mean the only thing you have to do is add an extra node (a *tiny* bit more memory), but it would allow you not to call that setEmissionDirection thing, saving up some valuable time for logic or rendering or whatever...

Those are your two options (again, no. 2 is untested, but should work from design), hope that helps.

DP

hmmm



This solution would mean that all particles in a blast would rotate when ship node did, right? This shouldent be the case, as soon as a particle is released from engine it should have it own world position and speed.



But perhaps I am not understanding your solution correctly?

check out how it’s done in TestDynamicSmoker… You’ll see I added an “emission zone” trimesh to the model at the point where I wanted the smoke to come out and also it stays relevant to the world once emitted (vs. TestRigidSmoker) It is also able to do all that without screwing up the particle billboarding.

ah yes now I can get it to work… A word of advise remember if you have scaled your model, cause then your coords wont fit :slight_smile:





Now to make it look good





I cant seem to get any color on my particl emitter. Can this be some alpha issue. I have a skybox created?

Hmm, are you using the same alpha as in the particle demos? I’ve used it with skybox without issue but you can always force the skybox to cull and see how the particles look.

"middy" wrote:
I cant seem to get any color on my particl emitter. Can this be some alpha issue. I have a skybox created?

Have you tried calling setLightCombineMode(LightState.OFF) on your particles (ParticleManager.getParticles())?

duh… ofcourse light…

Hey I tried testing my exaust while moving the ship. If I move the ship sideways the particle also move sideways, meaning that when the ship gets rotated/translated the particles also. This makes sense in the way I set it up as suggested by DarkProphet, but can I do this in another way?.



My hiracy



rootNode

|

shipNode

| |

Particle shuttle





/*
 * Created on Feb 11, 2005
 * This file is created for the Extorris game
 * and is copyrighted
 */
package com.extorris.test;



/**
 * @author oliver
 *Feb 11, 2005
 */
import com.extorris.effects.ExhaustEffect;
import com.extorris.node.NebulaSkyBox;
import com.extorris.node.spaceship.Shuttle;
import com.extorris.node.spaceship.SpaceShipFactory;
import com.jme.animation.SpatialTransformer;
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.effects.ParticleManager;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Geometry;
import com.jme.scene.Node;
import com.jme.scene.TriMesh;
import com.jme.scene.shape.Box;
import com.jmex.physics.DynamicPhysicsObject;
import com.jmex.physics.PhysicsWorld;
import com.jmex.physics.StaticPhysicsObject;







/**
 * @author DarkProphet
 * @version: $Id: TestShipEffects.java, Feb 11, 2005 2:35:38 PM
 */
public class TestShipEffects extends SimpleGame {
   
   Geometry geo;
   private Node shipNode;
   
   private Quaternion rotQuat;
   private float angle = 0;
   private Vector3f axis;
   
   private Node particleNode;

   protected void simpleUpdate() {
       PhysicsWorld.getInstance().update();
       
       if (tpf < 1) {
           angle = angle + (tpf * 25);
           if (angle > 360) {
             angle = 0;
           }
         }

         rotQuat.fromAngleAxis(angle * FastMath.DEG_TO_RAD, axis);
       //  shipNode.setLocalRotation(rotQuat);
         shipNode.setLocalTranslation(shipNode.getLocalTranslation().add(new Vector3f(0.01f,0f,0f)));
       
    }

   protected void simpleInitGame() {
       display.setTitle("Test of Ship Effects");
       cam.setLocation(new Vector3f(0.0f, 5.0f, 10.0f));
       cam.update();
       
       rotQuat = new Quaternion();
       axis = new Vector3f(1, 1, 0.5f);
       
       shipNode = new Node("ShipNode");
     
      //create skybox
      NebulaSkyBox skybox = new NebulaSkyBox();
      rootNode.attachChild(skybox);
      rootNode.setForceView(true);
     
      //create physicworld
      PhysicsWorld.create();
      PhysicsWorld.getInstance().setUpdateRate(100);
      PhysicsWorld.getInstance().setStepSize(1 / 100f);
      PhysicsWorld.getInstance().setGravity(new Vector3f(0, 0, 0));
     
      //create shuttle
      Shuttle shuttle = SpaceShipFactory.produceShuttle("shuttle");
      geo = (Geometry) shuttle.getChild(0);     
      shipNode.attachChild(shuttle);
     
      ParticleManager manager = ExhaustEffect.getExaustEffect(new Vector3f(0.11693f,
                        0.88654f, -0.407047f),new Vector3f(0,0,-1));
     
      manager.setEmissionDirection(shipNode.getLocalRotation().mult(new Vector3f(0,0,-1)));
     
    /*  ParticleManager manager2 = ExhaustEffect.getExaustEffect(new Vector3f(-0.101082f,
                0.886607f, -0.407047f),new Vector3f(0,0,-1));
     
      ParticleManager manager3 = ExhaustEffect.getExaustEffect(new Vector3f(-0.616357f,
                0.284557f, -0.549f),new Vector3f(0,0,-1));
     
      ParticleManager manager4 = ExhaustEffect.getExaustEffect(new Vector3f(0.632013f,
                0.284422f, -0.549f),new Vector3f(0,0,-1));
     
      shipNode.attachChild(manager4.getParticles());
     
      shipNode.attachChild(manager3.getParticles());
     
      shipNode.attachChild(manager2.getParticles());*/
   
      shipNode.attachChild(manager.getParticles());
     

     
      //Creates the box that makes out the floor.
      Box floor = new Box("Floor", new Vector3f(), 50, 1, 50);
      floor.setModelBound(new BoundingBox());
      floor.updateModelBound();

     // We move it down 5 units, and away from the camera 10 units.
     floor.getLocalTranslation().y = -200f;
     rootNode.attachChild(floor);
     rootNode.attachChild(shipNode);
     shipNode.updateGeometricState(0, true);

     // I create a controller to rotate my pivot
     SpatialTransformer st=new SpatialTransformer(1);
     // I tell my spatial controller to change pivot
     st.setObject(shipNode,0,-1);

     // Assign a rotation for object 0 at time 2 to rotate 180 degrees around the z axis
     Quaternion x180=new Quaternion();
     x180.fromAngleAxis(FastMath.DEG_TO_RAD*180,new Vector3f(0,0,1));
     st.setRotation(0,2,x180);

 
     
     
         
     StaticPhysicsObject floorObj = new StaticPhysicsObject(floor);
     PhysicsWorld.getInstance().addObject(floorObj);
     
     DynamicPhysicsObject obj = new DynamicPhysicsObject(geo, 100);
     PhysicsWorld.getInstance().addObject(obj);
         
   }

   public static void main(String[] args) {
      TestShipEffects app = new TestShipEffects();
      app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
      app.start();
   }
}

do you want the tails to bend a bit basically or what effect are you aiming for? Sounds like you are saying the flames are like a stick, sticking out the back of the ship rigidly.

uuhm I only just now found the demo TestDynamicSmoker and its exactly the effect I want. I was perviously looking at TestRigidSmoker instead.



Sorry about bothering you I will test some more



But you are right I am saying that the flames are like a stick.

hehe, great. Yeah, the dynamic smoker is a good start there. good luck.

Hey middy, sounds like you want to achieve something like this:





In that case maybe this class will help ya (Thruster is just a Node with some additional properties, attached to the vessel node):

package aviation.effects;

import aviation.game.Thruster;

import com.jme.bounding.BoundingSphere;
import com.jme.effects.ParticleManager;
import com.jme.image.Texture;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;

/**
 * Handles displaying of the jet effect of a thruster.
 *
 * @author Per Thulin
 */
public class JetEffect extends Controller {
   private static final float MAX_LIFETIME = 100;
   private static final float MIN_LIFETIME = 0;
   private static final float INCREASE_SPEED = 100f;
   private static final float DECREASE_SPEED = 200f;
   private float lifeTime = MIN_LIFETIME;
   
   private ParticleManager manager;   
   private Thruster thruster;
   
   // Temp variables to flatline memory usage.
   private final Vector3f direction = new Vector3f(0,0,-1);
   private final Vector3f store = new Vector3f();
   
   /**
    *
    * @param thruster The thruster to attach this jet effect to.
    */
   public JetEffect(Thruster thruster) {      
      
      this.thruster = thruster;
      
      DisplaySystem display = DisplaySystem.getDisplaySystem();      
      AlphaState alpha = display.getRenderer().createAlphaState();
      alpha.setBlendEnabled(true);
      alpha.setSrcFunction(AlphaState.SB_SRC_ALPHA);
      alpha.setDstFunction(AlphaState.DB_ONE);
      alpha.setTestEnabled(true);
      alpha.setTestFunction(AlphaState.TF_GREATER);
      alpha.setEnabled(true);
      
      TextureState tState = display.getRenderer().createTextureState();
      tState.setTexture(
            TextureManager.loadTexture(
                  thruster.getTextureURL(),
                  Texture.MM_LINEAR_LINEAR,
                  Texture.FM_LINEAR)
      );
      tState.setEnabled(true);
      
      ZBufferState zState = display.getRenderer().createZBufferState();
      zState.setWritable(false);
      zState.setEnabled(true);
      zState.setFunction(ZBufferState.CF_LEQUAL);
      
      manager = new ParticleManager(300,
            display.getRenderer().getCamera());       
      
      manager.setGravityForce(new Vector3f(0.0f, 0.0f, 0.0f));
      manager.setEmissionMaximumAngle(0.017453292f);
      manager.setSpeed(1.0f);
      manager.setParticlesMinimumLifeTime(lifeTime);
      manager.setStartSize(6.6f);
      manager.setEndSize(30.0f);
      manager.setStartColor(thruster.getStartColor());
      manager.setEndColor(thruster.getEndColor());
      manager.setRandomMod(10.0f);
      manager.setControlFlow(false);
      manager.setReleaseRate(300);
      manager.setReleaseVariance(0.0f);
      manager.setInitialVelocity(1.4599999f);
      manager.setParticleSpinSpeed(0.0f);
      
      manager.getParticles().setModelBound(new BoundingSphere());
      manager.getParticles().updateModelBound();
      
      manager.warmUp(1000);
      manager.getParticles().addController(manager);
      
      manager.getParticles().setLightCombineMode(LightState.OFF);
      
      // Make it somewhat smaller.
      manager.getParticles().setLocalScale(0.05f);
      
      manager.setParticlesOrigin(thruster.getLocalTranslation());
      
      manager.getParticles().setRenderState(tState);
      manager.getParticles().setRenderState(alpha);
      manager.getParticles().setRenderState(zState);
      manager.getParticles().updateRenderState();
      
      thruster.attachChild(manager.getParticles());
   }
   
   private void makeJetBigger(float speed) {
      lifeTime += speed;
      
      if (lifeTime > MAX_LIFETIME) lifeTime = MAX_LIFETIME;
      
      manager.setParticlesMinimumLifeTime(lifeTime);
   }
   
   private void makeJetSmaller(float speed) {
      lifeTime -= speed;
      
      if (lifeTime < MIN_LIFETIME) lifeTime = MIN_LIFETIME;
      
      manager.setParticlesMinimumLifeTime(lifeTime);
   }
   
   public void update(float tpf) {
      thruster.getWorldRotation().mult(direction, store);
      manager.setEmissionDirection(store);
      
      if (thruster.isActive()) makeJetBigger(tpf*INCREASE_SPEED);
      else makeJetSmaller(tpf*DECREASE_SPEED);
   }
   
}



This jet doesn't behave like a stick :)

ah crap this is weird. I have done exactly as in TestDynamicSmoker but it will not work.





OK… in dynamic smoker we have:



1 node - smokenode



1 node - camBox



1 trimesh - smoke



1 particle manager - manager



1 disk Emit disk - emitDisk





smokeNode ,smoke child of rootNode



camBox,emitDisk are child of smokenode



smoke is a controller to particle manager?? (what does this mean)



Anyway I have a big disk rotating behind my ship, but the particle stream stays where it are. it rotates but is not dynamic (stick effect)



I did exactly the same with my stuff (as you can see below)




/*
 * Created on Feb 11, 2005
 * This file is created for the Extorris game
 * and is copyrighted
 */
package com.extorris.test;



/**
 * @author oliver
 *Feb 11, 2005
 */
import jmetest.effects.TestDynamicSmoker;

import com.extorris.node.NebulaSkyBox;
import com.extorris.node.spaceship.Shuttle;
import com.extorris.node.spaceship.SpaceShipFactory;
import com.jme.app.SimpleGame;
import com.jme.effects.ParticleManager;
import com.jme.image.Texture;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Geometry;
import com.jme.scene.Node;
import com.jme.scene.TriMesh;
import com.jme.scene.shape.Disk;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.util.TextureManager;







/**
 * @author DarkProphet
 * @version: $Id: TestShipEffects.java, Feb 11, 2005 2:35:38 PM
 */
public class TestShipEffects extends SimpleGame {
   
   private Node shipNode;
   
   private Quaternion rotQuat;
   private float angle = 0;
   private Vector3f axis;
   
   private TriMesh exhaust;
   
   ParticleManager manager;

   protected void simpleUpdate() {
   
   
       if (tpf < 1) {
           angle = angle + (tpf * 25);
           if (angle > 360) {
             angle = 0;
           }
         }

         rotQuat.fromAngleAxis(angle * FastMath.DEG_TO_RAD, axis);
         shipNode.setLocalRotation(rotQuat);
         shipNode.setLocalTranslation(shipNode.getLocalTranslation().add(new Vector3f(0.001f,0f,0f)));
     
             manager.setEmissionDirection(shipNode.getLocalRotation().mult(new Vector3f(0,0,1)));
           
    }

   protected void simpleInitGame() {
       display.setTitle("Test of Ship Effects");
       cam.setLocation(new Vector3f(0.0f, 5.0f, 10.0f));
       cam.update();
       
       rotQuat = new Quaternion();
       axis = new Vector3f(1, 1, 0.5f);
       
       shipNode = new Node("ShipNode");
       shipNode.updateGeometricState(0, true);
     
      //create skybox
      NebulaSkyBox skybox = new NebulaSkyBox();
      rootNode.attachChild(skybox);
      rootNode.setForceView(true);
     
     
      //create shuttle
      Shuttle shuttle = SpaceShipFactory.produceShuttle("shuttle");   
      shipNode.attachChild(shuttle);
     
      Disk emitDisc = new Disk("disc", 6, 6, 1.5f);
      emitDisc.setLocalTranslation(new Vector3f(-0.101082f,
              0.886607f, -0.407047f));
      shipNode.attachChild(emitDisc);
      rootNode.attachChild(shipNode);
     

      AlphaState as1 = display.getRenderer().createAlphaState();
      as1.setBlendEnabled(true);
      as1.setSrcFunction(AlphaState.SB_SRC_ALPHA);
      as1.setDstFunction(AlphaState.DB_ONE);
      as1.setTestEnabled(true);
      as1.setTestFunction(AlphaState.TF_GREATER);
      as1.setEnabled(true);

      TextureState ts = display.getRenderer().createTextureState();
      ts.setTexture(
          TextureManager.loadTexture(
          TestDynamicSmoker.class.getClassLoader().getResource(
          "jmetest/data/texture/flaresmall.jpg"),
          Texture.MM_LINEAR_LINEAR,
          Texture.FM_LINEAR,
          true));
      ts.setEnabled(true);

      manager = new ParticleManager(300, display.getRenderer().getCamera());
      manager.setGravityForce(new Vector3f(0.0f, 0.0f, 0.0f));
      manager.setEmissionDirection(new Vector3f(0f, 0f, 1f));
      manager.setEmissionMaximumAngle(0.0f);
      manager.setSpeed(1.0f);
      manager.setParticlesMinimumLifeTime(750.0f);
      manager.setStartSize(1.6f);
      manager.setEndSize(15.0f);
      manager.setStartColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
      manager.setEndColor(new ColorRGBA(0.6f, 0.2f, 0.0f, 0.0f));
      manager.setRandomMod(.5f);
      manager.setInitialVelocity(0.5f);     
      manager.getParticles().setLocalScale(0.005f);
      manager.setGeometry(emitDisc);


     
     
     
      exhaust = manager.getParticles();
      exhaust.addController(manager);
     
      ZBufferState zbuf = display.getRenderer().createZBufferState();
      zbuf.setWritable(false);
      zbuf.setEnabled(true);
      zbuf.setFunction(ZBufferState.CF_LEQUAL);

      exhaust.setRenderState(ts);
      exhaust.setRenderState(as1);
      exhaust.setRenderState(zbuf);
      rootNode.attachChild(exhaust);
     
     
 
   }

   public static void main(String[] args) {
      TestShipEffects app = new TestShipEffects();
      app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
      app.start();
   }
}

"Per" wrote:
Hey middy, sounds like you want to achieve something like this:
(image)
This jet doesn't behave like a stick :)

Hi Per,

according to the image and the code you posted you are doing something very similar to me :P
I'm currently testing the physics engine to simulate space ships: Multiple steering thrusters are influencing the ship via addForceAt - works very nice.
Your post solved the problem that the fire, spit by the thrusters, was seen through everything (wrong zBuffer settings).

Thanks and best regards,
Irrisor

This actually seems to work just fine… the reason it’s not moving correctly along with the ship is because of the scaling you added. It is dynamic though (see how the flame bends as it turns?) I’ll look at fixing the scaling related issue.

Ok, the fix is in cvs. This will probably effect people who may have compensated for the bug manually… But better to have the fix in then be compensating every time. Let me know if any unsolvable problems crop up.



Also, you’ll probably want to shrink the radius and alter the position of the emit disc.

fix working… thanks :slight_smile:

excellent!

btw renanse



If I were to scale the emitdisk down it wouldent affect the "emit" area. Dunno if its problem