Heute habe ich (nach einigen mehr oder weniger erfolgreichen Versuchen) eine Rakete mit einem angefügten Partikeleffekt in meine Projected Grid-Szene geladen. Um ein 3DS-Modell zu laden genügen folgende Zeilen:

// Point to a URL of my model
URL model = RocketTest.class.getClassLoader().getResource(string);
Node node = null;

// Create something to convert .3ds format to .jme
FormatConverter converter = new MaxToJme();

// This byte array will hold my .jme file
ByteArrayOutputStream bo = new ByteArrayOutputStream();
try {
// Use the format converter to convert .obj to .jme
converter.convert(model.openStream(), bo);
node = (Node)BinaryImporter.getInstance().load(new ByteArrayInputStream(bo.toByteArray()));
// shrink this baby down some
node.setLocalScale(1f);
node.setModelBound(new BoundingSphere());
node.updateModelBound();
} catch (IOException e) {
e.printStackTrace();
System.exit(0);
}

Der Partikeleffekt ist schon etwas komplizierter. Dazu gehört ein Emitter, ein AlphaState, ein TextureState, ein ParticleMesh und ein ZBufferState. Wie das ganze aufgebaut werden muss, kann man in der Demo-Klasse TestDynamicSmoker nachschauen. Hier kommen nur die wichtigsten Zeilen:

Node model = addModel("de/kopis/jme/Generic_Missile.3ds");
model.setLocalScale(10f);
model.setLocalTranslation(new Vector3f(0, 100, 00));
model.rotateUpTo(new Vector3f(0, 0, 1f));

// attach the smoke
Disk emitDisc = new Disk( "disc", 6, 6, 1.5f );
emitDisc.setLocalTranslation(new Vector3f(0, 5f, 0));
emitDisc.setCullMode(SceneElement.CULL_ALWAYS);
model.attachChild(emitDisc);
rootNode.attachChild(model);

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 ts1 = display.getRenderer().createTextureState();
ts1.setTexture(
TextureManager.loadTexture(
TestDynamicSmoker.class.getClassLoader().getResource(
"jmetest/data/texture/flaresmall.jpg" ),
Texture.MM_LINEAR_LINEAR,
Texture.FM_LINEAR ) );
ts1.setEnabled( true );

mesh = ParticleFactory.buildParticles("particles", 300);
mesh.setEmissionDirection( new Vector3f( 0f, 1f, 0f ) );
mesh.setMaximumAngle( 0.0f );
mesh.setSpeed(1f);
mesh.setMinimumLifeTime( 0.0f );
mesh.setMaximumLifeTime( 900.0f );
mesh.setStartSize( 1.6f );
mesh.setEndSize( 15.0f );
mesh.setStartColor( new ColorRGBA( 1.0f, 1.0f, 1.0f, 1.0f ) );
mesh.setEndColor( new ColorRGBA( 0.6f, 0.2f, 0.0f, 0.0f ) );
mesh.setInitialVelocity( 0.25f );
mesh.setGeometry( emitDisc );
mesh.setRotateWithScene(true);

mesh.forceRespawn();
mesh.warmUp( 60 );

mesh.setModelBound(new BoundingBox());
mesh.updateModelBound();

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

mesh.setRenderState( ts1 );
mesh.setRenderState( as1 );
mesh.setRenderState( zbuf );
rootNode.attachChild( mesh );

Ein paar Bilder mit unterschiedlichen Modellen gibt es schon bei Flickr zu sehen:

Rocket Test #1 Rocket Test #2 Rocket Test #3

Die Szene ist immer noch statisch, d.h. die Rakete bewegt sich nicht. Das Projected Grid Water und die Partikel-Rauchspur allerdings schon. Das ganze sieht einfach toll aus und ist mit wenigen Zeilen Quelltext erstellt. Gelobt sei JMonkeyEngine!

Als nächster Schritt wäre konsequenterweise die Steuerung der Rakete und eine Verfolgerkamera dran. Mal schauen, wie weit ich noch komme, bevor der Schlaf mich packt… :-)