Appearance
光源和阴影
聚光源
沿着特定方向会逐渐发散的光源,照射范围在三维空间中构成一个圆锥体
js
const spotLight = new THREE.SpotLight(0xffffff, 0.8);
// 设置聚光光源位置
spotLight.position.set(0, 50, 0);
scene.add(spotLight); //光源添加到场景中
spotLight.intensity = 1.0; //修改光照强度
聚光源位置.position
js
spotLight.position.set(0, 50, 0);
聚光源发散角度.angle
js
spotLight.angle = Math.PI / 6; //光锥角度的二分之一
聚光源目标对象.target
js
// spotLight.target 默认是坐标原点
spotLight.target.position.set(50, 0, 0);
scene.add(spotLight.target);
注意
spotLight.target
要添加到场景中, .target.position
才会起作用
聚光源辅助对象SpotLightHelper
js
// 聚光源辅助对象,可视化聚光源
const spotLightHelper = new THREE.SpotLightHelper(spotLight, 0xffffff);
scene.add(spotLightHelper);
平行光阴影计算
点光源、聚光源、平行光等都可以产生阴影, 需要开启一些配置才会显现
1. 模型阴影投射.castShadow
js
// 设置产生投影的网格模型
mesh.castShadow = true;
2. 光源阴影投射属性.castShadow
光源默认不产生阴影,需要代码开启阴影投射属性
js
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 平行光设置产生阴影的光源对象,开启光源阴影的计算功能
directionalLight.castShadow = true;
3. 模型阴影接收属性.receiveShadow
js
// 设置接收阴影的投影面
planeMesh.receiveShadow = true;
4. .shadowMap.enabled
允许渲染器渲染阴影
开启 WebGL 的渲染器的阴影贴图属性
js
// 设置渲染器,允许光源阴影渲染
renderer.shadowMap.enabled = true;
5. 平行光阴影相机属性.shadow.camera
(阴影渲染范围)
该属性的属性值是一个正投影相机对象OrthographicCamera
js
// 平行光阴影相机属性
directionalLight.shadow.camera;
CameraHelper
可视化.shadow.camera
js
// 可视化平行光阴影对应的正投影相机对象
const cameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
scene.add(cameraHelper);
TIP
- 平行光阴影相机的位置
.shadow.camera.position
, 默认就是平行光的位置属性directionalLight.position
.shadow.camera
属性值是正投影相机OrthographicCamera
, 属性配置可以完全参考
阴影.mapSize
和.radius
这两个属性主要影响阴影的渲染质量
light.shadow.mapSize
阴影贴图尺寸属性
调节阴影边缘不够清晰、模糊感或锯齿感,值越大阴影渲染质量越好
js
// 默认值为 512x512, 尺寸一般2的n次方
directionalLight.shadow.mapSize.set(128, 128);
阴影半径.shadow.radius
属性
通过该属性调节阴影边缘与非阴影区域渐变过渡, 阴影边缘逐渐弱化或模糊化
js
directionalLight.shadow.radius = 3;
平行光模拟太阳光
1. 平行光辅助对象DirectionalLightHelper
可视化平行光.position
和照射方向
js
// 参数2表示平行光.position附近方框的尺寸
const dirHelper = new THREE.DirectionalLightHelper(directionalLight, 5);
scene.add(dirHelper);
2. 平行光位置和方向 GUI 可视化控制
添加高度控制
jsgui.add(directionalLight.position, "y", 0, 300);
添加绕 Y 轴的旋转控制
通过三角函数、指定半径还有角度计算出 x、z 坐标
jsconst obj = { R: 100, angle: 0 }; //控制旋转半径 gui.add(obj, "R", 0, 300).onChange(function (value) { directionalLight.position.x = value * Math.cos(obj.angle); directionalLight.position.z = value * Math.sin(obj.angle); }); //控制旋转角度 gui.add(obj, "angle", 0, Math.PI * 2).onChange(function (value) { directionalLight.position.x = obj.R * Math.cos(value); directionalLight.position.z = obj.R * Math.sin(value); });
3. 更新平行光辅助对象 DirectionalLightHelper
当平行光位置变化时,执行helper.update()
更新平行光辅助对象DirectionalLightHelper
的姿态同步变化
js
gui.add(directionalLight.position, "y", 0, 300).onChange(function (value) {
dirHelper.update();
});
js
gui.add(obj, "R", 0, 300).onChange(function (value) {
directionalLight.position.x = value * Math.cos(obj.angle);
directionalLight.position.z = value * Math.sin(obj.angle);
dirHelper.update();
});
gui.add(obj, "angle", 0, Math.PI * 2).onChange(function (value) {
directionalLight.position.x = obj.R * Math.cos(value);
directionalLight.position.z = obj.R * Math.sin(value);
dirHelper.update();
});
模拟太阳光阴影
1. 允许光源和渲染器光源投影计算
js
directionalLight.castShadow = true;
renderer.shadowMap.enabled = true;
2. 设置模型产生和接收阴影
所有模型既可以产生阴影, 也能够接收阴影, 给外部 gltf 模型批量配置
js
//递归遍历场景,允许所有Mesh产生投影、接收投影
gltf.scene.traverse(function (obj) {
if (obj.isMesh) {
// 批量设置所有Mesh都可以产生阴影和接收阴影
obj.castShadow = true;
obj.receiveShadow = true;
}
});
3. 调节阴影范围
通过 CameraHelper
辅助调试参数, 让平行光源覆盖要产生阴影的外部模型区域
js
//设置三维场景 directionalLight.shadow.camera 计算阴影的范围
//...
// 可视化平行光阴影对应的正投影相机对象
const cameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
scene.add(cameraHelper);
4. 阴影条纹问题解决.shadowMap.type
js
// 模型表面产生条纹影响渲染效果,可以改变.shadowMap.type默认值优化
renderer.shadowMap.type = THREE.VSMShadowMap;
5. 优化阴影效果
js
// 如果阴影边缘锯齿感的时候,可以适当提升像素
directionalLight.shadow.mapSize.set(1024, 1024);
// 模糊弱化阴影边缘
directionalLight.shadow.radius = 3;
gui 辅助调节光源阴影
js
// 阴影子菜单
const shadowFolder = gui.addFolder("平行光阴影");
const cam = directionalLight.shadow.camera;
js
// 相机left、right等属性变化执行.updateProjectionMatrix();
// 相机变化了,执行CameraHelper的更新方法.update();
shadowFolder.add(cam, "right", 0, 500).onChange(function (v) {
cam.updateProjectionMatrix();
cameraHelper.update();
});
shadowFolder.add(cam, "far", 0, 1000).onChange(function (v) {
cam.updateProjectionMatrix();
cameraHelper.update();
});
//...
注意
directionalLight.shadow.camera
参数改变后,注意执行 cameraHelper.update();