3D 模型不在 ThreeJS 中投射阴影

3D model not casting shadows in ThreeJS

我正在将 glTF 模型导入到 ThreeJS and have a PlaneGeometry 作为基础。我需要模型将阴影投射到 plane/ground.

我试过启用

renderer.shadowMap.enabled = true;

const renderer = new THREE.WebGLRenderer({ alpha: true });

我还有2个灯:

const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);
hemiLight.position.set(0, 10, 0);
scene.add( hemiLight );
const dirLight = new THREE.DirectionalLight(0xffffff);
dirLight.position.set(0, 0, 10);
dirLight.castShadow = true;
dirLight.shadow.camera.top = 200;
dirLight.shadow.camera.bottom = -200;
dirLight.shadow.camera.left = - 200;
dirLight.shadow.camera.right = 200;
dirLight.shadow.camera.near = 0.1;
dirLight.shadow.camera.far = 500;
scene.add( dirLight );

最终代码

body
{
  margin: 0px;
  padding: 0px;
}

div#container canvas
{
  cursor: grab;
}

div#container canvas:active
{
  cursor: grabbing;
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Import 3D Model into Three JS</title>
  
  <script type="module" defer>
  import * as THREE from 'https://cdn.skypack.dev/three@0.129.0/build/three.module.js';

  import { GLTFLoader } from 'https://cdn.skypack.dev/three@0.129.0/examples/jsm/loaders/GLTFLoader.js';    // for .glb and .gltf.glb
  // import { OBJLoader } from 'https://cdn.skypack.dev/three@0.129.0/examples/jsm/loaders/OBJLoader.js';   // for .obj

  import { OrbitControls } from 'https://cdn.skypack.dev/three@0.129.0/examples/jsm/controls/OrbitControls.js';

  const container = document.querySelector('div#container');

  const path_to_model = './ImportModel/Mini-Game Variety Pack/Models/gltf/tree_forest.gltf.glb';
  const loader = new GLTFLoader();

  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 500);

  // Add lights
  const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);
  hemiLight.position.set(0, 10, 0);
  scene.add( hemiLight );
  const dirLight = new THREE.DirectionalLight(0xffffff);
  dirLight.position.set(0, 0, 10);
  dirLight.castShadow = true;
  dirLight.shadow.camera.top = 200;
  dirLight.shadow.camera.bottom = -200;
  dirLight.shadow.camera.left = - 200;
  dirLight.shadow.camera.right = 200;
  dirLight.shadow.camera.near = 0.1;
  dirLight.shadow.camera.far = 500;
  scene.add( dirLight );

  // Make renderer
  const renderer = new THREE.WebGLRenderer({
    alpha: true
  });

  // Make transparent
  renderer.setClearColor(0xffffff, 0);

  // Set it to window size
  renderer.setSize(window.innerWidth, window.innerHeight);

  // Force shadows
  renderer.shadowMap.enabled = true;

  // Helper (optional)
  // const camera_helper = new THREE.CameraHelper(dirLight.shadow.camera);
  // scene.add(camera_helper);

  // Double quality
  const quality = 2;
  renderer.setSize(window.innerWidth * quality, window.innerHeight * quality, false);

  // Add mouse movement
  const controls = new OrbitControls(camera, renderer.domElement);

  // Add floor (plane)
  const plane_geometry = new THREE.PlaneGeometry(10, 10);
  const plane_material = new THREE.MeshPhongMaterial({
    color: 0xffff00,
    side: THREE.DoubleSide
  });
  const plane = new THREE.Mesh(
    plane_geometry,
    plane_material
  );
  plane.rotation.x = 1.5708;
  plane.castShadow = true;
  plane.receiveShadow = true;
  scene.add(plane);

  console.log(plane);

  // Import glTF
  loader.load(path_to_model, function (gltf)
  {
    //gltf.scene.position.y = -5;
    //gltf.scene.center();
    //gltf.scene.scale.set(0.1, 0.1, 0.1);

    // Make it cast shadows
    gltf.scene.castShadow = true;
    gltf.scene.traverse(function(node)
    {
      if (node.isMesh)
      {
        node.castShadow = true;
        //node.receiveShadow = true;
      }
    });

    console.log(gltf);

    console.log('Adding glTF model to scene...');
    scene.add(gltf.scene);
    console.log('Model added.');

    console.log('Moving camera 5z...');
    camera.position.z = 5;
    console.log('Camera moved.');
    }, undefined, function (error)
    {
      console.error(error);
    });

  container.appendChild(renderer.domElement);

  function animate()
  {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
  }
  animate();
  </script>
