Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Three.js custom objLoader geometry lighting

Tags:

three.js

I have this object I'm loading with THREE.objLoader and then create a mesh with it like so:

mesh = new THREE.SceneUtils.createMultiMaterialObject(
  geometry,
  [
    new THREE.MeshBasicMaterial({color: 0xFEC1EA}),
    new THREE.MeshBasicMaterial({
      color: 0x999999,
      wireframe: true,
      transparent: true,
      opacity: 0.85
    })
  ]
);

In my scene I then add a DirectionalLight, it works and I can see my object, however it's like the DirectionalLight was an ambient one. No face is getting darker or lighter as it should be.

The object is filled with the color, but no lighting is applied to it. If someone can help me with that it would be much appreciated :)

What could I be missing ?

Jsfiddle here: http://jsfiddle.net/5hcDs/

like image 990
daformat Avatar asked Jun 14 '12 11:06

daformat


2 Answers

Ok folks, thanks to Maël Nison and mr doob I was able to understand the few things I was missing, being the total 3d noob that I am... I believe people starting to get into the 3d may find useful a little recap:

Basic 3d concepts

  • A 3d Face is made of some points (Vertex), and a vector called a normal, indicating the direction of the face (which side is the front and which one is the backside).

  • Not having normals can be really bad, because lighting is applied on the frontside only by default. Hence the black model when trying to apply a LambertMaterial or PhongMaterial.

  • An OBJ file is a way to describe 3D information. Want more info on this? Read this wikipedia article (en). Also, the french page provides a cube example which can be useful for testing.

Three.js tips and tricks

  • When normals are not present, the lighting can't be applied, hence the black model render. Three.js can actually compute vertex and face normals with geometry.computeVertexNormals() and/or geometry.computeFaceNormals() depending on what's missing

  • When you do so, there's a chance Three.js' normal calculation will be wrong and your normals will be flipped, to fix this you can simply loop through your geometry's faces array like so:

/* Compute normals */
geometry.computeFaceNormals();
geometry.computeVertexNormals();

/* Next 3 lines seems not to be mandatory */
mesh.geometry.dynamic = true
mesh.geometry.__dirtyVertices = true;
mesh.geometry.__dirtyNormals = true;

mesh.flipSided = true;
mesh.doubleSided = true;

/* Flip normals*/               
for(var i = 0; i<mesh.geometry.faces.length; i++) {
  mesh.geometry.faces[i].normal.x = -1*mesh.geometry.faces[i].normal.x;
  mesh.geometry.faces[i].normal.y = -1*mesh.geometry.faces[i].normal.y;
  mesh.geometry.faces[i].normal.z = -1*mesh.geometry.faces[i].normal.z;
}
like image 97
daformat Avatar answered Oct 04 '22 16:10

daformat


You have to use a MeshPhongMaterial. MeshBasicMaterial does not take light in account when computing fragment color.

However, when using a MeshPhongMaterial, your mesh becomes black. I've never used the OBJ loader, but are you sure your model normales are right ?

Btw : you probably want to use a PointLight instead. And its position should probably be set to the camera position (light.position = camera.position should do the trick, as it will allow the light to be moved when the camera position will be edited by the Controls).

like image 43
Maël Nison Avatar answered Oct 04 '22 16:10

Maël Nison