Modifying Trimesh on the fly

Hi,



Quick question on TriMesh. I'm using TriMesh and WireframeState to create a triangular grid. I want to highlight the position of the player by changing color on the vertices.



My question is, if I change my color value in my float buffer, will the trimesh be updated, or do I need to rebuild it each time?



Thanks


It should work, be sure not to use lockMeshes and to switch off VBO for the color buffer. You could put a quad at the feet of the player as a highlight, so then no need to change the buffer.

any source code example on changing the trimesh color?


TriMesh mesh;
FloatBuffer cb = mesh.getColorBuffer(0);
FloatBuffer vb = mesh.getVertexBuffer(0);
cb.rewind();
vb.rewind();
Vector3f vPos = new Vector3f();
for (int vert = 0; vert < cb.limit(); vert++){
     vPos.set(vb.get(), vb.get(), vb.get());
     ColorRGBA color = someColorFunction(vPos);
     cb.put(color.r).put(color.g).put(color.b).put(color.a);
}
cb.flip();
vb.flip();


someColorFunction would be a function which generates a color value given a location in object space.

When I tried the code, I got null pointer exceptions, the following code set the model to yellow color:



            cb.rewind(); --> null pointer exception




SkinNode sn = ColladaImporter.getSkinNode(ColladaImporter.getSkinNodeNames().get(0));
Bone skel = ColladaImporter.getSkeleton(ColladaImporter.getSkeletonNames().get(0));
updateColors(sn);

    void updateColors(Spatial s) {
       
        if (s instanceof Node) {
            Node n = (Node) s;

            for (Spatial child : n.getChildren())
                updateColors(child);
           
        } else if (s instanceof TriMesh) {

            TriMesh mesh = (TriMesh) s;
            FloatBuffer cb = mesh.getColorBuffer(0);
            FloatBuffer vb = mesh.getVertexBuffer(0);
            cb.rewind();
            vb.rewind();
            Vector3f vPos = new Vector3f();
            for (int vert = 0; vert < cb.limit(); vert++){
                 vPos.set(vb.get(), vb.get(), vb.get());
                 ColorRGBA color = ColorRGBA.yellow;
                 cb.put(color.r).put(color.g).put(color.b).put(color.a);
            }
            cb.flip();
            vb.flip();
           
        }
    }

You will get that null pointer exception if your mesh doesn't have a color buffer to begin with.



Try calling setSolidColor() on the triangle batch when you first create your mesh, to make sure the color array is created.

Am i correct in thinking the colours will not be seen if lighting is added to the scene

If you enable color material, then vertex colors will be modulated with the lighting.

I set the color of TriMesh using setSolidColor but the color is not set for both of following code



            TriMesh mesh = (TriMesh) s;
            mesh.setSolidColor(ColorRGBA.yellow);
            mesh.setRandomColors();




            TriMesh mesh = (TriMesh) s;
            TriangleBatch batch = mesh.getBatch(0);
            batch.setSolidColor(ColorRGBA.yellow); 



if you take a look at the TriMesh object in debugger, there is no ColorBuffer / VertexBuffer at all, in fact the TriangleBatch object inside TriMesh does have both fields

http://www.oniva.com/upload/1356/tri.jpg

Also If I setSolidColor for the TriMesh, I will get BufferUnderflowException
            --> vPos.set(vb.get(), vb.get(), vb.get());


    void updateColors(Spatial s) {
       
        if (s instanceof Node) {
            Node n = (Node) s;

            for (Spatial child : n.getChildren())
                updateColors(child);
           
        } else if (s instanceof TriMesh) {
            TriMesh mesh = (TriMesh) s;
            mesh.setSolidColor(ColorRGBA.yellow);
           
            FloatBuffer cb = mesh.getColorBuffer(0);
            FloatBuffer vb = mesh.getVertexBuffer(0);
            cb.rewind();
            vb.rewind();
            Vector3f vPos = new Vector3f();
            for (int vert = 0; vert < cb.limit(); vert++){
                 vPos.set(vb.get(), vb.get(), vb.get());
                 ColorRGBA color = ColorRGBA.yellow;
                 cb.put(color.r).put(color.g).put(color.b).put(color.a);
            }
            cb.flip();
            vb.flip();
        }
      }



Any idea what's going wrong?

