Materialproblem

Hi,



this is problably just some simple problem, but at the moment I can't understand it. I'm drawing up a number of different boxes which are all connected to the same parent node (nodeBox). I then give the nodeBox a material, and then all the boxes should get the same material. Problem is they don't. Or actually they do, but not in the expected way. Some of the boxes get the correct material, some of them gets the same material, BUT only on the inside of the box…



How can this happen? It seems to be symmetric around the origin, so I don't know if it can has something to do with their coordinates. I'll post a picture to demonstrate.

hey there,



maybe the normal vectors are inverted (point inside) the geometries where it goes wrong. Also, try this:


    lightState.setTwoSidedLighting(true);



cheers

yeah, I was thinking the same thing, the problem is I don't know how to change the normals if that is the problem.

I tested to set TwoSidedLightning, but there were no difference.

But I think it should be a bit strange if the boxes where created with different normals depending on where in the coordinatesystem they where placed? I use the standard jme box and all the boxes are created from the exact same code, the only difference is their placement.

Maybe you could provide the part where you create your boxes and add the material.

sure, here it comes:



Here I initiate a testbox and the node that all boxes have as parent (nodeBox) and also the material. Note that the testbox always has the material on the outside of the box.


// initiate testbox
Box box = new Box("box" + newObject(), new Vector3f(0, 0, 0), new Vector3f(10, 10, 10));
box.setModelBound(new BoundingBox());
box.updateModelBound();
box.setRandomColors();
boxNode = new Node("nodeBox");
boxNode.attachChild(box);

MaterialState ms = display.getRenderer().createMaterialState();
ms.setAmbient(new ColorRGBA(0.5f,0.5f,0.5f,0.5f));
ms.setEmissive(new ColorRGBA(0,0.75f,0,0.5f));
ms.setDiffuse(new ColorRGBA(0,1,0,0.5f));
ms.setSpecular(new ColorRGBA(1,0,0,0.5f));
ms.setShininess(100);

boxNode.setRenderState(ms);

LightState ls = display.getRenderer().createLightState();
ls.setTwoSidedLighting(true);
boxNode.setRenderState(ls);


rootNode.attachChild(boxNode);




Here is the code I use to create all boxes except the testbox.


String boxName = "box" + newObject();
Box b = new Box(boxName, creation.getOriginPoint().add(0, creation.getHeight()/2, 0), creation.getWidthX()/2,creation.getHeight()/2, creation.getWidthZ()/2);
b.setModelBound(new BoundingBox());
b.updateModelBound();
//b.setSolidColor(ColorRGBA.green);
boxNode.attachChild(b);
LightState ls = display.getRenderer().createLightState();
ls.setTwoSidedLighting(true);
b.setRenderState(ls);



I have set the twoSidedLightning on both the parent node and the boxes, but that was just for testing, it didn't work if I only had it on one of them either.

I still haven't solved this materialproblem, but until I find a solution for it I can use only textures…



I have another problem I can't go around though… And that is that the graphics can get really strange when I remove objects during certain circumstances. I use raytracing from the mouse to determine which object to remove (the closest one of course), but if there is an object behind the one I am deleting something goes wrong. The object I delete will of course disappear, but something strange happens to all the other objects in the program. I think it's best described by pictures.



The code I use is:



    private void deleteMesh() {
        Ray ray = rayCast();
        pick.clear();
        rootNode.findPick(ray, pick);

        Geometry mesh = null;
        for (int i = 0; i < pick.getNumber(); i++) {
            mesh = pick.getPickData(i).getTargetMesh();
            if (!mesh.getName().equals("floor") && !buttonPushed) {
                mesh.getParent().detachChild(mesh);
                buttonPushed = true;
                return;
            }
        }
    }



