[Solved] Textures and updateRenderState

Hello everybody:



    I’ve been working on my NormalGenerator http://www.jmonkeyengine.com/jmeforum/index.php?topic=5768.0(shameless advertisement  ;)), and while toying with textures and RenderStates noticed something I think is a bug.



import com.jme.app.*;
import com.jme.math.*;
import com.jme.renderer.RenderContext;
import com.jme.renderer.Renderer;
import com.jme.scene.*;
import com.jme.scene.batch.*;
import com.jme.scene.shape.*;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;
import com.jme.util.resource.ResourceLocatorTool;
import java.net.URL;
import java.nio.*;
import java.util.ArrayList;

/**
 *
 * @author Edgar A. Duenez-Guzman
 */
public class TestBug extends SimpleGame
{
    private boolean flag = true;
    /** Creates a new instance of TestNormalGenerator */
    public TestBug()
    {
        super();
    }
    protected void simpleInitGame()
    {
        Box box1 = new Box( "Object1", new Vector3f( -1f, -1f, -1f ), new Vector3f( 1f, 1f, 1f ) );
        box1.setLocalTranslation( -3.0f, 0, 0 );
        rootNode.attachChild( box1 );
        Box box2 = new Box( "Object2", new Vector3f( -1f, -1f, -1f ), new Vector3f( 1f, 1f, 1f ) );
        box2.setLocalTranslation( 0.0f, 0, 0 );
        rootNode.attachChild( box2 );
        try {
            TextureState ts = display.getRenderer().createTextureState();
            ts.setEnabled( true );
            ts.setTexture( TextureManager.loadTexture( TestBug.class.getResource( "jmetest/data/images/buttonback.png" ) ) );
            box1.setRenderState( ts );
            box1.updateRenderState();
        } catch( Exception e ) { e.printStackTrace(); }
    }
    protected void simpleUpdate()
    {
        if( flag && timer.getTime() > 3000 )
        {
            flag = false;
            Box box3 = new Box( "Object3", new Vector3f( -1f, -1f, -1f ), new Vector3f( 1f, 1f, 1f ) );
            box3.setLocalTranslation( 0.0f, 3.0f, 0.0f );

            try {
                TextureState ts = display.getRenderer().createTextureState();
                ts.setEnabled( true );
                ts.setTexture( TextureManager.loadTexture( TestBug.class.getResource( "jmetest/data/images/Fieldstone.jpg" ) ) );
                box3.setRenderState( ts );
                box3.updateRenderState();
            } catch( Exception e ) { e.printStackTrace(); }

            rootNode.attachChild( box3 );
            rootNode.updateRenderState(); //<


*************************
        }
    }
    public static void main( String args[] )
    {
        TestBug t = new TestBug();
        t.start();
    }
}



The deal is this... the program creates 2 boxes, one with its own texture (and hence RenderState), I call updateRenderState on the box, and not on the rootNode because the state only modifies the box.

3 seconds later I create a third box with another texture and RenderState again calling updateRenderState only on this new object.

The bug is apparent if you comment the line marked with (too  ;)) many asterisks on the code. (Or commenting it out, and pressing 't' twice to force a call to updateRenderState on the rootNode)

The point is that the texture changes to a darker version  :-o. Not only that, but I think rootNode should not update anything (except geometric state perhaps).

Am I completely off?  :?

Here are screenshots:


I think the first one looks like it has no lightstates applied to. As if you had just disabled lighting on the node. I'll test it here.

Yep…



No bug… If you comment out the line, your third box just doesn't get the renderState information updated from the rootNode (lightstate included) and is bright because of the abstance of hardware lights. Test pressing 'L' and you'll see the same effect.

Well, but wouldn’t a call to updateRenderState take into account the parent’s render state and compute it accordingly? Besides, the bright box (which I agree is bright because no lighting is being applied) gets also rendered on top of the other boxes, which is even weirder.



If it is not a bug, I really think it is a very strange feature  :stuck_out_tongue:



I see your point now. Dunno if calling updateRenderState() should get the information bottom-up (calling in a leaf node to get info from parents)… I know the oposite propagates the states down the graph. Maybe one of the devs has something to say about it.

It gets rendered on top for the same reason as why the lighting doesnt work, it doesnt have a zbufferstate…I don't think it's a strange feature, and most scenegraph based engines use that way of propagating data(forward propagation). It's nice since you have control of what part of the tree that gets updated, for example if you change a state on a leaf node and don't want to go through the entire tree…I guess we could add in another set of update methods that uses extraction propagation for situations where you need that though.

Actually, updateRenderStates() does collect states from the parents all the way to the root and then applies forward from the node you originally called on. (see code)



That said, the bug is really a very simple one in your program, easy to overlook.  You correctly call box3.updateRenderState(), but you call it before attaching the box to the rootNode, therefore it does not get the states from the rootNode.

For me it's pretty clear now. Thanks guys.

Thanks Renanse, you are the man!  :smiley:

HTH :slight_smile:

wow! always nice to learn something new!  :smiley: