【问题标题】:Custom plane does not cast/ receive shadows in THREE js自定义平面不会在三个 js 中投射/接收阴影
【发布时间】:2017-09-01 16:39:27
【问题描述】:

我正在尝试使用六个平面创建一个盒子(一堵墙)。我创建了平面,但没有阴影。

这就是我创建自定义平面的方式。

function createWall(vertices) {
  var geometry = new THREE.Geometry(), i;
  for (i = 0; i < vertices.length; i = i + 1) {
    geometry.vertices.push(vertices[i]);
  }
  geometry.faces.push(new THREE.Face3(0, 1, 2));
  geometry.faces.push(new THREE.Face3(0, 2, 3));
 
  geometry.computeVertexNormals();
  geometry.computeFaceNormals();

  var material = new THREE.MeshStandardMaterial({
    emissive: 0x708090,
    emissiveIntensity: 1,
    side: THREE.DoubleSide,
    color: 0xD3D3D3
  });
  var mesh = new THREE.Mesh(geometry, material);
  mesh.castShadow = true;
  mesh.receiveShadow = true;
  return mesh;
}

这是完整的代码。

var camera, scene, renderer;

function addFloor() {
  var material = new THREE.MeshStandardMaterial({
    roughness: 0.8,
    color: 0x696969,
    metalness: 0.2,
    bumpScale: 0.0005
  });

  var geometry = new THREE.PlaneBufferGeometry(2000, 2000);
  var mesh = new THREE.Mesh(geometry, material);
  mesh.receiveShadow = true;
  mesh.rotation.x = -Math.PI / 2.0;
  scene.add(mesh);
}

function createWall(vertices) {
  var geometry = new THREE.Geometry(), i;
  for (i = 0; i < vertices.length; i = i + 1) {
    geometry.vertices.push(vertices[i]);
  }
  geometry.faces.push(new THREE.Face3(0, 1, 2));
  geometry.faces.push(new THREE.Face3(0, 2, 3));
 
  geometry.computeVertexNormals();
  geometry.computeFaceNormals();

  var material = new THREE.MeshStandardMaterial({
    emissive: 0x708090,
    emissiveIntensity: 1,
    side: THREE.DoubleSide,
    color: 0xD3D3D3
  });
  var mesh = new THREE.Mesh(geometry, material);
  mesh.castShadow = true;
  mesh.receiveShadow = true;
  return mesh;
}

function addBulb(location) {
  var geometry = new THREE.SphereGeometry(2, 20, 20);
  var light = new THREE.PointLight(0xffffff, 1, 100, 2);

  var material = new THREE.MeshStandardMaterial({
    emissive: 0xffffee,
    emissiveIntensity: 1,
    color: 0x000000
  });
  light.add(new THREE.Mesh(geometry, material));
  light.position.set(location.x, location.y, location.z);
  light.shadow.camera.near = 0.0001;
  light.castShadow = true;
  //light.shadow.darkness = 0.5;
  //light.shadow.camera.vsible = true;
  return light;
}

function addWalls() {
	var wall1 = createWall([
    new THREE.Vector3(0, 0, 0), //vertex0
    new THREE.Vector3(200, 0, 0), //1
    new THREE.Vector3(200, 100, 0), //2
    new THREE.Vector3(0, 100, 0) //3
  ]);
  var wall2 = createWall([
    new THREE.Vector3(0, 0, 5), //vertex0
    new THREE.Vector3(200, 0, 5), //1
    new THREE.Vector3(200, 100, 5), //2
    new THREE.Vector3(0, 100, 5) //3
  ]);
  scene.add(wall1);
  scene.add(wall2);
}

function addCamera() {
	camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.set(50, 100, 300);
  scene.add(camera);
}

function init() {
  scene = new THREE.Scene();

  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  renderer.shadowMap.renderSingleSided = false;
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setClearColor(0xffffff, 1);
	document.body.appendChild(renderer.domElement);

	addCamera();
  addFloor();
  addWalls();
  scene.add(addBulb({x: 100, y: 50, z: 25}));
  var ambientLight = new THREE.AmbientLight(0x999999, 0.6);
  scene.add(ambientLight);
  var controls = new THREE.OrbitControls(camera, renderer.domElement);
}

function animate() {
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

init();
animate();
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

我在创建自定义平面时可能做错了什么。我不明白这里出了什么问题。

更新:

renderer.shadowMap.renderSingleSided = false;

似乎阴影在起作用,但灯光有奇怪的方形效果。

在这里,我尝试了 BoxGeometry,正如 three-js-plane-doesnt-cast-shadow 中所建议的那样,它的深度很小, 正如我所指出的,这只发生在深度值较小的情况下。 (深度

var camera, scene, renderer;

function addFloor() {
  var material = new THREE.MeshStandardMaterial({
    roughness: 0.9,
    color: 0xffffff,
    metalness: 0.1,
    bumpScale: 0.0005
  });

  var geometry = new THREE.PlaneBufferGeometry(2000, 2000);
  var mesh = new THREE.Mesh(geometry, material);
  mesh.receiveShadow = true;
  mesh.rotation.x = -Math.PI / 2.0;
  scene.add(mesh);
}

function createWall(location) {
  var geometry = new THREE.BoxGeometry(200, 100, 0.1);
  geometry.translate((location.x1 + location.x2) / 2, 150 / 2, location.z);
  var material = new THREE.MeshStandardMaterial({
    emissive: 0x708090,
    emissiveIntensity: 1,
    side: THREE.DoubleSide,
    color: 0xD3D3D3,
    roughness: 0.9,
    metalness: 0.1
  });
  var mesh = new THREE.Mesh(geometry, material);
  mesh.castShadow = true;
  mesh.receiveShadow = true;
  return mesh;
}

function addBulb(options) {
  var geometry = new THREE.SphereGeometry(2, 20, 20);
  var light = new THREE.PointLight(options.color, 1, 500, 2);

  var material = new THREE.MeshStandardMaterial({
    emissive: options.color,
    emissiveIntensity: 1,
    color: options.color
  });
  light.add(new THREE.Mesh(geometry, material));
  light.position.set(options.x, options.y, options.z);
  light.shadow.camera.near = 0.0001;
  light.castShadow = true;
  light.shadow.darkness = 0.5;
  light.shadow.camera.vsible = true;
  return light;
}

function addWalls() {
	var wall1 = createWall({ x1: 0, x2: 200, z: 0});
  var wall2 = createWall({ x1: 0, x2: 200, z: 5});
  scene.add(wall1);
  //scene.add(wall2);
}

function addCamera() {
	camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.set(100, 100, 300);
  scene.add(camera);
}

function init() {
  scene = new THREE.Scene();

  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  renderer.shadowMap.renderSingleSided = false;
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setClearColor(0xffffff, 1);
	document.body.appendChild(renderer.domElement);

	addCamera();
  addFloor();
  addWalls();
  scene.add(addBulb({x: 0, y: 100, z: 25, color: 0xff0000 }));
  scene.add(addBulb({x: 100, y: 100, z: 25, color: 0x00ff00 }));
  scene.add(addBulb({x: 200, y: 100, z: 25, color: 0x0000ff }));
  var ambientLight = new THREE.AmbientLight(0x999999, 0.6);
  scene.add(ambientLight);
  var controls = new THREE.OrbitControls(camera, renderer.domElement);
}

function animate() {
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

init();
animate();
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

【问题讨论】:

  • @JuanFerrer 我认为这是不同的,因为我自己创建了飞机。我已根据该答案进行了更改,但它给出了奇怪的照明效果。 (我已经更新了我上面的代码)
  • 如链接问题中所述,“在这种情况下,您的飞机会投射阴影,但可能会出现自阴影伪影,因为您同时拥有 plane.castShadow = trueplane.receiveShadow = true”。如果你在飞机上禁用接收阴影,奇怪的灯光就会消失。
  • 是的,移除了奇怪的光照,但是我怎样才能接收到阴影呢?我需要创建一个需要投射和接收阴影的房间->墙。

标签: three.js


【解决方案1】:

你面对的是Z fighting。由于墙的厚度很小,两个面几乎互相接触,所以它们互相投下阴影。

您可以移除墙上阴影的投射/接收,或者更好地增加几何图形中的 z 值,如下所示:

var geometry = new THREE.BoxGeometry(200, 100, 1);

另外,由于你从平面变成了一个盒子,所以不再需要墙壁材料中的side: THREE.DoubleSide, 行。事实上,这是自我阴影问题的一部分。更改这两行应该可以解决您的问题。

这是一个有效的Fiddle

【讨论】:

    猜你喜欢
    • 2018-06-20
    • 2017-12-12
    • 1970-01-01
    • 1970-01-01
    • 2022-08-12
    • 1970-01-01
    • 1970-01-01
    • 2021-07-08
    • 1970-01-01
    相关资源
    最近更新 更多