Three.js 模型阴影教程

📅 2026/7/1 2:22:11
Three.js 模型阴影教程
模型阴影 ·Model Shadow· ▶ 在线运行案例案例合集三维可视化功能案例threehub.cn开源仓库github地址https://github.com/z2586300277/three-cesium-examples400个案例代码:网盘链接你将学到什么Three.js实时阴影的四步开启清单castShadow与receiveShadow的分工ShadowMap 类型Basic / PCF / PCFSoft / VSM的区别用 lil-gui 动态开关阴影调试效果说明白色地面Plane上狐狸 glTF 模型与旋转立方体投射实时阴影。GUI 面板可切换阴影总开关shadowMap.enabled阴影算法类型地面是否接收阴影、立方体/光源是否投射阴影核心概念阴影渲染管线Three.js 阴影基于Shadow Mapping阴影贴图光源视角渲染一张深度图主相机渲染时比较像素深度决定是否落在阴影中。开启阴影的四步清单renderer.shadowMap.enabled truelight.castShadow true ← 至少一个光源mesh.castShadow true ← 投射阴影的物体mesh.receiveShadow true ← 接收阴影的地面/墙面缺任何一步阴影都不会出现。castShadow vs receiveShadow| 属性 | 作用 | 本案例 | |------|------|--------| |castShadow| 该 Mesh 遮挡光线产生阴影 | Fox 模型、立方体 | |receiveShadow| 该 Mesh 表面显示 others 的阴影 | 白色 Plane 地面 |同一物体可以既 cast 又 receive如地面上的盒子投阴影到地面同时接收狐狸的阴影。材质要求只有受光材质才能正确显示阴影✅MeshStandardMaterial、MeshPhongMaterial、MeshLambertMaterial❌MeshBasicMaterial— 不受光照不显示阴影本案例地面和立方体均用MeshStandardMaterial。ShadowMap 类型renderer.shadowMap.type THREE.PCFSoftShadowMap; // 默认推荐| 类型 | 特点 | |------|------| |BasicShadowMap| 硬边锯齿明显最快 | |PCFShadowMap| 百分比邻近滤波边缘稍软 | |PCFSoftShadowMap| 更柔和大多数项目默认| |VSMShadowMap| 方差阴影贴图适合大面积软阴影偶有漏光 |切换类型后需触发material.needsUpdate true本案例 GUI 的 onChange 已处理。DirectionalLight 阴影本案例用平行光变量名虽叫 pointLight从上方(0, 400, 0)照射类似太阳const light new THREE.DirectionalLight(0xffffff, 1);light.position.set(0, 400, 0); light.castShadow true;平行光阴影由正交相机light.shadow.camera定义范围大场景需调整left/right/top/bottom/near/far避免阴影裁切或分辨率浪费。实现步骤Renderer 开启shadowMap.enabled创建 DirectionalLight 并castShadow truePlane 地面receiveShadow true旋转至水平加载 Fox.glbtraverse设置子 MeshcastShadow true立方体castShadow true加入旋转动画GUI 绑定阴影开关与类型便于对比代码要点import * as THREE from threeimport { OrbitControls } from three/examples/jsm/controls/OrbitControls.js import { GLTFLoader } from three/addons/loaders/GLTFLoader.js import { GUI } from three/addons/libs/lil-gui.module.min.js;console.log(THREE.REVISION)const box document.getElementById(box)const scene new THREE.Scene()const camera new THREE.PerspectiveCamera(50, box.clientWidth / box.clientHeight, 0.1, 1000)camera.position.set(0, 10, 10)const renderer new THREE.WebGLRenderer({})renderer.setSize(box.clientWidth, box.clientHeight)renderer.shadowMap.needsUpdate truerenderer.shadowMap.enabled truebox.appendChild(renderer.domElement)const controls new OrbitControls(camera, renderer.domElement)controls.enableDamping truewindow.onresize () {renderer.setSize(box.clientWidth, box.clientHeight)camera.aspect box.clientWidth / box.clientHeightcamera.updateProjectionMatrix()}new GLTFLoader().load(GLOBAL_CONFIG.getFileUrl(files/model/Fox.glb), (gltf) {const model gltf.scenemodel.scale.set(0.01, 0.01, 0.01)model.traverse((child) {if (child.isMesh) child.castShadow true})scene.add(model)})const mesh new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshStandardMaterial({ color: 0xffffff }))mesh.castShadow truemesh.position.set(3, 1, 1)scene.add(mesh)const pointLight new THREE.DirectionalLight(0xffffff, 1)pointLight.position.set(0, 400, 0)pointLight.castShadow truescene.add(pointLight)const plane new THREE.Mesh(new THREE.PlaneGeometry(100, 100), new THREE.MeshStandardMaterial({ color: 0xffffff }))plane.position.y - 0.5plane.rotation.x -Math.PI / 2plane.receiveShadow truescene.add(plane)const folder new GUI()const shadowMapList {Basic: THREE.BasicShadowMap,PCF: THREE.PCFShadowMap,PCFSoft: THREE.PCFSoftShadowMap,VSM: THREE.VSMShadowMap}folder.add(renderer.shadowMap, enabled).name(shadowEnabled).onChange(() {scene.traverse((object) {if (object.material) object.material.needsUpdate true; })})folder.add(renderer.shadowMap, type, shadowMapList).name(shadowType).onChange(() {scene.traverse((object) {if (object.material) object.material.needsUpdate true;})})folder.add(plane, receiveShadow).name(planeShadow)folder.add(mesh, castShadow).name(boxShadow)folder.add(pointLight, castShadow).name(lightShadow)animate()function animate() {mesh.rotation.x 0.01mesh.rotation.y 0.01requestAnimationFrame(animate)controls.update()renderer.render(scene, camera)}完整源码GitHub小结阴影 Renderer 开关 光源 cast 物体 cast 地面 receive默认用PCFSoftShadowMap调试时用 GUI 对比差异阴影不显示先查材质是否为 Basic、光源/物体 flag 是否遗漏