【问题标题】:Lighting not working properly with MeshLambertMaterial in THREE js三个 js 中的 MeshLambertMaterial 照明无法正常工作
【发布时间】:2021-07-13 08:47:35
【问题描述】:

我正在使用 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

【问题讨论】:

  • 请发布您的代码的最小、完整和可验证的示例,并且不要将链接粘贴到网络代码编辑器。
  • @Unlockedluca 在这种情况下,我必须提供工作代码。这就是我添加 jsfiddle 的原因。
  • Jonarya,你可以在 StackOverflow 中创建一个“sn-p”,也是一样的。查看帖子编辑器的工具栏。这些按钮从左到右依次为:粗体、斜体、插入超链接、插入引用、插入代码、插入图像、插入片段。您可能链接到外部网站,但是您还应该在此处粘贴您的代码,因为有一天该外部链接可能会更改,您的问题将失去所有上下文。

标签: three.js


【解决方案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

【讨论】:

    【解决方案2】:

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

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

    阴影可能很棘手。我建议您在 Google 上搜索该主题,并确保您了解所涉及的所有问题。

    另外,MeshLambertMaterial 处理阴影的方式受到限制。如果你有环境贴图,我会使用MeshStandardMaterial,否则我会使用MeshPhongMaterial

    three.js r.87

    【讨论】:

    • 这里有 2 面墙(盒子)和 2 个灯泡。右侧墙和地板不受左侧固定灯泡的影响。所以当移动灯泡到达右侧时,这种自阴影应该不会影响,不是吗?
    • 记住,点光源有六个阴影相机。当光线几乎平行于面部时,任何类型的光线都可能存在自阴影伪影。在您的情况下,当光线靠近墙壁时,您会在四个方向上获得平行光线......如果没有大量调查工作,有时很难理解这些伪影 - 但这是我对正在发生的事情的最佳猜测。此外,还有this issue,您可能会看到。
    猜你喜欢
    • 1970-01-01
    • 2019-07-26
    • 2020-02-27
    • 1970-01-01
    • 2011-12-25
    • 2021-12-04
    • 1970-01-01
    • 1970-01-01
    • 2012-01-29
    相关资源
    最近更新 更多