You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js r88中PointLight阴影无法渲染问题求助

解决Three.js r88中PointLight阴影不渲染的问题

我帮你排查了代码里的几个关键问题,调整后阴影就能正常显示了,具体问题和修复方案如下:

问题1:物体位置重叠导致阴影无法投射

你的平面(Plane)和球体(Sphere)默认都在场景原点(0, 0, 0),球体完全覆盖在平面上,阴影没有投射的空间。需要把平面向下移动并调整朝向,让球体处于平面上方:

// 修改平面的位置与朝向
plane.position.y = -10;
plane.rotation.x = -Math.PI / 2; // 让平面水平放置

问题2:PointLight的阴影参数未正确配置

在Three.js r88版本中,PointLight开启castShadow = true后,默认的阴影贴图尺寸和相机参数不足以渲染出可见的阴影,需要手动配置:

function getLight(scene) {
  var light = new THREE.PointLight( 0xffffff, 1, 100 );
  light.position.set( 0, 10, 0 );
  light.castShadow = true; 
  // 提升阴影贴图分辨率,避免模糊
  light.shadow.mapSize.width = 1024;
  light.shadow.mapSize.height = 1024;
  // 调整阴影相机的裁剪范围,确保覆盖场景内的物体
  light.shadow.camera.near = 0.1;
  light.shadow.camera.far = 50;
  scene.add( light );
  var ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
  scene.add(ambientLight);
  return light;
}

问题3:球体位置优化(可选)

可以把球体向上移动一点,让阴影投射的效果更明显:

sphere.position.y = 2;

修改后的完整代码

/**
 * Generate a scene object with a background color **/
function getScene() {
 var scene = new THREE.Scene();
 scene.background = new THREE.Color(0x000000);
 return scene;
}
/**
 * Generate the camera to be used in the scene. Camera args:
 * [0] field of view: identifies the portion of the scene
 * visible at any time (in degrees)
 * [1] aspect ratio: identifies the aspect ratio of the
 * scene in width/height
 * [2] near clipping plane: objects closer than the near
 * clipping plane are culled from the scene
 * [3] far clipping plane: objects farther than the far
 * clipping plane are culled from the scene **/
function getCamera() {
 var aspectRatio = window.innerWidth / window.innerHeight;
 var camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 1000);
 camera.position.set(0, 1, -30);
 return camera;
}
/**
 * Generate the light to be used in the scene. Light args:
 * [0]: Hexadecimal color of the light
 * [1]: Numeric value of the light's strength/intensity
 * [2]: The distance from the light where the intensity is 0
 * @param {obj} scene: the current scene object **/
function getLight(scene) {
 // SHADOW
 var light = new THREE.PointLight( 0xffffff, 1, 100 );
 light.position.set( 0, 10, 0 );
 light.castShadow = true; // default false
 // 新增阴影配置
 light.shadow.mapSize.width = 1024;
 light.shadow.mapSize.height = 1024;
 light.shadow.camera.near = 0.1;
 light.shadow.camera.far = 50;
 scene.add( light );
 var ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
 scene.add(ambientLight);
 return light;
}
/**
 * Generate the renderer to be used in the scene **/
function getRenderer() {
 // Create the canvas with a renderer
 var renderer = new THREE.WebGLRenderer({antialias: true});
 // Add support for retina displays
 renderer.setPixelRatio(window.devicePixelRatio);
 // Specify the size of the canvas
 renderer.setSize(window.innerWidth, window.innerHeight);
 // SHADOW
 renderer.shadowMap.enabled = true;
 renderer.shadowMap.type = THREE.PCFSoftShadowMap;
 // Add the canvas to the DOM
 document.body.appendChild(renderer.domElement);
 return renderer;
}
/**
 * Generate the controls to be used in the scene
 * @param {obj} camera: the three.js camera for the scene
 * @param {obj} renderer: the three.js renderer for the scene **/
function getControls(camera, renderer) {
 var controls = new THREE.TrackballControls(camera, renderer.domElement);
 controls.zoomSpeed = 0.4;
 controls.panSpeed = 0.4;
 return controls;
}
// Render loop
function render() {
 requestAnimationFrame(render);
 renderer.render(scene, camera);
 controls.update();
};
var scene = getScene();
var camera = getCamera();
var light = getLight(scene);
var renderer = getRenderer();
var controls = getControls(camera, renderer);
//Create a sphere that cast shadows (but does not receive them)
var sphereGeometry = new THREE.SphereBufferGeometry( 5, 32, 32 );
var sphereMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff } );
var sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
sphere.castShadow = true; //default is false
sphere.receiveShadow = false; //default
sphere.position.y = 2; // 新增球体位置调整
scene.add( sphere );
//Create a plane that receives shadows (but does not cast them)
var planeGeometry = new THREE.PlaneGeometry( 50, 20, 32 );
var planeMaterial = new THREE.MeshPhongMaterial({ color: 0xffff00, side: THREE.DoubleSide})
var plane = new THREE.Mesh( planeGeometry, planeMaterial );
plane.receiveShadow = true;
plane.position.y = -10; // 新增平面位置调整
plane.rotation.x = -Math.PI / 2; // 新增平面朝向调整
scene.add( plane );
render();
body {
 margin: 0;
}
canvas {
 width: 100%;
 height: 100%
}
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js'></script>
<script src='https://threejs.org/examples/js/controls/TrackballControls.js'></script>

这些修改后,你就能看到球体在黄色平面上投射的柔和阴影了。核心是确保物体之间有足够的空间让阴影投射,同时正确配置PointLight的阴影参数,让渲染器能生成清晰的阴影贴图。

内容的提问来源于stack exchange,提问作者duhaime

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:10:10