</head>
<body>
  <div id="container">

  </div>
</body>
</html>

更新: 按照 的建议将平面中的 MeshBasicMaterial 更改为 MeshPhongMaterial

半球光似乎是罪魁祸首。如果你改变它的位置,你可以开始获得阴影。很可能它到处都在投射光线,从而淹没了任何可能出现的阴影。把它从飞机上移开有帮助。 dirLight.shadow.camera.top/bottom/left/right 也太高了。我用了2,vice 200,同时换了半光,好像还行。

HTML

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Import 3D Model into Three JS</title>
</head>

<body>

  <div id="container">

  </div>
</body>

</html>

CSS

body
{
  margin: 0px;
  padding: 0px;
}

div#container canvas
{
  cursor: grab;
}

div#container canvas:active
{
  cursor: grabbing;
}

JS

import * as THREE from "https://cdn.skypack.dev/three@0.129.0/build/three.module.js";

import { GLTFLoader } from "https://cdn.skypack.dev/three@0.129.0/examples/jsm/loaders/GLTFLoader.js"; // for .glb and .gltf.glb
// import { OBJLoader } from 'https://cdn.skypack.dev/three@0.129.0/examples/jsm/loaders/OBJLoader.js';   // for .obj

import { OrbitControls } from "https://cdn.skypack.dev/three@0.129.0/examples/jsm/controls/OrbitControls.js";

const container = document.querySelector("div#container");

const path_to_model =
  "https://s3-us-west-2.amazonaws.com/s.cdpn.io/1376484/stacy_lightweight.glb";
const loader = new GLTFLoader();

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.01,
  500
);

// Add lights
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);
hemiLight.position.set(20, 20, 10);
scene.add(hemiLight);
const dirLight = new THREE.DirectionalLight(0xffffff);
dirLight.position.set(-10, 20, 6);
dirLight.castShadow = true;
dirLight.shadow.camera.top = 2;
dirLight.shadow.camera.bottom = -2;
dirLight.shadow.camera.left = -2;
dirLight.shadow.camera.right = 2;
dirLight.shadow.camera.near = 0.1;
dirLight.shadow.camera.far = 500;
scene.add(dirLight);

// Make renderer
const renderer = new THREE.WebGLRenderer({
  alpha: true
});

// Make transparent
renderer.setClearColor(0xffffff, 0);

// Set it to window size
renderer.setSize(window.innerWidth, window.innerHeight);

// Force shadows
renderer.shadowMap.enabled = true;

// Helper (optional)
// const camera_helper = new THREE.CameraHelper(dirLight.shadow.camera);
// scene.add(camera_helper);

// Double quality
const quality = 2;
renderer.setSize(
  window.innerWidth * quality,
  window.innerHeight * quality,
  false
);

// Add mouse movement
const controls = new OrbitControls(camera, renderer.domElement);

// Add floor (plane)
const plane_geometry = new THREE.PlaneGeometry(10, 10);
const plane_material = new THREE.MeshPhongMaterial({
  color: 0xffff00,
  side: THREE.DoubleSide
});
const plane = new THREE.Mesh(plane_geometry, plane_material);
plane.rotation.x = 1.5708;
plane.castShadow = true;
plane.receiveShadow = true;
scene.add(plane);

console.log(plane);

//scene.add(box)

// Import glTF
loader.load(
  path_to_model,
  function (gltf) {
    //gltf.scene.position.y = -5;
    //gltf.scene.center();
    //gltf.scene.scale.set(0.1, 0.1, 0.1);

    // Make it cast shadows
    gltf.scene.castShadow = true;
    gltf.scene.traverse(function (node) {
      if (node.isMesh) {
        node.castShadow = true;
        //node.receiveShadow = true;
      }
    });

    console.log(gltf);

    console.log("Adding glTF model to scene...");
    scene.add(gltf.scene);
    console.log("Model added.");

    console.log("Moving camera 5z...");
    camera.position.z = 5;
    console.log("Camera moved.");
  },
  undefined,
  function (error) {
    console.error(error);
  }
);

container.appendChild(renderer.domElement);

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