
three.js SpotLightShadow 详解聚光灯投影相机的配置与实现原理【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.jsSpotLightShadow是 three.js 中SpotLight聚光灯的阴影配置类继承自抽象基类LightShadow负责描述阴影相机Shadow Camera、阴影贴图分辨率、偏移偏置等所有与投影相关的数据。读完本文你将理解focus、aspect两个特有属性的计算公式与影响机制掌握基类继承的完整参数表并能在真实示例如 webgl_lights_spotlight.html中配置出无阴影痤疮、边缘锐利的聚光灯投影。继承结构与类定位文档定义的继承链为LightShadow → SpotLightShadow这一关系在单元测试 SpotLightShadow.tests.js 中被明确验证QUnit.test( Extending, ( assert ) { const object new SpotLightShadow(); assert.strictEqual( object instanceof LightShadow, true, SpotLightShadow extends from LightShadow ); } );类定义位于 SpotLightShadow.js注意源文件顶部注释沿用了“directional lights”的措辞但实现针对的是聚光灯的透视阴影相机。SpotLight在构造时直接内建一个阴影实例见 SpotLight.js/** * This property holds the lights shadow configuration. * * type {SpotLightShadow} */ this.shadow new SpotLightShadow();并且SpotLight.dispose()会级联调用this.shadow.dispose()释放 GPU 端阴影贴图资源——这意味着删除聚光灯时阴影资源随之回收无需手动清理。构造函数默认阴影相机文档给出的构造函数签名为new SpotLightShadow()无参数。源码实现如下SpotLightShadow.js#L15-L45constructor() { super( new PerspectiveCamera( 50, 1, 0.5, 500 ) ); this.isSpotLightShadow true; this.focus 1; this.aspect 1; }三个关键点阴影相机是一台透视相机默认参数为fov50、aspect1、near0.5、far500。这与平行光DirectionalLightShadow使用正交相机形成对比——聚光灯光束本身是锥形用透视投影才能正确覆盖光锥内近大远小的深度分布。this.focus 1阴影相机视场角为聚光灯视场角的百分比取值范围[0, 1]。this.aspect 1阴影贴图长宽比的额外缩放因子。特有属性详解.focus : number默认值 1取值范围 [0, 1]focus决定阴影相机的视场角相对聚光灯本体的“聚焦程度”。从源码结构看它只在渲染管线调用updateMatrices时生效SpotLightShadow.js#L47-L66updateMatrices( light ) { const camera this.camera; const fov RAD2DEG * 2 * light.angle * this.focus; const aspect ( this.mapSize.width / this.mapSize.height ) * this.aspect; const far light.distance || camera.far; if ( fov ! camera.fov || aspect ! camera.aspect || far ! camera.far ) { camera.fov fov; camera.aspect aspect; camera.far far; camera.updateProjectionMatrix(); } super.updateMatrices( light ); }由此可以推出几个实用结论视场角公式fov 57.2958 * 2 * light.angle * focusRAD2DEG将弧度转角度。默认focus 1时阴影相机恰好覆盖整个光锥调小focus如 0.5会让阴影相机“放大”到光锥中心区域等效于把阴影贴图的像素集中到聚光灯锥体核心代价是锥体边缘超出阴影相机范围的部分将不再被阴影相机覆盖。惰性更新只有当fov / aspect / far任一发生变化时才重建投影矩阵渲染管线每帧调用该方法不会产生冗余开销。far的取值逻辑是light.distance || camera.far——当聚光灯设置了非零的distance即光衰减范围有限时阴影远平面自动收缩到distance避免把像素浪费在光已不可见的区域。.aspect : number默认值 1aspect是阴影贴图长宽比的额外乘数同样在updateMatrices中参与计算(mapSize.width / mapSize.height) * this.aspect。若阴影贴图本身是正方形默认 512×512且aspect 1阴影相机即为正方形视口修改该值可以拉伸/压缩阴影相机横向视野适合需要非方形阴影覆盖范围的场景。.isSpotLightShadow : boolean (readonly)类型测试标志默认true用于在ObjectLoader反序列化或业务代码中区分不同光型的阴影类。单元测试中对它有独立断言SpotLightShadow.tests.js#L31-L39。继承自 LightShadow 的完整参数表SpotLightShadow的全部通用能力来自 LightShadow.js 基类构造函数。以下是文档未展开、但对调参至关重要的继承属性属性类型默认值说明.cameraCameraPerspectiveCamera(50, 1, 0.5, 500)阴影相机即聚光灯“眼中的世界”.intensitynumber1阴影浓度取值[0, 1]越小阴影越淡.biasnumber0深度偏置微小调整约0.0001量级可缓解阴影伪影.biasNodeNodefloatnullbias的节点版本仅WebGPURenderer支持定义后bias失效.normalBiasnumber0沿法线方向偏移查询位置可抑制大面积、浅角度光照下的阴影痤疮代价是阴影可能轻微变形.radiusnumber1大于 1 时模糊阴影边缘过高会引入条带BasicShadowMap下无效.blurSamplesnumber8VSM 阴影贴图模糊时的采样数.mapSizeVector2(512, 512)阴影贴图分辨率需为 2 的幂次越大越清晰但开销越高.mapTypenumberUnsignedByteType阴影贴图纹理类型.map/.mapPassRenderTargetnull深度图 / VSM 分布图渲染时由引擎内部生成.matrixMatrix4—模型空间到阴影相机空间的矩阵用于计算阴影贴图坐标.autoUpdatebooleantrue静态场景可设false省去每帧重绘阴影.needsUpdatebooleanfalse在autoUpdate false时置true触发下一次render更新阴影基类的updateMatricesLightShadow.js#L213-L224负责把阴影相机摆到聚光灯世界坐标处并朝向light.target随后_updateMatrixLightShadow.js#L235-L268将投影矩阵与视图矩阵相乘并缩放偏移到[0,1]纹理空间——这正是后续顶点着色器计算vSpotLightCoord的矩阵来源。序列化与克隆SpotLightShadow对基类的三个方法做了扩展copy(source)SpotLightShadow.js#L68-L77先调用super.copy复制相机、bias、radius、mapSize 等再复制focus与aspecttoJSON()SpotLightShadow.js#L85-L94在基类 JSON 基础上追加focus、aspect两个字段clone()继承自LightShadow.clone()通过new this.constructor().copy(this)构造同类型副本。单元测试验证了toJSON与ObjectLoader的往返一致性SpotLightShadow.tests.js#L63-L78const light new SpotLight(); const shadow new SpotLightShadow(); shadow.bias 10; shadow.radius 5; shadow.mapSize.set( 128, 128 ); light.shadow shadow; const json light.toJSON(); const newLight new ObjectLoader().parse( json ); assert.smartEqual( newLight.shadow, light.shadow, Reloaded shadow is equal to the original one );clone/copy测试同时确认了克隆是深拷贝修改副本的mapSize不会影响原实例SpotLightShadow.tests.js#L42-L61。实战配置官方示例中的完整用法webgl_lights_spotlight.html 展示了聚光灯阴影的完整配置是该类参数最直观的参考webgl_lights_spotlight.html#L99-L124spotLight new THREE.SpotLight( 0xffffff, 100 ); spotLight.position.set( 2.5, 5, 2.5 ); spotLight.angle Math.PI / 6; spotLight.penumbra 1; spotLight.decay 2; spotLight.distance 0; spotLight.castShadow true; spotLight.shadow.mapSize.width 1024; spotLight.shadow.mapSize.height 1024; spotLight.shadow.camera.near 2; spotLight.shadow.camera.far 10; spotLight.shadow.focus 1; spotLight.shadow.bias - .003; spotLight.shadow.intensity 1; scene.add( spotLight ); // 调试用辅助线可视化阴影相机的视锥 spotLight.shadowCameraHelper new THREE.CameraHelper( spotLight.shadow.camera ); spotLight.shadowCameraHelper.visible false; scene.add( spotLight.shadowCameraHelper );几点值得注意camera.near/far直接手改虽然updateMatrices会在far变化时按light.distance覆写但示例中distance 0far保持手设值10。收窄 near/far如2 → 10能显著提升深度精度减少阴影痤疮。bias -0.003负向偏置把查询深度向光源方向推近是消除贴面阴影痤疮的常用手段基类注释提示该值通常在0.0001量级微调本示例用了更大的-0.003以适配具体场景几何。GUI 可调focus示例把spotLight.shadow.focus暴露到控制面板webgl_lights_spotlight.html#L179-L229实时观察聚焦对阴影范围的影响。CameraHelper可视化把spotLight.shadow.camera包进CameraHelper即可看到阴影相机视锥与光锥的对齐关系是调试focus/aspect最直观的工具。SpotLight源码注释中还提供了一个经典范式SpotLight.js#L11-L23castShadow truemapSize设为 1024 显式设置shadow.camera.near/far/fov配合spotLight.map可产生带纹理调制的“饼干光”效果。渲染管线中的消费方式从着色器侧看SpotLightShadow的配置最终通过spotLightShadows[ i ]结构体数组传入 GPU。在 shadowmap_pars_fragment.glsl.js 中声明uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];片元端lights_fragment_begin.glsl.js#L144-L145用它查阴影贴图并调制直接光spotLightShadow spotLightShadows[ i ]; directLight.color * ( directLight.visible receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowIntensity, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;顶点端shadowmap_vertex.glsl.js则在计算阴影坐标前应用shadowNormalBias对应normalBias属性的几何偏移策略。WebGLLights与WebGLProgram负责把SpotLightShadow实例的字段打包进上述 uniform因此调整 CPU 端属性如bias、radius会在下一次编译/绘制时直接反映到 GPU 计算中。参数调优速查结合源码实现与官方示例聚光灯阴影常见问题的处理路径现象调整项依据阴影贴图覆盖范围不足/溢出focus调大趋近 1或调小视场角公式fov 2·angle·focus弧度→角度边缘锯齿mapSize升到 1024/2048配合radius轻微模糊基类注释高radius会引入条带需更大贴图支撑阴影痤疮贴面带噪微调bias±0.0001量级或增大normalBias基类属性注释示例中bias -0.003静态场景性能浪费autoUpdate false需要时needsUpdate trueLightShadow.js#L140-L158阴影相机范围不匹配光锥检查light.distance决定far与aspect乘数updateMatrices实现小结SpotLightShadow以极简的三个特有成员focus、aspect、isSpotLightShadow扩展了LightShadow基类构造时注入一台透视阴影相机updateMatrices根据聚光灯的angle、distance动态重算视场角、纵横比与远平面copy/clone/toJSON保证克隆与场景序列化ObjectLoader往返的完整性。配合 webgl_lights_spotlight.html 中的CameraHelper调试手段与本文的调优速查表即可对聚光灯投影做像素级的精确控制。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考