自定义平面不会在三个js中投射/接收阴影

时间:2017-08-31 10:31:50

标签: three.js

我正在尝试使用六架飞机创建一个盒子(墙)。我创造了飞机,但阴影不存在。

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

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所示, 正如我所指出的,这只发生在深度较小的值上。 (深度&lt; 1)

BoxGeometry with 0.1 depth (with or without single sided render

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>

1 个答案:

答案 0 :(得分:1)

您正面临Z fighting。由于墙壁的厚度很小,两面几乎相互接触,因此它们相互投射阴影。

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

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

此外,由于您从平面更改为方框,因此不再需要墙材料中的线side: THREE.DoubleSide,。事实上,它是自我遮蔽问题的一部分。改变这两行应该可以解决你的问题。

这是一个有效的Fiddle