[SOLVED] Delete a face from a mesh

Hi. Given a mesh like a box that have index, position, normals and tex. buffers. Is there a way to iterate over the faces (a triangle of three vertices) of the mesh and delete just those faces from the mesh given some filter?

For example, the box have the faces with the normals:

0 normal: (0.0, 0.0, 1.0) (0.0, 0.0, 1.0) (0.0, 0.0, 1.0)
1 normal: (0.0, 0.0, 1.0) (0.0, 0.0, 1.0) (0.0, 0.0, 1.0)
2 normal: (0.0, -1.0, 0.0) (0.0, -1.0, 0.0) (0.0, -1.0, 0.0)
3 normal: (0.0, -1.0, 0.0) (0.0, -1.0, 0.0) (0.0, -1.0, 0.0)
4 normal: (-1.0, 0.0, 0.0) (-1.0, 0.0, 0.0) (-1.0, 0.0, 0.0)
5 normal: (-1.0, 0.0, 0.0) (-1.0, 0.0, 0.0) (-1.0, 0.0, 0.0)
6 normal: (0.0, 0.0, -1.0) (0.0, 0.0, -1.0) (0.0, 0.0, -1.0)
7 normal: (0.0, 0.0, -1.0) (0.0, 0.0, -1.0) (0.0, 0.0, -1.0)
8 normal: (1.0, 0.0, 0.0) (1.0, 0.0, 0.0) (1.0, 0.0, 0.0)
9 normal: (1.0, 0.0, 0.0) (1.0, 0.0, 0.0) (1.0, 0.0, 0.0)
10 normal: (0.0, 1.0, 0.0) (0.0, 1.0, 0.0) (0.0, 1.0, 0.0)
11 normal: (0.0, 1.0, 0.0) (0.0, 1.0, 0.0) (0.0, 1.0, 0.0)

I want to delete all faces with z=-1, i.e. all faces that are facing downwards. That’s not the same as culling, because it’s independent from the camera. So even if you rotate the camera those faces should not be there.

I just tried something like this below but the results were terrible.

var model = modelsg.get(ModelCacheObject.class, ModelCacheObject.OBJECT_TYPE, mb.getObject());
var mesh = ((Geometry) ((Node) model.model).getChild(0)).getMesh();
var bindex = mesh.getShortBuffer(Type.Index).rewind();
var bnormal = mesh.getFloatBuffer(Type.Normal).rewind();
var bpos = mesh.getFloatBuffer(Type.Position).rewind();
var btex = mesh.getFloatBuffer(Type.TexCoord).rewind();
int delta = cindex.position();
for (int i = 0; i < bindex.limit() / 3; i++) {
    short i0 = (short) (bindex.get() * 3);
    short i1 = (short) (bindex.get() * 3);
    short i2 = (short) (bindex.get() * 3);
    var n0 = temp.vect1.set(bnormal.get(i0), bnormal.get(i0 + 1), bnormal.get(i0 + 2));
    var n1 = temp.vect2.set(bnormal.get(i1), bnormal.get(i1 + 1), bnormal.get(i1 + 2));
    var n2 = temp.vect3.set(bnormal.get(i2), bnormal.get(i2 + 1), bnormal.get(i2 + 2));
    n0.addLocal(n1.addLocal(n2)).divideLocal(3f);
    if (n0.z < 0.0f) {
        continue;
    }
    cindex.put((short) (i0 + delta));
    cindex.put((short) (i1 + delta));
    cindex.put((short) (i2 + delta));
    System.out.printf("%d normal: %s %s %s\n", i, n0, n1, n2); // TODO
}
copyNormal(mb, mesh, cnormal);
copyTex(mb, mesh, ctex);
copyPos(mb, mesh, cpos, transform, w, h, d);

Deleted faces:

All faces:

Probably, you will need to convert your mesh into some intermediate form (extracting all of the data), remove the faces you want, then regenerate the mesh data.

It is non-trivial to remove a particular face in the general case. If you already know the mesh structure well then it’s at least possible. In the general case, you will need to worry about shared vertexes, etc…

…unless you just want the face to disappear. Then just remove its entry from the index buffer and leave everything else around. That’s relatively easy. JME even has some code to iterate over the mesh’s triangles that may help.

Edit: it also might help to know why you want to do this. My initial answer was “load it into blender and delete the faces”… which is the “right answer” in most cases.

1 Like

Thank you for your reply. I want them to just disappear.

Then just remove its entry from the index buffer and leave everything else around. That’s relatively easy.

