SoftBody : duplicated vertex and UV map

Hi,

I encounter a little problem in the making of the binding to bullet softbody.

Currently the binding only allow to create a softbody from a mesh, use the mesh’s vertex buffer to generate a “softbody” structure for physics simulation.
The problem is a soft body mesh tearing apart because of unlinked vertex.
There are unlinked vertex in the soft body because a “flat” shaded mesh or a mesh with a UV map use different vertex with the same position but only with different normals or texture coordinate.


The idea is to only use vertex with different positions. So the physics vertex buffer will contain “less” vertex than the buffer used for rendering.

The first solution i find is to keep data about duplicated vertex and then use this info to properly update “duplicated” vertex (for rendering).

Do you have other/better idea ?

Edit : the problem come from different index for same vertex position

I think you will have to keep a mapping somehow. A vertex in OpenGL is more than just position.

you will have to keep a mapping somehow

sure

A vertex in OpenGL is more than just position.

You mean normals and texCoord ?

Bullet only update positions and normals.
Then I update the mesh data (position and optionally normlas) by updating buffers.
Maybe this isn’t the best option but i don’t understand the problem with OpenGL.

In OpenGL a vertex is “every vertex attribute”. So it just depends… but it’s not just position and normal. It’s every thing attached to the vertex and so a “unique vertex” in OpenGL (not just JME) is duplicate only if all of those things are the same.

So for bullet you will have to figure out what is unique only across position and normal, keep a mapping, and then update all of the OpenGL vertexes as appropriate. If the entire mesh is updated all the time, then I recommend a forward mapping because those are at least 1:1. (Where the target may be shared.)

Nice idea but unfortunately keeping “different vertex” because of different normals will not “bound” them and the mesh will torn, that mean flat shaded mesh will tear. If i only use position, normals will not be correctly updated for flat shaded mesh (one will not be updated and other will be “smooth” shaded). So i doesn’t need to use normals , flat shaded mesh will not work in any case.

I think i understand what you mean, plus the entire mesh is updated all the time. But i don’t know what “forward mapping” is. (i am looking forward shadow mapping, related ? seem to be openGL stuff)

Forward mapping… is you map forward from OpenGL vertex to bullet vertex. Backwards mapping would be you map backwards from bullet vertex to many OpenGL vertexes. The first way requires one simple array. The second requires an array of arrays… thus forward mapping is easier.

Pseudo code:

for( int i = 0; i < numVerts; i++ ) {
    int bulletIndex = map[i];
    setOpenGlVertex i to position, normal of bulletIndex
}
1 Like

Ok thanks i’ll try this.

Little exemple to show what’s has to be done

Exemple :
mesh :   P1\P3----P4
            ¦¯\_   ¦
            ¦   ¯\_¦
           P2----P6\P5

 with P1==P3 and P6==P5
 Buffers indexes        :  | 0| 1| 2| 3| 4| 5|
 >-  JME PositionBuffer :  [P1,P2,P3,P4,P5,P6] 
 >-  JME IndexBuffer    :  [ 0, 1, 5, 2, 4, 3]
 <-> JME -> Bullet map  :  [ 0, 1, 0, 2, 3, 3]
  -> Bullet Positions   :  [P3,P2,P4,P6]       == [P1,P2,P4,P5]
  -> Bullet Index       :  [ 0, 1, 3, 0, 3, 2]

This what i did, i use a HashMap and i hope it is better than using a LinkedList.
And i am not sure about the use of buffer.rewind() .

FloatBuffer jmePositions = triMesh.getFloatBuffer(Type.Position);
IndexBuffer jmeIndex = triMesh.getIndexBuffer();

// Generation of jmeToBulletMap, maping JME index to Bullet index.
int jmePositionSize = jmePositions.capacity();
jmeToBulletMap = BufferUtils.createIntBuffer(jmePositionSize / 3);
HashMap<Vector3f, Integer> uniquePositions = new HashMap<Vector3f, Integer>();
for (int i = 0, indice = 0; i < jmePositionSize; i += 3) {
    float x = jmePositions.get(i + 0);
    float y = jmePositions.get(i + 1);
    float z = jmePositions.get(i + 2);
    Vector3f p = new Vector3f(x, y, z);
    if (!uniquePositions.containsKey(p)) {
        uniquePositions.put(p, indice);
        jmeToBulletMap.put(indice);
        indice++;
    } else {
        jmeToBulletMap.put(uniquePositions.get(p));
    }
}
jmeToBulletMap.rewind();
jmePositions.rewind();

// Generation of bullet indexes with the help of jmeToBulletMap
int jmeIndexSize = jmeIndex.size();
IntBuffer bulletIndexBuffer = BufferUtils.createIntBuffer(jmeIndexSize);
for (int i = 0; i < jmeIndexSize; i += 3) {
    // create the bullet index to recreate each face with bullet position
    bulletIndexBuffer.put(jmeToBulletMap.get(jmeIndex.get(i + 0)));
    bulletIndexBuffer.put(jmeToBulletMap.get(jmeIndex.get(i + 1)));
    bulletIndexBuffer.put(jmeToBulletMap.get(jmeIndex.get(i + 2)));
}

bulletIndexBuffer.rewind();

// Generation of bullet position with the help of jmeToBulletMap
int bulletNbPosition = uniquePositions.size() * 3;
FloatBuffer bulletPositions = BufferUtils.createFloatBuffer(bulletNbPosition);
for (int i = 0; i < jmePositionSize / 3; i++) {
    // create the bullet positions, do the conversion from JME -> Bullet (not 1:1, with some overwrite)
    int iBullet = jmeToBulletMap.get(i);
    bulletPositions.put(iBullet * 3 + 0, jmePositions.get(i * 3 + 0));
    bulletPositions.put(iBullet * 3 + 1, jmePositions.get(i * 3 + 1));
    bulletPositions.put(iBullet * 3 + 2, jmePositions.get(i * 3 + 2));
}

objectId = createFromTriMesh(bulletIndexBuffer, bulletPositions, jmeIndexSize / 3, false);

2 Likes

rewind just places the position to read or write at the beginning of the buffer data.
So you usually use it before going through the entire buffer for read or write, to make sure you are starting from the beginning if that’s what you intend to do.

Rewinding after writing the whole buffer is good practice IMO… like “ok, I did what had to do now i clean up before leaving…”
rewiding a buffer is not what’s going to kill the perfs anyway, you can navigate into the code and see what it does, it’s pretty trivial.

1 Like

Ok, thanks.