mboisseau
mboisseau

Reputation: 23

THREE.MeshBasicMaterial renders, but THREE.MeshLambertMaterial does not

I'm working on a project that makes a sort of randomized sheet. It stores arrays of x, y, and z coordinates and draws triangles between the points. You can see this working pretty well in this screenshot.

I used MeshBasicMaterial to make that sheet, but wanted to switch to MeshLambertMaterial to take advantage of lighting. When I try this, I get a sheet that looks like this.

This is the working Basic Mesh code on green tiles:

for(j = 0; j < h-1; j++) {      //h is the number of tiles vertically
    for(i = 0; i < w-1; i++) {  //w is the number of tiles horizontally
        o = ((j%2==1)?1:0);     //checks if the row is odd
        var geom = new THREE.Geometry();
        var a = new THREE.Vector3(x[i][j],      y[i][j]     ,z[i][j]);
        var b = new THREE.Vector3(x[i+1][j],    y[i+1][j]   ,z[i+1][j]);
        var c = new THREE.Vector3(x[i+o][j+1],  y[i+o][j+1] ,z[i+o][j+1]);
        geom.vertices.push(a);
        geom.vertices.push(b);
        geom.vertices.push(c);
        geom.faces.push(new THREE.Face3(0,1,2));
        tile1[i][j] = new THREE.Mesh(
            geom,
            new THREE.MeshBasicMaterial({color: 'green'})
        );
        scene.add(tile1[i][j]);
    }
}

And this is the failing Lambert Mesh code on red tiles (note that I only changed 'Basic' to 'Lambert'):

for(j = 0; j < h-1; j++) {      //h is the number of tiles vertically
    for(i = 0; i < w-1; i++) {  //w is the number of tiles horizontally
        o = ((j%2==1)?0:1);     //checks if the row is even
        var geom = new THREE.Geometry();
        var a = new THREE.Vector3(x[i+o][j],    y[i+o][j]   ,z[i+o][j]);
        var b = new THREE.Vector3(x[i+1][j+1],  y[i+1][j+1] ,z[i+1][j+1]);
        var c = new THREE.Vector3(x[i][j+1],    y[i][j+1]   ,z[i][j+1]);
        geom.vertices.push(a);
        geom.vertices.push(b);
        geom.vertices.push(c);
        geom.faces.push(new THREE.Face3(0,1,2));
        tile2[i][j] = new THREE.Mesh(
            geom,
            new THREE.MeshLambertMaterial({color: 'red'})
        );
        scene.add(tile2[i][j]);
    }
}

A cube created with the following Lambert Mesh works perfectly and catches light properly.

scene.add(new THREE.Mesh(new THREE.BoxGeometry(10,1000,5),new THREE.MeshLambertMaterial({color:'red'})));

Why does the Lambert Mesh not work on a geometry that Basic Mesh works on?

EDIT: I placed a colored box under the sheet to test how the box would react to lighting and found that the tiles above it weren't failing to render, but were just black. They are opaque, but don't use the color or pick up light the way the box does.

Upvotes: 2

Views: 852

Answers (1)

Wilt
Wilt

Reputation: 44422

You should have lights in your scene to profit from THREE.LambertMaterial. Did you setup your scene lighting correctly?

EDIT:

I found out where your problem is. You should add a normal to your faces, otherwise the WebGL renderer does not know how to render the light bouncing of the THREE.LambertMaterial on the surfaces. So change your code like this:

face = new THREE.Face3( 0, 1, 2 );
face.normal = new THREE.Vector3().crossVectors(
    new THREE.Vector3().subVectors( b, a ),
    new THREE.Vector3().subVectors( c, b )
).normalize();
geom.faces.push( face );

Now your faces should render.

Instead of doing this manually you can also use the geometry methods for calculating them:

geometry.computeFaceNormals();
geometry.computeVertexNormals();

Upvotes: 3

Related Questions