Material of InstancedMesh geometry does not show when created with custom BufferGeometry

Hi all,

This is probably a simple question, but here goes.

There are 2 example codes shown below. In the first example, the material successfully renders on my viewport if I use THREE.BoxGeometry. However, in the second example, the material does not render at all if I use THREE.BufferGeometry. Why is this so, and how should I resolve this?

Example Code 1:

let geom = new THREE.BoxGeometry(1, 1, 1);

let im = new THREE.InstancedMesh(
        geom,
        new THREE.MeshLambertMaterial(),
       length
)

Example Code 2:

let geom = new THREE.BufferGeometry();

let vertices = new Float32Array( [
        -0.5, -0.5,  -0.5, 
        0.5, -0.5,  -0.5, 
        0.5,  0.5,  -0.5, 
        -0.5,  0.5,  -0.5,
        -0.5, -0.5,  0.5, 
        0.5, -0.5,  0.5, 
        0.5,  0.5,  0.5, 
         -0.5,  0.5,  0.5, 
 ] );;

let indices = [0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4, 0, 4, 3, 3, 4, 7, 3, 7, 2, 2, 7, 6, 2, 1, 6, 6, 1, 5, 0, 1, 5, 0, 5, 4]

geom.setIndex( indices );
geom.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );

let im = new THREE.InstancedMesh(
        geom,
        new THREE.MeshLambertMaterial(),
        length
)

Thanks in advance.

Is the geometry working ok when using just Three.Mesh instead of Three.InstancedMesh? You’re not assigning any normals, so I’d assume MeshLambertMaterial wouldn’t work in either case :thinking:

The same thing happens when using THREE.Mesh. THREE.BoxGeometry renders the material successfully unlike THREE.BufferGeometry.

Yes, as above - you’re defining only position in the geometry. To make light work, you’ll need to either define normal buffer attribute, to specify direction of each vertex, or use BufferGeometry.computeVertexNormals to do it automatically (otherwise three doesn’t know the direction of faces in the mesh, making it impossible to calculate light properly.)

After using computeVertexNormals, this is the result.

Therefore, I tried specifying vertex normals.

From the website:

.computeVertexNormals () : undefined

Computes vertex normals for the given vertex data. For indexed geometries, the method sets each vertex normal to be the average of the face normals of the faces that share that vertex. For non-indexed geometries, vertices are not shared, and the method sets each vertex normal to be the same as the face normal.

In this case, assuming the point (-0.5, -0.5, -0.5), shouldn’t the face normals of each face related to the point be (-1, 0 ,0), (0, -1,0) and (0, 0, -1), and the average of the face normals be (-1, -1, -1)?

However, the code below does not work.

Let normals = new FloatArray32([
-1,-1,-1,
1,-1,-1,
1,1,-1,
-1,1,-1,
-1,-1,1,
1,-1,1,
1,1,1,
-1,1,1
])

geom.setAttribute( ‘normal’, new THREE.BufferAttribute( normals, 3 ) );

The vertex normals above is arranged accordingly according to the order of the points specified above. Am I doing something wrongly? How should I go about specifying vertex normals?

Thanks

.computeVertexNormals() allocates the normals if they aren’t there… and recomputes them. You shouldn’t have to do any manual stuff.

Also perhaps unrelated, but a warning… if you use a geometry on an InstancedMesh, I’ve seen problems if the same geometry is then also used by a regular mesh somewhere else. The geometry seems to only be able to work with one type of mesh or the other.

Hi,

the below happens when using computeVertexNormals(). This object in a viewport should be a cube, but has the material rendered on the wrong side for a few faces due to flipped normals. How should I resolve this issue?

No worries, am only the geometry on a singular instanced mesh.

The reason I am using custom THREE.BufferGeometry and not THREE.BoxGeometry is because I would like to ultimately output the data from the geometry into JSON, and using a custom indexed THREE.BufferGeometry, would be able to reduce the size of the final JSON output data.

Thanks.

Flip the normals for the bad triangles by reversing the indices of their vertices, or… use material.side = THREE.DoubleSide

Hi,

after reversing the indices, this shading is different from that of THREE.BoxGeometry.

  1. Using THREE.BufferGeometry:

  1. Using THREE.BoxGeometry

I would use VertexNormalHelper on both geometries to see what happens with normals. That might be surprising.

2 Likes

If you’re sharing the 8 points of a cube, you won’t have a unique normal for each cube face sharing that point…

To make them flat shaded, each quad face needs to have 4 unique vertices + normals + uvs.

As prisoner849 said, check out the helper on both objects and it will make more sense. :slight_smile:

1 Like