[SOLVED] Messed up Normals?

Hello!
My third post now, but I am finally getting out of the noobish phase. I can now successfully generate a mesh from scratch in the form of cubic voxels using 3D Perlin noise (thank you noise.js!). However, the normal vectors for my procedural generation are fairly broken, if you look:


This luckily is still a huge improvement from this:

But even after switching up the vector patterns, they always seem to be wrong in one way or another.

Anyone have experience in procedural mesh generation? I have used many Playcanvas sources, and it seems that the way I am doing it matches them… but doesn’t.

Here is the problem child:


    var verts = [];
    var norms = [];
    var uvs = [];
    var inds = [];

    var blocks = [];
    var i = 0;

    for(let x = 0; x < 16; x++){
        for(let y = 0; y < 16; y++){
            for(let z = 0; z < 16; z++){
                blocks.push(Math.round(noise.perlin3(x+pos.x+0.3, y+0.3, z+pos.y+0.3)));
            }
        }
    }

    for(let x = 0; x < 16; x++){
        for(let y = 0; y < 16; y++){
            for(let z = 0; z < 16; z++){
                var block = blocks[x*256 + y*16 + z];
                if(block != 0){
                    //top face
                    if(blocks[x*256 + y*16 + z + 16] == 0){
                        verts.push(x,y,z, x+1,y,z, x+1,y,z+1, x+1,y,z+1, x,y,z+1, x,y,z);
                        norms.push(0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0);
                        uvs.push(0,0,1,0,1,1,1,1,0,0,0,0);
                        inds.push(inds.length,inds.length+1,inds.length+2,inds.length+3,inds.length+4,inds.length+5);
                    }
                    //back face
                    if(blocks[x*256 + y*16 + z + 256] == 0){
                        verts.push(x,y,z, x+1,y,z, x+1,y-1,z, x+1,y-1,z, x,y-1,z, x,y,z);
                        norms.push(1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0);
                        uvs.push(0,0,1,0,1,1,1,1,0,0,0,0);
                        inds.push(inds.length,inds.length+1,inds.length+2,inds.length+3,inds.length+4,inds.length+5);
                    }
                    //right face
                    if(blocks[x*256 + y*16 + z + 1] == 0){
                        verts.push(x+1,y,z, x+1,y,z+1, x+1,y-1,z+1, x+1,y-1,z+1, x+1,y-1,z, x+1,y,z);
                        norms.push(-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0);
                        uvs.push(0,0,1,0,1,1,1,1,0,0,0,0);
                        inds.push(inds.length,inds.length+1,inds.length+2,inds.length+3,inds.length+4,inds.length+5);
                    }
                    //Front face
                    if(blocks[x*256 + y*16 + z - 256] == 0){
                        verts.push(x,y,z+1, x+1,y,z+1, x+1,y-1,z+1, x+1,y-1,z+1, x,y-1,z+1, x,y,z+1);
                        norms.push(0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1);
                        uvs.push(0,0,1,0,1,1,1,1,0,0,0,0);
                        inds.push(inds.length,inds.length+1,inds.length+2,inds.length+3,inds.length+4,inds.length+5);
                    }
                    //left face
                    if(blocks[x*256 + y*16 + z - 1] == 0){
                        verts.push(x,y,z, x,y,z+1, x,y-1,z+1, x,y-1,z+1, x,y-1,z, x,y,z);
                        norms.push(-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0);
                        uvs.push(0,0,1,0,1,1,1,1,0,0,0,0);
                        inds.push(inds.length,inds.length+1,inds.length+2,inds.length+3,inds.length+4,inds.length+5);
                    }
                    //bottom face
                    if(blocks[x*256 + y*16 + z - 16] == 0){
                        verts.push(x,y-1,z, x+1,y-1,z, x+1,y-1,z+1, x+1,y-1,z+1, x,y-1,z+1, x,y-1,z);
                        norms.push(0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0);
                        uvs.push(0,0,1,0,1,1,1,1,0,0,0,0);
                        inds.push(inds.length,inds.length+1,inds.length+2,inds.length+3,inds.length+4,inds.length+5);
                    }
                    i++;
                }
            }
        }
    }
    //norms = pc.calculateNormals(verts, inds);
    return {verts: verts, norms: norms, uvs: uvs, indicies: inds};

Did I misconnect indicies? pc.calculateNormals does not even work for this… so where did I go wrong?

Project:
https://playcanvas.com/editor/scene/1439135
Find this in game.js.

Thank you.