Weird, I thought I did it with the code above but the result was catastrophic. In the code I just keep the indexes that have z>=0.0f, only positive z. The other buffers are copied. Maybe I made some mistake?

Here are the indexes that I keep: (ignore the 2.0 that’s actually 1.0).

0 normal: (0.0, 0.0, 1.0) (0.0, 0.0, 2.0) (0.0, 0.0, 1.0)
1 normal: (0.0, 0.0, 1.0) (0.0, 0.0, 2.0) (0.0, 0.0, 1.0)
2 normal: (0.0, -1.0, 0.0) (0.0, -2.0, 0.0) (0.0, -1.0, 0.0)
3 normal: (0.0, -1.0, 0.0) (0.0, -2.0, 0.0) (0.0, -1.0, 0.0)
4 normal: (-1.0, 0.0, 0.0) (-2.0, 0.0, 0.0) (-1.0, 0.0, 0.0)
5 normal: (-1.0, 0.0, 0.0) (-2.0, 0.0, 0.0) (-1.0, 0.0, 0.0)
8 normal: (1.0, 0.0, 0.0) (2.0, 0.0, 0.0) (1.0, 0.0, 0.0)
9 normal: (1.0, 0.0, 0.0) (2.0, 0.0, 0.0) (1.0, 0.0, 0.0)
10 normal: (0.0, 1.0, 0.0) (0.0, 2.0, 0.0) (0.0, 1.0, 0.0)
11 normal: (0.0, 1.0, 0.0) (0.0, 2.0, 0.0) (0.0, 1.0, 0.0)

Edit: it also might help to know why you want to do this. My initial answer was “load it into blender and delete the faces”… which is the “right answer” in most cases.

I have the idea from GitHub - rvandoosselaer/Blocks: A block (voxel) engine for jMonkeyEngine

I want to remove the vertices that are never seen by the gamer. But other than Blocks I want to use models that I create in Blender (plus some other extra stuff that Blocks doesn’t do). I can’t do it in Blender before because the stuff will change in game all the time.

Oh, I did made a mistake. Now it works. I need to copy the correct index.

for (int i = 0; i < bindex.limit() / 3; i++) {
    short in0 = bindex.get(); // <-----
    short in1 = bindex.get(); // <-----
    short in2 = bindex.get(); // <-----
    short i0 = (short) (in0 * 3);
    short i1 = (short) (in1 * 3);
    short i2 = (short) (in2 * 3);
    var n0 = temp.vect1.set(bnormal.get(i0), bnormal.get(i0 + 1), bnormal.get(i0 + 2));
    var n1 = temp.vect2.set(bnormal.get(i1), bnormal.get(i1 + 1), bnormal.get(i1 + 2));
    var n2 = temp.vect3.set(bnormal.get(i2), bnormal.get(i2 + 1), bnormal.get(i2 + 2));
    n0.addLocal(n1.addLocal(n2)).divideLocal(3f);
    if (n0.z < 0.0f) {
        continue;
    }
    cindex.put((short) (in0 + delta)); // <-----
    cindex.put((short) (in1 + delta)); // <-----
    cindex.put((short) (in2 + delta)); // <-----
    System.out.printf("%d normal: %s %s %s\n", i, n0, n1, n2); // TODO
}

Minecraft-style games will definitely 100% represent their data “some other way” and then generate the geometry from it. Removing a face is then a matter of adjusting the intermediate data and then regenerating.

Editing raw mesh data is pretty rare.

This is done during the generation process when emitting faces. Block world games are not made of blocks. They are made of visible faces.

Simplified:

for every solid block {
    for every neighbor {
        if no neighbor {
            emit face
        }
    }
}

If you are removing “hidden faces” from an existing Mesh then you are upside down.

You are right, thank you. Yes, I see the code of Blocks and it’s basically your simplified algorithm.

But it’s not a Minecraft-style game or a blocks game, and I will have more complex models than just blocks. I’m just starting with the simplest model first, a block.

Well, lets see how it turns out. The result is the same, and I’m happy now. Your comment is of course highly appreciated.

1 Like

Mesh data is meant for the GPU. It’s had all of the useful analysis bits “compiled” out of it.

If you want to do “math” on your geometry, you will certainly need to keep it in some intermediate form.

I say this as someone with a LOT of experience in generative/procedural geometry. (Whether Mythruna or IsoSurface demos or SimArboreal or whatever.)

1 Like

SimArboreal looks cool.