使用三个js中的MeshLambertMaterial无法正常工作

时间:2017-08-30 10:41:00

标签: three.js

我正在用Three.js创建3D房间。我使用MeshLambertMaterial作为墙面材料。当我将PointLight添加到房间时,它正常工作。但是当我在房间外面添加另一个灯泡时,它就无法工作了。

var cubeMat = new THREE.MeshLambertMaterial({ color: 0xD3D3D3, side: THREE.DoubleSide });

这是一个复制测试案例:

var camera, scene, renderer;

init();
animate();

var bulbLight;
var bulbLight2;
var bulbLightDirection = 1;

function addLights() {
  var bulbGeometry = new THREE.SphereGeometry(0.02, 16, 8);
  bulbLight = new THREE.PointLight(0xffee88, 2, 100, 2);
  bulbLight2 = new THREE.PointLight(0xffee88, 2, 100, 2);

  var bulbMat = new THREE.MeshStandardMaterial({
    emissive: 0xffffee,
    emissiveIntensity: 1,
    color: 0x000000
  });
  bulbLight.add(new THREE.Mesh(bulbGeometry, bulbMat));
  bulbLight.position.set(-0.5, 0.6, -1.5);
  bulbLight.shadow.camera.near = 0.01;
  bulbLight.castShadow = true;
  scene.add(bulbLight);
  
  bulbLight2.add(new THREE.Mesh(bulbGeometry, bulbMat));
  bulbLight2.position.set(-0.5, 0.6, -1.5);
  bulbLight2.shadow.camera.near = 0.01;
  bulbLight2.castShadow = true;
  scene.add(bulbLight2);

  var hemiLight = new THREE.HemisphereLight(0xddeeff, 0x0f0e0d, 0.02);
  scene.add(hemiLight);
}

function addFloor() {
  var floorMat = new THREE.MeshLambertMaterial({ color: 0xD3D3D3, side: THREE.DoubleSide });

  var floorGeometry = new THREE.PlaneBufferGeometry(20, 20);
  //floorGeometry.computeFaceNormals();
  //floorGeometry.computeVertexNormals();
  var floorMesh = new THREE.Mesh(floorGeometry, floorMat);
  floorMesh.receiveShadow = true;
  floorMesh.rotation.x = -Math.PI / 2.0;
  scene.add(floorMesh);
}

function addWalls() {
  var cubeMat = new THREE.MeshLambertMaterial({ color: 0xD3D3D3, side: THREE.DoubleSide });
  var boxGeometry = new THREE.BoxGeometry(0.1, 2, 5);
  //boxGeometry.computeFaceNormals();
  //boxGeometry.computeVertexNormals();
  var boxMesh = new THREE.Mesh(boxGeometry, cubeMat);
  boxMesh.position.set(0.1, 0.25, -0.5);
  boxMesh.castShadow = true;
  boxMesh.receiveShadow = true;
  scene.add(boxMesh);

  var boxMesh2 = new THREE.Mesh(boxGeometry, cubeMat);
  boxMesh2.position.set(0.5, 0.25, 0.5);
  boxMesh2.castShadow = true;
  boxMesh2.receiveShadow = true;
  scene.add(boxMesh2);
}

function addControls() {
  var controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.target.set(0, 0, 0);
  controls.update();
}

function init() {
  camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100);
  camera.position.x = -4;
  camera.position.z = 4;
  camera.position.y = 2;

  scene = new THREE.Scene();

  addLights();
  addFloor();
  addWalls();

  renderer = new THREE.WebGLRenderer();
  renderer.physicallyCorrectLights = true;
  renderer.gammaInput = true;
  renderer.gammaOutput = true;
  renderer.shadowMap.enabled = true;
  renderer.toneMapping = THREE.ReinhardToneMapping;
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  addControls();

  window.addEventListener('resize', onWindowResize, false);
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
  requestAnimationFrame(animate);
  render();

  bulbLight.position.x += (bulbLight.direction === 1) ? 0.01 : -0.01;

  if (bulbLight.position.x > 1) bulbLight.direction = 0;
  if (bulbLight.position.x < -1) bulbLight.direction = 1;

}

function render() {
  renderer.render(scene, camera);
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

这里有什么问题?

MeshPhongMaterial给出了相同的结果。但是使用MeshStandardMaterial

2 个答案:

答案 0 :(得分:1)

看起来你可能发现了MeshLambertMaterial的错误,它错误地计算了多个阴影。我玩了你的代码一段时间,从它的外观来看,材料正在执行一个乘法操作,它只能照亮两个灯光照射的地方,但只有一个闪耀时才会亮起:

1 x 1 = 1;
1 x 0 = 0;
0 x 0 = 0;

实际上,应该以加法的方式计算灯光:

1 + 1 = 2;
1 + 0 = 1;
0 + 0 = 0;

我找到的唯一解决方案是将墙壁和地板材料更改为MeshPhongMaterial。此外,您可能不需要THREE.DoubleSide在墙上。

var floorMat = new THREE.MeshPhongMaterial({ color: 0xD3D3D3, side: THREE.DoubleSide });
var cubeMat = new THREE.MeshPhongMaterial({ color: 0xD3D3D3 });

See working fiddle

答案 1 :(得分:1)

您看到的是自阴影工件,因为您的网格设置receiveShadowcastShadow都设置为true

通过调整light.shadow.bias可以减少自阴影伪影。不幸的是,这样做会导致其他伪影。

阴影可能很棘手。我建议你谷歌主题,并确保你了解所涉及的所有问题。

此外,MeshLambertMaterial在处理阴影方面受到限制。如果您有环境地图,我会使用MeshStandardMaterial,否则会使用MeshPhongMaterial

three.js r.87