EDIT:
Just so the code makes more sense:
Verts make the positions for the polygons. Six points for two polygons, branching from the block position. Same for UVs that connect them. Indicies (“inds”) connect the points. Norms are in sets of 3 for xyz vector parts.

EDIT2: I found the issue, just being really bad at placing the points correctly. :slight_smile:

1 Like

This is already looking great!

If you don’t mind posting your solution so this post serves as a helper to future users searching for a similar answer. Many thanks!

1 Like

My solution is not quite complete, apparently…
Although everything is visualized properly, there is a discrepancy. Even though I started with the top faces in development, apparently they are not there at all. If I invert the normals, the faces do not reappear.
From the top:

Beautiful voxels below:

Here is the new code that mostly works:


    var verts = [];
    var norms = [];
    var uvs = [];
    var inds = [];

    var blocks = [];

    for(let x = 0; x < 16; x++){
        for(let y = 0; y < 16; y++){
            for(let z = 0; z < 16; z++){
                blocks.push(Math.round(noise.perlin3(x+pos.x+0.3, y+0.3, z+pos.y+0.3)));
            }
        }
    }

    for(let x = 0; x < 16; x++){
        for(let y = 0; y < 16; y++){
            for(let z = 0; z < 16; z++){
                var block = blocks[x*256 + y*16 + z];
                if(block != 0){
                    //Top
                    if(this.findBlock(pos,x,y+1,z) == 0){
                        verts.push(x,y,z, x+1,y,z, x+1,y,z+1, x+1,y,z+1, x,y,z+1, x,y,z);
                        norms.push(0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0);
                        uvs.push(0,0,1,0,1,1,1,1,0,0,0,0);
                        inds.push(inds.length,inds.length+1,inds.length+2,inds.length+3,inds.length+4,inds.length+5);
                    }
                    //Front
                    if(this.findBlock(pos,x,y,z-1) == 0){
                        verts.push(x,y,z, x+1,y,z, x+1,y-1,z, x+1,y-1,z, x,y-1,z, x,y,z);
                        norms.push(0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1);
                        uvs.push(0,0,1,0,1,1,1,1,0,0,0,0);
                        inds.push(inds.length,inds.length+1,inds.length+2,inds.length+3,inds.length+4,inds.length+5);
                    }
                    //Right
                    if(this.findBlock(pos,x+1,y,z) == 0){
                        verts.push(x+1,y,z, x+1,y,z+1, x+1,y-1,z+1, x+1,y-1,z+1, x+1,y-1,z, x+1,y,z);
                        norms.push(1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0);
                        uvs.push(0,0,1,0,1,1,1,1,0,0,0,0);
                        inds.push(inds.length,inds.length+1,inds.length+2,inds.length+3,inds.length+4,inds.length+5);
                    }
                    //Left
                    if(this.findBlock(pos,x-1,y,z) == 0){
                        verts.push(x,y,z+1, x,y,z, x,y-1,z, x,y-1,z, x,y-1,z+1, x,y,z+1);
                        norms.push(-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0);
                        uvs.push(0,0,1,0,1,1,1,1,0,0,0,0);
                        inds.push(inds.length,inds.length+1,inds.length+2,inds.length+3,inds.length+4,inds.length+5);
                    }
                    //Back
                    if(this.findBlock(pos,x,y,z+1) == 0){
                        verts.push(x+1,y,z+1, x,y,z+1, x,y-1,z+1, x,y-1,z+1, x+1,y-1,z+1, x+1,y,z+1);
                        norms.push(0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1);
                        uvs.push(0,0,1,0,1,1,1,1,0,0,0,0);
                        inds.push(inds.length,inds.length+1,inds.length+2,inds.length+3,inds.length+4,inds.length+5);
                    }
                    //Bottom
                    if(this.findBlock(pos,x,y-1,z) == 0){
                        verts.push(x,y-1,z, x+1,y-1,z, x+1,y-1,z+1, x+1,y-1,z+1, x,y-1,z+1, x,y-1,z);
                        norms.push(0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0);
                        uvs.push(0,0,1,0,1,1,1,1,0,0,0,0);
                        inds.push(inds.length,inds.length+1,inds.length+2,inds.length+3,inds.length+4,inds.length+5);
                    }
                }
            }
        }
    }
    //norms = pc.calculateNormals(verts, inds);
    return {verts: verts, norms: norms, uvs: uvs, indicies: inds};

Wait, I found the issue. I messed around with Index connections and finally it connected properly! Ignore this! Thank you anyways for being available!

1 Like