The first picture shows how it looks before the deleting, and the second one after. It's the small box that I delete. In the code for deleting it, the large box behind it isn't even mentioned, but still it is affected (as all other boxes would've been if there were more boxes present).

Anyone knows why this could happen?

okay, now I actually solved it, by commenting away code until there was almost none left… Apperantly I can't have my Node called "nodeBox" which only purpose was to have all boxes as it's children. Even if I removed all textures and so on which was attached on it it wouldn't work. The only way to get around it was to skip it and attach all the boxes directly to the rootNode.



Have I missunderstod something? I thought it was possible to use the sceneGraph like a hierarchy as I did above… Please correct me if I missunderstod how the sceneGraph works.

okay, but I don't run several threads, unless JME does that by itself in the background. I havn't initiated any multithreading at least.



I saw now that it's not entirely solved anyways… if I add the textures to the boxes they still behave strange… They only show two of the boxes for sides (I'm not including the top and bottom) and keep only showing the two sides which are furthest away from the camera.



Is there anything wrong with this code? Because if I uncomment it everything seems to work fine…



                    MaterialState ms = display.getRenderer().createMaterialState();
                    ms.setAmbient(new ColorRGBA(0.5f,0.5f,0.5f,0.5f));
                    ms.setEmissive(new ColorRGBA(1,0.75f,0,0.5f));
                    ms.setDiffuse(new ColorRGBA(1,1,0,0.5f));
                    ms.setSpecular(new ColorRGBA(1,0,0,0.5f));
                    ms.setShininess(100);

                    b.setRenderState(ms);

                    TextureState ts = display.getRenderer().createTextureState();
                    ts.setEnabled(true);
                    ts.setTexture(TextureManager.loadTexture(Test.class
                            .getClassLoader().getResource("navigator/data/grass.jpg"),
                            Texture.MinificationFilter.BilinearNearestMipMap, Texture.MagnificationFilter.Bilinear));
                    ts.getTexture().setWrap(Texture.WrapMode.Repeat);
                    b.setRenderState(ts);

                    b.updateRenderState();

hi, new update!



I don't think it's the delete method which is wrong anymore. Before I always drawed out a hardcoded box first of all (the small one in the pictures) and the rest is user generated, but now I tried to just take away the code for this hardcoded box. It really shouldn't affect anything, since nothing else in the program calls it in any way, the only connection to the rest of the program is that is was a child of the same Node (nodeBox) as all the other boxes.



Now when I don't add this box, all new boxes get's that strange apperance as in the post above from the beginning. I have no idea why, something is really strange here!! And I can also mention if I have a skybox behind, the boxes will take the texture from the skybox and also try to behave as the skybox, even though they don't have any connection to the skybox.



haven't anyone else experienced something like this? I don't think I've done something out of the ordinary, and I only draw basic boxes, so this must've happened to others too right?



Just noticed one more thing, If I draw a box the last thing I do in "simpleInitGame" it works, BUT if I remove EVERYTHING in simpleUpdate (my overridden version) and only creates one box in it, the box will get that strange apperance again… So apperantly something strange happens between simpleInitGame and simpleUpdate…



This just keeps getting stranger…

dj_danne said:

okay, but I don't run several threads, unless JME does that by itself in the background. I havn't initiated any multithreading at least.


Yes it does, if you use StandardGame (and GameStates) because StandardGame runs in its own newly created Thread. And typically the GameState creation runs in the main thread. Do you use StandardGame?

okay, no, I run SimpleGame, is it the same with that one?

dj_danne said:

okay, no, I run SimpleGame, is it the same with that one?


No, you should be good to go. Sorry though, I cant help you with the problem above. I can just say that the code looks good to me  :|

yeah, I don't think that's the problem, I really have no idea what it is… but for now I'll just skip textures and materials, this is a prototype, so the functions are more important.



If anyone comes up with any ideas to what it could be you are of course welcome to come with suggestions!

Just so you don't think you're alone, I have had similar problems where stuff just sometimes does not render after scene changes, even though threading and scene-object-relationships are eliminated as problems.  In one case, I've resorted to adding and removing a simple TriMesh to the middle of the scene (at a specific point in the sequence), which empirically makes everything appear on all of my target platforms.