The setColor Methods only work if there is no lightning in the scene. (Pressing 'L' in SimpleGame)

Usually you set Colors with the MaterialState/AlphaState like this Utility Function from jmephysics util.java:



    public static void color( Spatial spatial, ColorRGBA color, int shininess ) {
        DisplaySystem display = DisplaySystem.getDisplaySystem();
        final MaterialState materialState = display.getRenderer().createMaterialState();
        materialState.setDiffuse( color );
        materialState.setAmbient( color.mult( new ColorRGBA( 0.3f, 0.3f, 0.3f, 1 ) ) );
        materialState.setShininess( shininess );
        float mul = 1 + shininess > 18 ? (shininess-28)*0.01f : 0;
        materialState.setSpecular( color.mult( new ColorRGBA( mul, mul, mul, 1 ) ) );
        spatial.setRenderState( materialState );

        if ( color.a < 1 ) {
            final AlphaState alphaState = display.getRenderer().createAlphaState();
            alphaState.setEnabled( true );
            alphaState.setBlendEnabled( true );
            alphaState.setSrcFunction( AlphaState.SB_SRC_ALPHA );
            alphaState.setDstFunction( AlphaState.DB_ONE_MINUS_SRC_ALPHA );
            alphaState.setTestEnabled(true);
            alphaState.setTestFunction(AlphaState.TF_GREATER);
            spatial.setRenderState( alphaState );
            spatial.setRenderQueueMode( Renderer.QUEUE_TRANSPARENT );
        }

        CullState cullState = display.getRenderer().createCullState();
        cullState.setCullMode( CullState.CS_BACK );
        spatial.setRenderState( cullState );
    }



Of course you don't need all that, but its a nice Method which works out of the box.

You know, I would have said "just turn on GL_COLOR_MATERIAL," which is there exactly for this reason. However, it appears that the LWJGL wrapper doesn't actually support that render state.



For those not in the know, GL_COLOR_MATERIAL with GL_AMBIENT_DIFFUSE makes it so that the ambient and diffuse parts of the material state come from the vertex color channel. That way, the vertex colors get modulated into the calculated lighting values. I think I'll go add this as a suggestion for 2.0, because it's a mighty useful feature when you're using the fixed function pipeline!

in LWJGL:  GL11.GL_COLOR_MATERIAL



in jME:  MaterialState.setColorMaterial(int)

Curious. I couldn't find it when looking through the renderer and renderer.lwjgl namespace:


C:Javauserworkspacejmesrccomjmerenderer>grep -ri color.*material .

C:Javauserworkspacejmesrccomjmerenderer>



Looking at it again, I see that it lives in the jme.state namespace, not jme.renderer. Thanks for the pointer!

And, yeah, turn on that state, and your vertex colors will work fine.

I was trying to use this technique to color a specific TriMesh from a terrain page.



Everything seems to be working correctly, except I keep getting an java.nio.BufferOverflowException @ cb.put()



tracing through the loop that momoko_fan posted it looks as if the limit is 4356 and the loop iterates 1089 times (1089*4=4356); and there are 2048 triangles in the mesh.

So I guess there is not enough buffer space allocated, I tried increasing it with buffer.setCapacity() however it isn't working (and probably not safe anyway).





Also, if I lower the number of iterations to 100 there is no error, however I don't see any change in the vert colors; if I update the color state itself it does change (so I haven't forgotten a updateRenderState() )



Any hints or help??

Momoko_Fan said:


TriMesh mesh;
FloatBuffer cb = mesh.getColorBuffer(0);
FloatBuffer vb = mesh.getVertexBuffer(0);
cb.rewind();
vb.rewind();
Vector3f vPos = new Vector3f();
for (int vert = 0; vert < cb.limit(); vert++){
     vPos.set(vb.get(), vb.get(), vb.get());
     ColorRGBA color = someColorFunction(vPos);
     cb.put(color.r).put(color.g).put(color.b).put(color.a);
}
cb.flip();
vb.flip();




This code adds 3 colors PER storage unit in cb... I would say you need to change vert++ with vert += 3

Sorry about that, I don't test my code so logic errors are entirely possible. :expressionless:


This code adds 3 colors PER storage unit in cb... I would say you need to change vert++ with vert += 3


Yeah, had to figure that one out the hard way  .  Thanx though :)