README: RenderStates

Hey Folks,



Mojo has asked me to relay the following important information.



There have been some changes to the way render states work to better handle various state conditions. The important thing to know is that you MUST call the new Spatial method updateRenderState() in order for any state changes to take affect. The best way to do this is to call it on the root node of your tree near the end of initGame. If you have multiple trees, (like several of our demos which have fpsNode as a separate tree,) make sure you call it on all roots. Every one of the tests has been updated and verified to be correct.



The other thing to make note of is the state collapsing. This feature addition affects lights and textures. Basically, if you have multiple lightstates or texturestates along a given path from the root to a given node, the node may compact those states into a single state. How this compacting occurs at a given Geometry is definable by setting the appropriate mode at that Geometry, but the defaults should cover most situations.



For lightstates, the default mode will collect all the lights (up to max of 8… ) in the gathered states and place them in a new state set at the given Geometry. For example, if you have a parent node with 1 light set and a child node with 2 lights set, the child would automatically apply a state with 3 lights set. See the javadoc notes in LightState for explanations of the other modes.



For texturestates, the default mode will start at the given Geometry and add Textures to a new TextureState at the position it finds them at in the various states. It will only add them to the new state if it doesn’t already have a texture at that index. For example, if a parent node has a texturestate with 2 textures (ie multitexture) and a child has a texturestate with only texture 1 assigned, the child will be draw multi-textured, with the texture 1 it was assigned in it’s state and the texture 2 from it’s parent (leaving out the texture 1 from it’s parent since it already has a texture 1.) Again, see the javadoc notes in TextureState for explanations of the other possible modes.



In most cases this change only means you need to go into the end of your initGame() method and add a updateRenderStates() call to your root node. However, if you have troubles adjusting to the new method of doing, please ask questions.





PS: Please note that for the compacting described above, the compacted states are not accessible (they are not actually set in the user accessible list of states.) So don’t think you can grab it by calling getRenderState(int).

I just want to mention how you’d change modes. For instance, let’s say you have a node A, this node has a texture state with multitexturing in unit 0 and 1. A has a child B, with a texture state with only one texture. By default, child B’s texture would collapse into having a multitexture of 0 and 1 where 1 is from A. Let’s say you don’t want this to happen, to change the way the combining works you’d say:



B.setTextureCombineMode(TextureState.REPLACE);



it’s that simple.

I may be misunderstanding how parent render states propagate.



I have node A with child B, and A.setRenderState( RS1 ), and B.setRenderState( RS2 ). What’s the simplified sequence of calls?



Assuming that RS1 and RS2 are of the same render state type (e.g. texture, light, etc.) is A’s render state still set when B renders, like this:

RS1.set()
render( A );
RS2.set();
render( B );
RS2.unset();
RS1.unset();



Or is it more like this?


RS1.set()
render( A );
RS1.unset();
RS2.set();
render( B );
RS2.unset();

The first is correct.

It’s more like the 1st, however it depends on the mode that is set on B as to whether RS1 will affect it or not.



Also, please note that there is no longer a set or unset. Only an apply.

What he said. 8)

What’s the contract about how render states propagate through the scene graph? I’m finding that, in the new system, render states can ‘bleed over’ to sibling nodes that are visited later on.

If you are finding bleeding, it is likely updateRenderState was not called in such a way as to be able to visit those node (ie, it was called too low of the tree and thus missed a few branches or perhaps it was not called on a second tree)



Renderstates follow Eberly’s 2.X modus operadi. Basically, renderstates are applied per Geometry. If you look at Geometry, it has a private array of RenderStates. This array is populated via updateRenderState by starting from the spatial you call it on and working down the tree, picking up states as it goes. It does this via a stack. The most recently added item to the stack for a given state type is placed in Geometry’s array. If no state exists for a given type, a default (disabled) state is used instead. States are removed from the stack when it finishes applying them to the Spatial it came from and any children it may have.



During rendering, the states are applied before drawing a given Geometry. If a Geometry is encountered that has no states, no state is called (meaning the last state used will be in affect.) This should only happen though if updateRenderState was not called on that Geometry.



That’s the basics anyhow, there’s obviously more to it. Hope the description helps.



(
Except for Lights and Texture which happen as described above.)

It all sounds very cool - and yeah, it seems that the propagation problem was mine. (What else!)

As a general fyi to this sticky post, please also see the combine mode additions described here:

http://www.jmonkeyengine.com/jmeforum/index.php?topic=556.0



EDIT: updated url