Going back to your earlier problems with materials being rendered on inside surfaces, even if the following points are not the cause, you probably want to know about them.  The winding order of vertexes, not the normal directions, determines the "front" of surfaces.  Just reverse the winding order of each face by changing the sequence of elements in the vert/norm/texcoord buffers, or in the index buffer, and you'll change the face fronts.  If you have not changed the default KeyBindingManager setup of SimpleGame (inherited from BaseSimpleGame), you can hit "n" to see if the normals are pointing where you want them to.

okay, I checked the normals, most of them seems okay, some may be a bit off, but since all of them are having the same problem independent of how the normals are, that seems not to be the problem.



I have now realized that I can comment practically everything away and it still won't work… The code below is an example program I wrote from the code that I havn't commented away. WHY doesn't this work?? Something must be wrong with this code…




import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.shape.Box;
import com.jme.scene.state.MaterialState;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author daer
 */
public class newTest extends SimpleGame {

    public static void main(String[] args) {
        newTest t = new newTest();
        t.setConfigShowMode(ConfigShowMode.AlwaysShow);
        t.start();
    }
    private boolean test = false;
    private int objectCount = 0;

    @Override
    protected void simpleInitGame() {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
     protected void simpleUpdate() {

        if (!test) {
            String boxName = "box" + newObject();
            Box b = new Box(boxName, new Vector3f(0, 0, 0), new Vector3f(10, 10, 10));
            b.setModelBound(new BoundingBox());
            b.updateModelBound();

            MaterialState ms = display.getRenderer().createMaterialState();
            ms.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f));
            ms.setEmissive(new ColorRGBA(0, 0.75f, 0, 0.5f));
            ms.setDiffuse(new ColorRGBA(0, 1, 0, 0.5f));
            ms.setSpecular(new ColorRGBA(1, 0, 0, 0.5f));
            ms.setShininess(100);

            b.setRenderState(ms);

            TextureState ts = display.getRenderer().createTextureState();
            ts.setEnabled(true);
            ts.setTexture(TextureManager.loadTexture(newTest.class.getClassLoader().getResource("grass.jpg"),
                    Texture.MinificationFilter.BilinearNearestMipMap, Texture.MagnificationFilter.Bilinear));
            ts.getTexture().setWrap(Texture.WrapMode.Repeat);
            b.setRenderState(ts);
            b.updateRenderState();
            test = true;
            rootNode.attachChild(b);
        }
    }

    public int newObject() {
        return ++objectCount;
    }

}

dj_danne said:

okay, I checked the normals, most of them seems okay, some may be a bit off, but since all of them are having the same problem independent of how the normals are, that seems not to be the problem.

I have now realized that I can comment practically everything away and it still won't work... The code below is an example program I wrote from the code that I havn't commented away. WHY doesn't this work?? Something must be wrong with this code...


It works fine if you move the updateRenderState to where it will do something:  after the attachChild.

Oh, thanks! :slight_smile:



Now the textures work as they should! The materials are still messed up, but I can live with that, I really don't need them anyway, I can use only textures.

