Updating a model's mesh causes weird behavior

I’m probably doing something wrong but I can’t figure out what it is. My code, which is quite messy sorry for that, takes a mesh with shared vertices (which has an index buffer) and then makes the vertices unshared with a flat normal according to the triangle. Here are two images to demonstrate what I’m trying to do :

The first image depicts my bug. For some reason, when changing loaded model’s buffers, this happens. The model is the teapot in jme3-testdata.

Here’s my code :

private static final int VERTICES_PER_TRIANGLE = 3;                                                                                                             
                                                                                                                                                                
public static <T extends Mesh> T computeNormals(T mesh, boolean containsSharedVertices) {                                                                       
    VertexBuffer positionVertexBuffer = mesh.getBuffer(Type.Position);                                                                                          
    FloatBuffer positionFloatBuffer = (FloatBuffer) positionVertexBuffer.getData();                                                                             
    positionFloatBuffer.rewind();                                                                                                                               
                                                                                                                                                                
    VertexBuffer normalVertexBuffer = mesh.getBuffer(Type.Normal);                                                                                              
    FloatBuffer normalFloatBuffer = (FloatBuffer) normalVertexBuffer.getData();                                                                                 
    normalFloatBuffer.rewind();                                                                                                                                 
                                                                                                                                                                
    Vector3f[] triangleVertices = new Vector3f[VERTICES_PER_TRIANGLE];                                                                                          
    for (int i = 0; i < triangleVertices.length; ++i)                                                                                                           
        triangleVertices[i] = new Vector3f();                                                                                                                   
                                                                                                                                                                
    if (!containsSharedVertices) {                                                                                                                              
        // Not important ...                                                                                    
    } else {                                                                                                                                                    
        VertexBuffer indexVertexBuffer = mesh.getBuffer(Type.Index);                                                                                            
        ShortBuffer indexShortBuffer = (ShortBuffer) indexVertexBuffer.getData();                                                                               
        int targetVertexCount = indexShortBuffer.limit();                                                                                                       
        int targetTriangleCout = targetVertexCount / VERTICES_PER_TRIANGLE;                                                                                     
        indexShortBuffer.rewind();                                                                                                                              
                                                                                                                                                                
        FloatBuffer positionNewFloatBuffer = (FloatBuffer) VertexBuffer.createBuffer(Format.Float, positionVertexBuffer.getNumComponents(), targetVertexCount); 
        FloatBuffer normalNewFloatBuffer = (FloatBuffer) VertexBuffer.createBuffer(Format.Float, normalVertexBuffer.getNumComponents(), targetVertexCount);     
                                                                                                                                                                
        for (int triangleIndex = 0; triangleIndex < targetTriangleCout; ++triangleIndex) {                                                                      
            for (int triangleVertexIndex = 0; triangleVertexIndex < VERTICES_PER_TRIANGLE; ++triangleVertexIndex) {                                             
                positionFloatBuffer.position(indexShortBuffer.get() * positionVertexBuffer.getNumComponents());                                                 
                                                                                                                                                                
                for (int vertexComponentIndex = 0; vertexComponentIndex < positionVertexBuffer.getNumComponents(); ++vertexComponentIndex) {                    
                    float vertexComponent = positionFloatBuffer.get();                                                                                          
                                                                                                                                                                
                    triangleVertices[triangleVertexIndex].set(vertexComponentIndex, vertexComponent);                                                           
                    positionNewFloatBuffer.put(vertexComponent);                                                                                                
                }                                                                                                                                               
            }                                                                                                                                                   
                                                                                                                                                                
            Vector3f normal = computeTriangleNormal(triangleVertices);                                                                                          
                                                                                                                                                                
            for (int normalIndex = 0; normalIndex < VERTICES_PER_TRIANGLE; ++normalIndex)                                                                       
                for (int normalComponentIndex = 0; normalComponentIndex < normalVertexBuffer.getNumComponents(); ++normalComponentIndex)                        
                    normalNewFloatBuffer.put(normal.get(normalComponentIndex));                                                                                 
        }                                                                                                                                                       
                                                                                                                                                                
        positionNewFloatBuffer.flip();                                                                                                                          
        normalNewFloatBuffer.flip();                                                                                                                            
                                                                                                                                                                
        mesh.clearBuffer(Type.Index);                                                                                                                           
        positionVertexBuffer.updateData(positionNewFloatBuffer);                                                                                                
        normalVertexBuffer.updateData(normalNewFloatBuffer);                                                                                                    
        // TODO                                                                                                                                                 
    }                                                                                                                                                           
                                                                                                                                                                
    mesh.updateCounts();                                                                                                                                        
    mesh.updateBound();                                                                                                                                         
                                                                                                                                                                
    return mesh;                                                                                                                                                
}                                                                                                                                                               
                                                                                                                                                                
public static boolean mayNotShareVertices(Mesh mesh) {                                                                                                          
    return mesh.getMode() == Mode.Triangles;                                                                                                                    
}                                                                                                                                                               
                                                                                                                                                                
public static Vector3f computeTriangleNormal(Vector3f[] vertices) {                                                                                             
    return computeTriangleNormal(vertices[0], vertices[1], vertices[2]);                                                                                        
}                                                                                                                                                               
                                                                                                                                                                
public static Vector3f computeTriangleNormal(Vector3f p1, Vector3f p2, Vector3f p3) {                                                                           
    return p2.subtract(p1).cross(p3.subtract(p1)).normalizeLocal();                                                                                             
}

Depending on what you are going to use this for, you may be doing things the hard way:

http://javadoc.jmonkeyengine.org/com/jme3/scene/Mesh.html#getTriangle-int-com.jme3.math.Vector3f-com.jme3.math.Vector3f-com.jme3.math.Vector3f-

Or even:
http://javadoc.jmonkeyengine.org/com/jme3/scene/Mesh.html#getTriangle-int-com.jme3.math.Triangle-

Which also has:
http://javadoc.jmonkeyengine.org/com/jme3/math/Triangle.html#calculateNormal--
http://javadoc.jmonkeyengine.org/com/jme3/math/Triangle.html#getNormal--

If it were me, I’d make a new mesh, iterate over the triangles of the first and just plug them into the second. Way fewer chances for error, to me.

1 Like

You’re right : I’ve had some problems with skeletons an animations. With that, I could just discard them easily.

Thank you, I’ll try that and reply again here for updates.

1 Like