关于 threejs-lighting
面向 Three.js 开发者的灯光参考技能,覆盖多种灯光、阴影与环境照明,并提供 WebGLRenderer 和 WebGPURenderer 示例。
主要功能
- 01介绍常见灯光类型与单位
- 02讲解阴影设置与调试
- 03配置环境照明和光照探针
- 04提供常见照明方案与动画示例
适用场景
- 01为场景选择合适的灯光类型
- 02调整定向光、点光或聚光灯阴影
- 03为材质添加 HDR 环境照明
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ cloudai-x/ threejs-skills --skill threejs-lighting安装后在 Claude Code 中输入/threejs-lighting确认已加载。
详细介绍
Three.js 光照
面向 three.js r186。示例使用 WebGLRenderer;WebGPU 和 TSL 部分使用 WebGPURenderer。
快速入门
import * as THREE from "three";
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(4, 3, 8);
// A single directional light: intensity is a plain multiplier, no distance falloff
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.position.set(5, 10, 5);
scene.add(dirLight);
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(20, 20),
new THREE.MeshStandardMaterial({ color: 0x808080 })
);
floor.rotation.x = -Math.PI / 2;
scene.add(floor);
const mesh = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({ color: 0x3a76c4 })
);
scene.add(mesh);
// Shadows need three switches: renderer, light, and the meshes that cast and receive
renderer.shadowMap.enabled = true;
dirLight.castShadow = true;
mesh.castShadow = true;
floor.receiveShadow = true;
function animate() {
renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);
光源类型和单位
| 光源 | 阴影 | 强度 | 说明 |
|---|---|---|---|
| AmbientLight | 否 | 倍数 | 从各个方向均匀照亮 |
| HemisphereLight | 否 | 倍数 | 上方为天空颜色,下方为地面颜色 |
| DirectionalLight | 是 | 倍数 | 平行光线(太阳);朝向其目标照射 |
| SunLight(附加组件) | 是,级联 | 倍数 | 阴影视锥会自动适配视图 |
| PointLight | 是,六个面 | 坎德拉 | 按平方反比衰减(decay 为 2) |
| SpotLight | 是 | 坎德拉 | 锥形光束;按平方反比衰减(decay 为 2) |
| RectAreaLight | 否 | 尼特 | 仅适用于 MeshStandardMaterial 和 MeshPhysicalMaterial |
| LightProbe | 否 | 倍数 | 球谐环境光,通常为预烘焙 |
PointLight 和 SpotLight 的强度单位为坎德拉,并按平方反比衰减(decay 默认为 2):距离为 5 个单位的 1 坎德拉光源贡献为 1/25,因此合适的数值取决于距离,通常可达数百(官方文档示例使用 80 到 1000)。light.power 以流明为单位设置相同的光照。light.distance 是平滑的截断范围(0 表示不限制)。DirectionalLight、AmbientLight 和 HemisphereLight 的强度都是无单位的倍数。RectAreaLight 的强度单位为尼特(每平方米坎德拉)。
环境光和半球光
// AmbientLight(color, intensity) — a flat multiplier on every lit material
const ambient = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambient);
// HemisphereLight(skyColor, groundColor, intensity)
const hemi = new THREE.HemisphereLight(0x87ceeb, 0x8b6f47, 0.6);
scene.add(hemi);
DirectionalLight
// DirectionalLight(color, intensity): parallel rays from position towards target; the distance only matters to the shadow camera
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.position.set(5, 10, 5);
// Shines from its position towards target; add the target to the scene when you move it
dirLight.target.position.set(0, 0, 0);
scene.add(dirLight.target);
scene.add(dirLight);
SunLight:自动级联阴影
SunLight(three/addons/lights/SunLight.js)是一种平行光,带有两张级联阴影贴图,适用于大型场景。它没有目标:光线从其位置朝向原点,默认垂直向下照射。使用 WebGLRenderer 时可直接工作;使用 WebGPURenderer 时需先注册(参见 WebGPU 和 TSL)。
import { SunLight } from "three/addons/lights/SunLight.js";
const sun = new SunLight(0xfff2e3, 3);
sun.position.set(100, 160, 60);
sun.castShadow = true;
scene.add(sun);
级联会自动适配相机视锥体的各个切片,范围最多到 sun.shadow.camera.far 或视图相机的远平面,以较小者为准。shadow.camera.left/right/top/bottom 会被忽略;每个级联的默认 mapSize 为 1024 × 1024。无需手动收紧阴影视锥。
PointLight 和 SpotLight
// PointLight(color, intensity in candela, distance, decay)
const bulb = new THREE.PointLight(0xffdcb0, 100, 20, 2);
bulb.position.set(0, 4, 0);
scene.add(bulb);
// SpotLight(color, intensity in candela, distance, angle, penumbra, decay)
const deskLamp = new THREE.SpotLight(0xffffff, 250, 30, Math.PI / 6, 0.4, 2);
deskLamp.position.set(2, 5, 0);
deskLamp.target.position.set(0, 0, 0);
scene.add(deskLamp.target);
scene.add(deskLamp);
// Prefer lumens: power writes the candela intensity for you
bulb.power = 800;
angle 是以弧度为单位的锥形半角,上限为 Math.PI / 2;penumbra(0 到 1)用于柔化锥形边缘。
RectAreaLight
矩形发光体,可产生适合窗户或灯带的柔和光照。它仅照亮 MeshStandardMaterial 和 MeshPhysicalMaterial,且无法投射阴影。
import { RectAreaLightHelper } from "three/addons/helpers/RectAreaLightHelper.js";
import { RectAreaLightUniformsLib } from "three/addons/lights/RectAreaLightUniformsLib.js";
// WebGLRenderer: add the LTC lookup textures to the renderer's uniforms, once
RectAreaLightUniformsLib.init();
// RectAreaLight(color, intensity in nits, width, height)
const windowLight = new THREE.RectAreaLight(0xffffff, 5, 4, 10);
windowLight.position.set(-5, 5, 0);
windowLight.lookAt(0, 0, 0); // emits from its front face
scene.add(windowLight);
// The helper must be added as a child of the light
const helper = new RectAreaLightHelper(windowLight);
windowLight.add(helper);
使用 WebGPURenderer 时,应改用 RectAreaLightTexturesLib 注册 LTC 纹理(参见 WebGPU 和 TSL)。
阴影
// 1. Renderer: shadow maps are off by default; PCFShadowMap is the soft filtered default,
// VSMShadowMap blurs the map itself, BasicShadowMap is hard-edged
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
// 2. Light
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.position.set(5, 10, 5);
dirLight.castShadow = true;
scene.add(dirLight);
// 3. Objects
mesh.castShadow = true;
mesh.receiveShadow = true;
shadow.radius 大于 1 时会加宽 PCF 滤波和 VSM 模糊;对 BasicShadowMap 无效。VSM 还提供 shadow.blurSamples(默认为 8),而 PointLight 阴影完全不支持 VSM——WebGLRenderer 会发出警告并跳过该光源的阴影。PCFSoftShadowMap 已弃用:它会发出警告并回退到 PCFShadowMap,而后者本身已经是软阴影。使用 VSMShadowMap 时,每个接收阴影的网格也会投射阴影。
调整方向光阴影
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.position.set(5, 10, 5); // every caster must lie between near and far from here
dirLight.castShadow = true;
// The shadow camera sits at the light's position and looks at its target: near and far
// are distances from the light; left/right/top/bottom frame the area around the target
const shadowCam = dirLight.shadow.camera;
shadowCam.left = -10;
shadowCam.right = 10;
shadowCam.top = 10;
shadowCam.bottom = -10;
shadowCam.near = 0.5;
shadowCam.far = 50;
shadowCam.updateProjectionMatrix(); // needed whenever these change after the first render
dirLight.shadow.mapSize.set(2048, 2048); // powers of two
// Acne: normalBias offsets the lookup along the surface normal (light grazing a surface);
// bias offsets the depth compared against the map — start tiny, negative fights acne
dirLight.shadow.normalBias = 0.02;
dirLight.shadow.bias = -0.0001;
// Lighten shadows without adding fill lights: 0 removes, 1 is full darkness
dirLight.shadow.intensity = 0.7;
点光和聚光灯的阴影相机由系统推导
渲染器会在每次阴影渲染时重建这些相机:聚光灯阴影的视野角为 2 × angle × shadow.focus(以度为单位),远平面取自 light.distance;点光源的远平面也取自 light.distance。视野角始终会被覆盖;只有当 distance 为 0 时,手动设置的 far 才会保留。使用 angle 和 shadow.focus 控制锥形光束,使用 distance 控制范围。
const deskLamp = new THREE.SpotLight(0xffffff, 250, 30);
deskLamp.castShadow = true;
deskLamp.shadow.mapSize.set(1024, 1024);
deskLamp.shadow.focus = 0.9; // shadow fov as a fraction of the light's cone
deskLamp.shadow.bias = -0.0001;
将 new THREE.CameraHelper(light.shadow.camera) 添加到场景中,可视化方向光或聚光灯的阴影相机;更改相机后,调用辅助对象的 update()。
接触阴影(伪造,成本低)
为了营造物体落地的效果,每盏灯都用一张阴影贴图实在太浪费;径向渐变阴影只需绘制一个带纹理的四边形。
// A soft blob under the object: no shadow map, works under both renderers
const size = 128;
const canvas = document.createElement("canvas");
canvas.width = canvas.height = size;
const ctx = canvas.getContext("2d");
const gradient = ctx.createRadialGradient(size / 2, size / 2, 0, size / 2, size / 2, size / 2);
gradient.addColorStop(0, "rgba(0,0,0,0.6)");
gradient.addColorStop(1, "rgba(0,0,0,0)");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, size, size);
const shadowTexture = new THREE.CanvasTexture(canvas);
shadowTexture.colorSpace = THREE.SRGBColorSpace; // a canvas used as a color map is sRGB
const blob = new THREE.Mesh(
new THREE.PlaneGeometry(2, 2),
new THREE.MeshBasicMaterial({ map: shadowTexture, transparent: true, depthWrite: false })
);
blob.rotation.x = -Math.PI / 2;
blob.position.y = 0.001; // just above the floor to avoid z-fighting
scene.add(blob);
若要让阴影轮廓跟随物体,可从下方向渲染目标渲染深度,再进行模糊处理——官方的 webgl_shadow_contact 示例使用了 three/addons/shaders/ 中的 HorizontalBlurShader 和 VerticalBlurShader。
灯光辅助对象
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
const hemi = new THREE.HemisphereLight(0x87ceeb, 0x8b6f47, 0.6);
const bulb = new THREE.PointLight(0xffdcb0, 100, 20);
const deskLamp = new THREE.SpotLight(0xffffff, 250, 30);
scene.add(dirLight, hemi, bulb, deskLamp);
// Built-in helpers are objects: add them to the scene
const dirHelper = new THREE.DirectionalLightHelper(dirLight, 5);
const pointHelper = new THREE.PointLightHelper(bulb, 0.5);
const spotHelper = new THREE.SpotLightHelper(deskLamp);
const hemiHelper = new THREE.HemisphereLightHelper(hemi, 5);
scene.add(dirHelper, pointHelper, spotHelper, hemiHelper);
所有灯光辅助对象都只会在 update() 中复制灯光的颜色;DirectionalLightHelper、SpotLightHelper 和 HemisphereLightHelper 也只会在此处重新调整朝向:更改灯光颜色后,以及移动或重新调整这三种灯光的朝向后,都要调用 update()。
环境光照(IBL)
import { HDRLoader } from "three/addons/loaders/HDRLoader.js";
// Both renderers prefilter an equirect environment themselves: assign it directly
const hdr = await new HDRLoader().loadAsync("sunset.hdr");
hdr.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = hdr; // lights the scene
scene.background = hdr; // optional: also draw it behind the scene
scene.environmentIntensity = 1; // scales the lighting contribution only
scene.environmentRotation.set(0, Math.PI / 4, 0); // rotates the lighting
scene.backgroundBlurriness = 0; // blurs the background, not the lighting
scene.backgroundIntensity = 1;
scene.backgroundRotation.set(0, 0, 0); // rotates the background independently
两种渲染器都会使用 scene.environment 为 MeshStandardMaterial 和 MeshPhysicalMaterial 提供光照;WebGLRenderer 也会为 MeshLambertMaterial 和 MeshPhongMaterial 提供光照,而 WebGPURenderer 不会。场景生成的环境仍需使用 PMREMGenerator;对于等距柱状投影文件,它只会重复渲染器已经执行的预过滤:
import { RoomEnvironment } from "three/addons/environments/RoomEnvironment.js";
const pmrem = new THREE.PMREMGenerator(renderer);
const room = new RoomEnvironment();
scene.environment = pmrem.fromScene(room, 0.04).texture;
room.dispose(); // frees the room's geometries and materials
pmrem.dispose();
立方体纹理无需设置映射即可用作环境:
const cubeEnv = await new THREE.CubeTextureLoader().loadAsync([
"px.jpg",
"nx.jpg",
"py.jpg",
"ny.jpg",
"pz.jpg",
"nz.jpg",
]);
scene.environment = cubeEnv;
scene.background = cubeEnv;
光照探针
import { LightProbeGenerator } from "three/addons/lights/LightProbeGenerator.js";
// Bake ambient spherical harmonics from what a cube camera sees
const cubeCamera = new THREE.CubeCamera(0.1, 100, new THREE.WebGLCubeRenderTarget(256));
cubeCamera.update(renderer, scene);
const lightProbe = await LightProbeGenerator.fromCubeRenderTarget(renderer, cubeCamera.renderTarget);
scene.add(lightProbe);
LightProbeGenerator.fromCubeTexture(cubeTexture) 可从已加载的立方体纹理同步生成光照探针。若要实现随位置变化的环境光,请改为烘焙 3D 网格:使用 WebGLRenderer 时选用 LightProbeGridWebGL,使用 WebGPURenderer 时选用 LightProbeGrid(位于 three/addons/lighting/)。使用 WebGPURenderer 时,需通过 three/webgpu 中的 CubeRenderTarget 构建立方体渲染目标。
import { LightProbeGridWebGL } from "three/addons/lighting/LightProbeGridWebGL.js";
// A 10 × 4 × 10 volume centered on its position, size + 1 probes per axis by default
const probeGrid = new LightProbeGridWebGL(10, 4, 10);
probeGrid.position.set(0, 2, 0);
scene.add(probeGrid);
probeGrid.bake(renderer, scene); // bake again when the static lighting changes
常见配置
// Three-point lighting: key, fill, rim
const keyLight = new THREE.DirectionalLight(0xffffff, 2);
keyLight.position.set(5, 6, 4);
const fillLight = new THREE.DirectionalLight(0xffffff, 0.5);
fillLight.position.set(-5, 3, 5);
const backLight = new THREE.DirectionalLight(0xffffff, 1);
backLight.position.set(-4, 5, -6);
scene.add(keyLight, fillLight, backLight);
import { SunLight } from "three/addons/lights/SunLight.js";
// Outdoor daylight: sun with cascaded shadows plus a sky gradient
const sun = new SunLight(0xfff2e3, 3);
sun.position.set(100, 160, 60);
sun.castShadow = true;
const sky = new THREE.HemisphereLight(0x87ceeb, 0x8b6f47, 0.5);
scene.add(sun, sky);
为灯光添加动画
// Timer drives per-frame time: update() first, then read it
const timer = new THREE.Timer();
timer.connect(document); // avoids huge deltas after tab switches
const lamp = new THREE.PointLight(0xffd0a0, 100, 20);
scene.add(lamp);
function animate() {
timer.update();
const t = timer.getElapsed();
lamp.position.set(Math.cos(t) * 4, 3, Math.sin(t) * 4);
lamp.intensity = 100 + Math.sin(t * 2) * 30;
renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);
性能
- 两种渲染器都会将灯光集合编译进每个受光材质中:添加或移除灯光(仅 WebGPURenderer 中的 AmbientLight),或切换
castShadow,都会触发重新编译。移除不使用的灯光;运行时通过灯光的intensity开关灯光。在 WebGPURenderer 中,只要不投射阴影且聚光灯没有map,DynamicLighting就能在环境光、半球光、方向光、点光源或聚光灯增减时保持材质已编译;ClusteredLighting则可扩展以支持大量点光源(参见 WebGPU 和 TSL)。 - 每盏投射阴影的灯光都会增加深度渲染通道(点光源有六个)。不需要阴影的地方应关闭
castShadow。 - 静态场景:按需渲染灯光阴影,设置
light.shadow.autoUpdate = false; light.shadow.needsUpdate = true;,并在有物体移动后再次设置light.shadow.needsUpdate = true;(两种渲染器均适用;WebGLRenderer 还提供全局设置renderer.shadowMap.autoUpdate)。 - 收紧方向光阴影视锥,或改用 SunLight,它会自动根据视图调整阴影视锥。
- 灯光不会按网格物体的图层进行筛选:灯光的图层只会与相机的图层进行比对。若要只照亮选定的网格物体,可在 WebGPURenderer 中使用
material.lightsNode。
WebGPU 和 TSL
灯光类、阴影设置和上述场景环境属性都可用于 WebGPURenderer,但本节替换的仅限 WebGL 的部分除外:RectAreaLightUniformsLib、WebGLCubeRenderTarget(改用 CubeRenderTarget)、LightProbeGridWebGL(改用 LightProbeGrid)以及全局设置 renderer.shadowMap.autoUpdate。SunLight 必须注册;此外,scene.environment 在此处不会为 Lambert 或 Phong 材质提供光照。
import * as THREE from "three/webgpu";
const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init(); // before any other use of the renderer
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x101010); // the WebGPU canvas is transparent by default
const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(4, 3, 8);
renderer.shadowMap.enabled = true;
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.castShadow = true;
scene.add(dirLight);
function animate() {
renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);
import * as THREE from "three/webgpu";
import { RectAreaLightTexturesLib } from "three/addons/lights/RectAreaLightTexturesLib.js";
import { SunLight } from "three/addons/lights/SunLight.js";
import { SunLightNode } from "three/addons/lights/SunLightNode.js";
import { ClusteredLighting } from "three/addons/lighting/ClusteredLighting.js";
// RectAreaLight: register the LTC textures once (replaces RectAreaLightUniformsLib)
THREE.RectAreaLightNode.setLTC(RectAreaLightTexturesLib.init());
// SunLight: register its node implementation once
renderer.library.addLight(SunLightNode, SunLight);
// Many point lights: clustered Forward+ shading (DynamicLighting instead avoids recompiles when unshadowed lights come and go)
renderer.lighting = new ClusteredLighting();
import * as THREE from "three/webgpu";
import { lights } from "three/tsl";
const keyLight = new THREE.PointLight(0x66aaff, 120, 20);
scene.add(keyLight);
// A material lit only by keyLight, ignoring every other light in the scene
const material = new THREE.MeshStandardNodeMaterial();
material.lightsNode = lights([keyLight]);
彩色阴影:启用 renderer.shadowMap.transmitted = true 后,投射阴影的物体会将颜色和 alpha 写入阴影贴图,来源可以是 material.castShadowNode(一个 vec4),也可以是 map 和 colorNode 的 alpha。material.receivedShadowNode(一个以阴影值为参数的 Fn)可更改接收阴影的物体应用阴影的方式,且无需启用该标志。
常见错误
light.layers.set(1);→material.lightsNode = lights([keyLight, fillLight]);:灯光不会按图层过滤网格——灯光的图层会与摄像机的图层进行比对,因此这会关闭整个场景的灯光;按材质选择需要使用节点材质,可通过 WebGPURenderer 实现,或在 WebGLRenderer 下通过 WebGLNodesHandler 插件实现。new THREE.PointLight(0xffffff, 1, 100);→new THREE.PointLight(0xffffff, 100, 20);:点光源和聚光灯的强度单位是坎德拉,并按平方反比衰减,因此强度为 1 时在较远距离几乎没有贡献;典型值可达数百。renderer.useLegacyLights = true;→const bulb = new THREE.PointLight(0xffffff, 100, 20);:旧版灯光单位已不存在,useLegacyLights 和 physicallyCorrectLights 也都不起作用,因此应改用坎德拉重新调整点光源和聚光灯。renderer.shadowMap.type = THREE.PCFSoftShadowMap;→renderer.shadowMap.type = THREE.PCFShadowMap;:PCFSoftShadowMap 已在 r182 中弃用;两个渲染器都会发出警告并回退到 PCFShadowMap,而它本身已经具有柔和效果。lightProbe.copy(LightProbeGenerator.fromCubeRenderTarget(renderer, rt));→lightProbe.copy(await LightProbeGenerator.fromCubeRenderTarget(renderer, rt));:该调用是异步的,会返回 Promise,而 copy() 无法读取它。new ContactShadows({ opacity: 0.5 });→new THREE.Mesh(new THREE.PlaneGeometry(2, 2), new THREE.MeshBasicMaterial({ transparent: true, map: blobTexture }));:three.js 没有 ContactShadows 类(它是一个 drei 组件);可用径向渐变平面模拟接触阴影。scene.environment = pmremGenerator.fromEquirectangular(texture).texture;→texture.mapping = THREE.EquirectangularReflectionMapping; scene.environment = texture;:渲染器会自行对等距柱状环境贴图进行预过滤,因此手动调用 PMREM 不会提升画质;PMREMGenerator 仍可用于 fromScene。scene.background = hdr;→hdr.mapping = THREE.EquirectangularReflectionMapping; scene.background = hdr;:HDRLoader 返回的纹理使用 UV 映射,因此若缺少这一行,背景会被绘制成平面的屏幕空间图像。import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";→import { HDRLoader } from "three/addons/loaders/HDRLoader.js";:RGBELoader 在 r180 中更名为 HDRLoader,并且必须从 three/addons/ 导入插件,导入映射才能解析。spotLight.shadow.camera.fov = 30;→spotLight.shadow.focus = 0.9;:阴影摄像机的 fov 会在每次渲染时重新计算为 2 × angle × focus(单位为度),因此应通过灯光的 angle 和 focus 控制它。const lamp = new THREE.PointLight(0xffffff, 100, 20); lamp.shadow.camera.far = 50;→const lamp = new THREE.PointLight(0xffffff, 100, 50);:非零 distance 会在每次阴影渲染时覆盖阴影摄像机的 far,因此应通过 distance 设置阴影范围;只有 distance 为 0 时,才会保留手动设置的 far。material.envMapIntensity = 0.5;→scene.environmentIntensity = 0.5;:envMapIntensity 只会缩放材质自身的 envMap,不会缩放 scene.environment。const clock = new THREE.Clock();→const timer = new THREE.Timer(); timer.connect(document);:Clock 已在 r183 中弃用;每帧调用 getDelta() 或 getElapsed() 前,都要先调用 timer.update()。RectAreaLightUniformsLib.init();→THREE.RectAreaLightNode.setLTC(RectAreaLightTexturesLib.init());:在 WebGPURenderer 下不会读取 uniforms 库,而且在注册纹理之前,灯光节点会解引用空的 LTC 库。
另请参阅
- threejs-materials — 材质对光线的响应方式(roughness、metalness、material.envMap)。
- threejs-textures — 加载环境贴图并设置纹理色彩空间。
- threejs-shaders — 自定义 GLSL 效果,例如菲涅耳边缘光、使用 onBeforeCompile 扩展内置受光材质,以及 TSL 中的受光节点材质。
- threejs-postprocessing — 泛光及其他与光照相关的效果。
- threejs-fundamentals — 渲染器设置、色调映射和曝光,用于物理尺度的灯光和 HDR 环境。