[SOLVED] Backface Culling Issue

Hello to everyone!
While I was coding a simple voxel engine in jme3, I run into an issue:

When I use Backface Culling The faces are not rendering correctly, even though my normals are pointing in the right direction.

Here I have a bunch of screenshots of my scene:


Since I’m a new user, I could not post more than a picture in a Topic, so I’m going to describe the specific rendering issue I’m encountering:

The TOP and BOTTOM face is only rendered when looking from the bottom;
Two lateral faces are rendered in the same direction, while the other two are rendered in the opposite one;

switch (face) {
                                        case TOP: {
                                            verticesl.add(top_front_left);
                                            verticesl.add(top_front_right);
                                            verticesl.add(top_back_left);
                                            verticesl.add(top_back_right);

                                            addNormals(normalsl, 0, -1, 0);
                                        }
                                        break;

                                        case BOTTOM: {
                                            verticesl.add(bottom_front_left);
                                            verticesl.add(bottom_front_right);
                                            verticesl.add(bottom_back_left);
                                            verticesl.add(bottom_back_right);

                                            addNormals(normalsl, 0, +1, 0);
                                        }
                                        break;

                                        case FRONT: {
                                            verticesl.add(top_front_left);
                                            verticesl.add(top_front_right);
                                            verticesl.add(bottom_front_left);
                                            verticesl.add(bottom_front_right);

                                            addNormals(normalsl, 0, 0, +1);
                                        }
                                        break;

                                        case BACK: {
                                            verticesl.add(top_back_left);
                                            verticesl.add(top_back_right);
                                            verticesl.add(bottom_back_left);
                                            verticesl.add(bottom_back_right);

                                            addNormals(normalsl, 0, 0, -1);
                                        }
                                        break;

                                        case LEFT: {
                                            verticesl.add(top_front_left);
                                            verticesl.add(top_back_left);
                                            verticesl.add(bottom_front_left);
                                            verticesl.add(bottom_back_left);

                                            addNormals(normalsl, +1, 0, 0);
                                        }
                                        break;

                                        case RIGHT: {
                                            verticesl.add(top_front_right);
                                            verticesl.add(top_back_right);
                                            verticesl.add(bottom_front_right);
                                            verticesl.add(bottom_back_right);

                                            addNormals(normalsl, -1, 0, 0);
                                        }
                                    }

And this is the function I used to add normals:

private void addNormals(List<Float> normals, float x, float y, float z) {
    for (int i = 0; i < 4; i++) {
        normals.add(x);
        normals.add(y);
        normals.add(z);
    }
}

This is the code I used to attach meshes to the node:

private void attachFlaggedChunks() {
    if (toAttach.isEmpty()) {
        return;
    }

    try {
        LOCK.lock();
        for (Iterator<Chunk> it = toAttach.iterator(); it.hasNext();) {
            Chunk chunk = it.next();
            Mesh meshta = chunk.getMesh();
            Mesh tbnmeshta = chunk.getTangentBinormalsMesh();

            if (meshta != null) {
                Spatial chunkSpatial = new Geometry(chunk.getPosition().toString(), meshta);

                Material mat = new Material(world.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
                Material debug = new Material(world.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
                
                Spatial tbn = new Geometry(chunk.getPosition().toString() + "tbn", tbnmeshta);
                tbn.setCullHint(Spatial.CullHint.Never);
                tbn.setMaterial(debug);
                
                mat.getAdditionalRenderState().setWireframe(true);
                mat.getAdditionalRenderState().setLineWidth(2f);
                mat.setBoolean("UseMaterialColors", true);
                mat.setColor("Ambient", ColorRGBA.Yellow);
                mat.setColor("Diffuse", ColorRGBA.Yellow);

                chunkSpatial.setMaterial(mat);
                //chunkSpatial.setCullHint(Spatial.CullHint.Never);
                
                node.attachChild(tbn);
                node.attachChild(chunkSpatial);
            }

            if (tbnmeshta != null) {
                //Spatial tbnSpatial = new Geometry(chunk.getPosition().toString() + "tb", tbnmeshta);

                //node.attachChild(tbnSpatial);
            }

            it.remove();
        }
    } finally {
        LOCK.unlock();
    }
}

I tried to disable Backface Culling and the program draws all the faces, so I suppose that the problem relies in the Backface Culling.

mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);

Thanks!

PS: I know that coding a voxel engine is difficult, but I do not intend to do anything super complex, I’m here just to learn :smiley:

1 Like

Welcome to the forums and the JME community!

1 Like

It seems some of your faces have a wrong winding order.
The order of the vertices in a triangle determines whether it’s culled, not the normal.
It must be counterclockwise, but your FRONT face for example seems to be built clockwise.
Also depends on the order of indices though…

1 Like

Indeed, make sure that the vertices of the triangles are in counter clockwise order.

Have a look at the Box mesh to see the correct vertices for all faces of a block and make sure to check out the custom mesh page on the wiki.

https://wiki.jmonkeyengine.org/jme3/advanced/custom_meshes.html#connecting-the-dots

I still haven’t figured out what I’m doing wrong, this is the method I use to add indices.
The argument offset represents the list’s size.

 private void addIndices(List<Short> indicesl, int offset) {
    indicesl.add((short) (offset + 2));
    indicesl.add((short) (offset + 0));
    indicesl.add((short) (offset + 1));
    indicesl.add((short) (offset + 1));
    indicesl.add((short) (offset + 3));
    indicesl.add((short) (offset + 2));
}

I call this method just before the switch I posted earlier.

Disable culling in the material. If your triangles are visible, the order of your indices is wrong.

You can also have a look a blocks, It’s an existing voxel engine for jme.

I can already tell from your case statements that you will have issues because for example the front is top left, top right, bottom left, bottom right… and the back is also top left, top right, bottom left, bottom right.

…so if you add their indices the same way then they will both face in the same direction, ie: one will be backwards.

You need to treat each quad as its own “thing” in the sense that you need to add four vertices, four normals, 6 indices (2*3), etc. for each quad.

Edit: I’m assuming the terms “left” and “right” are consistent and not dependent on face… because that gets kind of crazy, too. You may want to change names to non-relative things like north, south, east, west, etc.

Thank you all for your replies!
In the end I managed to fix the issue by reordering the indices. :smiley:

3 Likes