three.js 线性雾(THREE.Fog):场景深度雾效的原理、配置与序列化详解
发布时间:2026/9/7 10:37:29 作者:尧图编辑部 阅读量:1,286
:场景深度雾效的原理、配置与序列化详解)
three.js 线性雾THREE.Fog场景深度雾效的原理、配置与序列化详解【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js导读THREE.Fog是 three.js 中用于创建线性雾效的核心类——物体离相机越远被雾色覆盖的比例越大距离超过far后完全隐没在雾中常用于模拟天气朦胧感、拉开场景纵深或隐藏远处加载未完成的物体。本文基于 Fog.html.md 文档结合 Fog.js 源码、Scene集成逻辑、WebGL 着色器实现与单元测试完整讲解 Fog 的构造参数、全部属性、clone/toJSON 方法、与指数雾FogExp2的选型区别以及它在渲染管线中的真实工作方式。一、什么是线性雾一个类两行接入雾效本身不是独立渲染的物体而是挂在场景上的一个状态对象。Fog描述了一种“随距离线性增密”的雾从near处开始起雾到far处雾达到完全浓度。three.js 官方注释将其定义为 “a linear fog that grows linearly denser with the distance”见 Fog.js。让场景使用雾的最小配置只需一行官方代码示例Fog.html.md如下const scene new THREE.Scene(); scene.fog new THREE.Fog( 0xcccccc, 10, 15 );这段代码的含义是场景雾色为浅灰0xcccccc距离相机 10 个单位以内不受雾影响从 10 到 15 个单位之间线性过渡超过 15 个单位后物体完全被雾色覆盖。Scene对象内置了fog属性默认null见 Scene.js因此Fog类自身没有apply、update之类的方法——它只负责描述雾实际的计算与混合发生在渲染器生成的着色器中见本文第六节。二、构造函数与默认值构造函数签名如下new Fog( color : number | Color, near : number, far : number )参数类型默认值含义colornumber | Color必填雾的颜色可传十六进制数或THREE.Color实例nearnumber1开始施加雾的最小距离farnumber1000停止计算与施加雾的最大距离从 Fog.js 的构造函数源码可以看到两个要点默认值在函数签名上直接给出constructor( color, near 1, far 1000 )。只传颜色的写法new THREE.Fog(0xcccccc)完全合法此时近处 1 个单位内无雾、1000 个单位后全雾通常适合无限远处淡出的大场景。颜色在内部被包装成 Color 对象this.color new Color( color )。因此无论传入数字还是 Color最终访问fog.color得到的都是一个 Color 实例可直接使用.r/.g/.b、.getHex()等 Color API。单元测试 Fog.tests.js 验证了三种实例化方式均可成功无参数new Fog()、仅颜色new Fog( 0xffffff )、以及完整参数new Fog( 0xffffff, 0.015, 100 )。若省略near/far建议结合实际场景尺度显式传入合理的近远值——当far相对场景过小时远处物体如天空盒后的大地形会整体变灰过大时雾效又几乎不可见。三、全部属性说明Fog实例包含五个公开属性其中四个在构造时初始化一个是只读的类型标记.color : Color雾的颜色。源码中直接映射构造函数入参this.color new Color( color )Fog.js。雾色通常与scene.background取一致或相近值这样被雾完全覆盖的远处物体能够与背景无缝衔接视觉上不会出现明显的物体剪影断层。.near : number开始施加雾的最小距离。距离活跃相机小于near的物体完全不受雾影响等于说它划定了清晰区的边界。默认1。.far : number雾停止计算与施加的最大距离。距离活跃相机大于far的物体不再受雾影响——注意这里原文的准确表述是“objects … wont be affected by fog”更严谨的理解是在far距离上雾因子已达到 1100% 雾色更远处的像素在混合时同样以纯雾色呈现。默认1000。.isFog : boolean只读类型标记恒为trueFog.js。three.js 中大量类都带有这类isXxx标志用于在运行时做鸭子类型判断例如区分Fog与FogExp2见第四节从而避免依赖instanceof与模块引用耦合。.name : string雾的名称便于调试或序列化后定位默认空字符串Fog.js。四、方法与 JSON 序列化.clone() : Fog返回一个拷贝当前值的新实例。实现非常直观Fog.jsclone() { return new Fog( this.color, this.near, this.far ); }注意它把color实例直接传给新对象而构造函数内部会再次执行new Color(color)因此新旧两个雾对象的颜色是各自独立的 Color 实例后续修改任一方的颜色分量不会污染另一方。与之配套Scene.copy()在克隆场景时也会复制雾Scene.jsif ( source.fog ! null ) this.fog source.fog.clone();这意味着通过scene.copy(otherScene)复用整套场景配置时雾效会被一并带过来无需手动重建。.toJSON( meta : Object | string ) : Object将雾序列化为 JSON 对象。从源码看Fog.js无论是否传入meta序列化结果都包含五个固定字段toJSON( /* meta */ ) { return { type: Fog, name: this.name, color: this.color.getHex(), near: this.near, far: this.far }; }即输出形如{ type: Fog, name: , color: 13421772, near: 10, far: 15 }要点color通过getHex()输出为十进制整数0xcccccc即 13421772与 ObjectLoader 的反序列化格式对应。type: Fog是反序列化时选择构造哪个类的依据Fog与FogExp2的 type 字段不同。meta参数在当前实现中被注释忽略源码写作toJSON( /* meta */ )为将来保留扩展位。当整个场景被序列化时雾会随场景一起落盘——Scene.js 中if ( this.fog ! null ) data.object.fog this.fog.toJSON();因此保存/加载场景文件时雾效配置可以无缝往返无需手工二次处理。五、线性雾 vs 指数雾 FogExp2如何选型雾还有另一实现FogExp2指数平方雾官方文档独立成篇见 FogExp2.html.md源码在 FogExp2.js。两者的差异决定了使用场景维度Fog线性雾FogExp2指数平方雾控制参数nearfar两个距离区间单一density默认0.00025浓度变化随距离线性增密近处清晰、远处快于指数地增密数学模型在[near, far]区间线性插值1 - exp( -density² · depth² )类曲线典型用途界限分明的可见范围控制大气透视、烟霭等自然效果类型标记isFog trueisFogExp2 true两者的关键区别也体现在类型标记上渲染器正是靠fog.isFogExp2这一标志来决定走哪套雾计算见下节这也是.isFog这类只读标记存在的实际意义——FogExp2.js 中isFogExp2 true而线性雾只有isFog true。选型建议当你需要某个精确距离内绝对清晰、某个精确距离后完全隐没的硬性可视范围控制例如视距裁剪式的场景雾化选Fog当你需要更自然的空气透视、无需关心精确截止距离时FogExp2往往效果更柔和。六、渲染器视角Fog 在管线中如何真正生效理解了 API 之后再看源码里雾是如何算出来的能帮你把握near/far的真实语义。1. 场景雾 - 程序参数WebGL 后端在生成着色程序前会读取物体所在场景的雾并产出三个开关/常量见 WebGLPrograms.jsfog: !! fog, useFog: material.fog true, fogExp2: ( !! fog fog.isFogExp2 ),由此可以确认雾的存在性是**逐场景scene.fog**判定的是否套用雾还受材质开关material.fog二次控制默认true。也就是说即使场景挂了雾只要把某个材质的fog设为false该材质绘制的物体就能穿雾而不受影响——这是做特殊物体如 UI 面板、不受雾影响的发光体的常用手段。2. 着色器中的线性雾公式WebGL 后端的雾相关逻辑封装在 src/renderers/shaders/ShaderChunk 目录的fog_pars_vertex.glsl.js、fog_vertex.glsl.js、fog_pars_fragment.glsl.js、fog_fragment.glsl.js四个 chunk 中并以#ifdef USE_FOG条件编译。顶点阶段根据视图空间深度输出雾深度片元阶段则依据当前材质编译时的雾类型走不同公式。从该类文档与实现约定可以推断线性雾在片元着色器中通过smoothstep( fogNear, fogFar, fogDepth )计算雾因子指数雾则走FOG_EXP2分支最后用gl_FragColor.rgb mix( gl_FragColor.rgb, fogColor, fogFactor );把片元颜色向雾色过渡。这正是near/far语义的底层来源fogFactor在near处为 0、far处为 1两点之间线性增长。理解这一点有助于解释一些现象——例如物体在near之后开始发灰、到far处完全变成雾色且过渡是平滑阶梯式的与 shader 中 smoothstep 的缓动特性一致。3. 面向 WebGPU 的新后端在面向 WebGPU 的通用节点渲染后端中雾同样作为场景状态被纳入节点管理NodeManager.js 中可检索到对Fog/FogExp2的处理分支配合 TSLThree Shading Language以节点方式构建雾逻辑说明雾效在 WebGL 与 WebGPU 两条后端路径上都得到了一等支持。七、常见坑与调参建议雾色与背景不一致导致剪影far之后物体被完全混成雾色若scene.background颜色与fog.color不同地平线附近会出现物体轮廓与背景之间的色差建议两者取同一颜色。near/far相对相机而非场景原点距离以活跃相机为基准计算相机移动时同一物体会随距离变化而进出雾区这通常是期望行为雾跟着镜头走。想局部豁免雾把该物体所有材质的.fog false。单位尺度不匹配three.js 不强制单位1 单位可以是 1 米也可表示任意比例因此默认near1, far1000只适合场景尺度恰在千单位量级的情况室内小场景请相应缩小far。线性雾与指数雾不要叠加滥用scene.fog同一时刻只能挂一个雾实例二选一即可。八、延伸阅读与验证路径围绕Fog的完整证据链分布在仓库以下位置可继续深入官方 API 文档Fog.html.md本文主体指数雾文档 FogExp2.html.md源码实现Fog.js、FogExp2.js场景集成Scene.jsfog属性、copy()复制雾、场景序列化输出雾渲染开关WebGLPrograms.jsfog/useFog/fogExp2标志着色器实现src/renderers/shaders/ShaderChunk 下的fog_*.glsl.js系列单元测试Fog.tests.js、FogExp2.tests.js综上THREE.Fog虽只是一个存着颜色与两个距离值的对象但通过scene.fog挂载、材质fog开关、渲染器条件编译与 TSL/WebGL 双后端支撑构成了 three.js 距离雾效体系中精确可控的一极。掌握它的参数语义与底层过渡公式就能在需要线性可视范围控制的场景中准确预测每一个物体的雾化程度。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考