Actually I now realize that I need to get the materials working as they should too. Probably it's just some simple misstake, but what I can see I've done like the tutorials says ( http://www.jmonkeyengine.com/wiki/doku.php?id=transparency&s[]=blendstate ).



I try to make a box transparent, but only 3 out of 6 faces of the box becomes transparent, the other 3 just seem to disappear, and also, when the "disappearing" faces are closest to the camera, the 3 transparent faces becomes solid.



This code is the only code that is run, all other code is commented away.



        Box b = new Box("bla", new Vector3f(0, 0, 0), new Vector3f(10, 10, 10));

        float opacityAmount = 0.5f;
        MaterialState materialState = display.getRenderer().createMaterialState();
        materialState.setAmbient(new ColorRGBA(0.0f, 0.0f, 0.0f, opacityAmount));
        materialState.setDiffuse(new ColorRGBA(0.1f, 0.5f, 0.8f, opacityAmount));
        materialState.setSpecular(new ColorRGBA(1.0f, 1.0f, 1.0f, opacityAmount));
        materialState.setShininess(128.0f);
        materialState.setEmissive(new ColorRGBA(0.0f, 0.0f, 0.0f, opacityAmount));
        materialState.setEnabled(true);

        BlendState bs = display.getRenderer().createBlendState();
        bs.setBlendEnabled(true);
        bs.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
        bs.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
        bs.setTestEnabled(true);
        bs.setTestFunction(BlendState.TestFunction.GreaterThan);

        b.setRenderState(bs);
        b.setRenderState(materialState);
        b.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
      

        rootNode.attachChild(b);
        b.updateRenderState();



Anyone have a clue why it doesn't work?

Hi again, I just noticed that it actually did work, it was just the lights playing a trick on me. The shadows caused that three edges wasn't possible to make out, but if I inserted another light from the opposite direction it worked fine.

Okay, first I want to excuse myself for being so confused! :stuck_out_tongue: The original problem I posted here about earlier still exists, I just thought it was gone (since it only appears in certain areas of the world).



Here I will show you a code example of when it works (the material comes on the outside of the box) and when it doesn't work (when the material comes on the inside of the box).



        if (test) {
            Box b = new Box("boxtest", new Vector3f(90, 0, -20), new Vector3f(100, 10, -30));
            //Box b = new Box("boxtest", new Vector3f(0, 0, 0), new Vector3f(10, 10, 10));
            b.setRenderState(bs);
            b.setRenderState(materialStateTransparent);
            b.setRenderState(grass);
            b.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
            b.setModelBound(new BoundingBox());
            b.updateModelBound();
            rootNode.attachChild(b);
            b.updateRenderState();
            createArrowsForBox(b);
            test = false;
        }



This code is the only thing that runs in the simpleUpdate() method for the moment. with the first placement of the box with the constructor (the one that is not commented away), the material comes on the inside of the box. If I use the one that is commented away instead, it comes on the outside of the box.

createArrowsForBox only creates some arrows piercing the box, I use them to indicate wheather it is correct or not. They have a red texture and the box has a blue texture, so the correct color of the part of the arrows that are inside the box should be a combination red and blue (since the box is transparent). But when the material ends up on the inside of the box, the part of the arrows inside the box gets entirely blue (if you see them from the outside of the box).

I'll give you the code for my initialisation of the materials too:


        materialStateTransparent = display.getRenderer().createMaterialState();
        materialStateTransparent.setAmbient(new ColorRGBA(0.0f, 0.0f, 0.0f, opacityAmount));
        materialStateTransparent.setDiffuse(new ColorRGBA(0.1f, 0.5f, 0.8f, opacityAmount));
        materialStateTransparent.setSpecular(new ColorRGBA(1.0f, 1.0f, 1.0f, opacityAmount));
        materialStateTransparent.setShininess(128.0f);
        materialStateTransparent.setEmissive(new ColorRGBA(0.0f, 0.0f, 0.0f, opacityAmount));
        materialStateTransparent.setEnabled(true);

        bs = display.getRenderer().createBlendState();
        bs.setBlendEnabled(true);
        bs.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
        bs.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
        bs.setTestEnabled(true);
        bs.setTestFunction(BlendState.TestFunction.GreaterThan);

        grass = display.getRenderer().createTextureState();
        grass.setEnabled(true);
        grass.setTexture(TextureManager.loadTexture(Test.class
                .getClassLoader().getResource("navigator/data/blue.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap, Texture.MagnificationFilter.Bilinear));
        grass.getTexture().setWrap(Texture.WrapMode.Repeat);

        red = display.getRenderer().createTextureState();
        red.setEnabled(true);
        red.setTexture(TextureManager.loadTexture(Test.class
                .getClassLoader().getResource("navigator/data/grass.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap, Texture.MagnificationFilter.Bilinear));
        red.getTexture().setWrap(Texture.WrapMode.Repeat);



anyone has a clue why this is happening? I can't see that I'm doing anything strange... And apart from what I mentioned now there is no more code running in the program.