环境色与氛围感:从CSS到Three.js的实战指南

发布时间:2026/8/26 22:58:11
环境色与氛围感:从CSS到Three.js的实战指南 在实际开发里环境色并不是一个开关开了就有氛围、关了就没有。更常见的情况是一位前端或视觉同学改了一版页面在聊天里问“我尝试加入了一些环境色不知道能不能体现氛围感”然后丢出一张截图。截图里也许有渐变、有阴影、有发光物体但问题往往不是颜色加得不够而是环境色加在了哪一层、强度多少、和主光的比例是否合适以及暗部是否仍然保持通透。这篇内容从“环境色”这个概念入手先用 CSS 做一个二维页面环境色示例再用 Three.js 做一个三维场景环境光示例把环境色的取值、混合、参数调节和验收方法讲清楚。学完后你可以在自己的页面或 Three.js 项目里快速复现并根据环境光强度、方向、颜色和色调映射做出一眼就能看出氛围感的效果。1. 先从渲染原理理解环境色为什么能带来氛围感1.1 环境色来自周围环境不是灯光自身的颜色环境色最简单的理解是一个物体摆在不同颜色的房间里它的暗部会被周围物体的反射光染色。太阳光本身是白色如果房间墙面是蓝色那么白色物体的阴影里会带着一点蓝如果地面是木地板物体底部又会带着一点暖黄。这个来自周围环境、而不是直接来自光源的颜色就是环境色。在三维渲染里环境色通常由三类手段模拟环境光Ambient Light给整个场景加一个均匀的基础亮度。半球光Hemisphere Light把环境分成天空方向颜色和地面方向颜色比均匀环境光更有立体感。环境贴图Environment Map / IBL用一张全景图记录周围环境的光线PBR 材质的反射和高光会从这张图里取色。很多初学时容易把“环境色”和“背景色”混在一起。背景色只是镜头能看到的远处颜色它不一定会影响物体。环境色必须参与到光照计算里才会改变物体暗部、反射和高光的颜色。这也是为什么在 Three.js 里只设置scene.background时物体看起来不会变还会感觉画面很空。1.2 氛围感的关键是暗部颜色不是亮部颜色人的视觉对画面氛围的判断很大程度上来自阴影和暗部。一个场景如果暗部是纯黑亮部再鲜艳看起来也会生硬反过来如果暗部带一点冷蓝或暖黄空间感马上会出来。这就是环境色最容易出效果的位置。举一个具体例子同一个白色陶瓷杯放在傍晚的蓝灰房间和暖黄灯光房间里材质的高光可能差不多但杯子的暗部颜色完全不同。前者偏冷、安静后者偏暖、温馨。想看一个页面有没有氛围感不要盯着最亮的地方而是要看物体和背景交界的阴影区域环境色调是否正确。从渲染公式角度看一个常规漫反射表面可以简化成最终颜色 固有色 × (主光贡献 环境光贡献)主光决定物体的明暗对比和立体感环境光决定暗部脱离纯黑之后呈现的色彩倾向。如果环境光贡献是零暗部就会被压成接近黑色不管亮部多好看氛围感都很难成立。1.3 环境色不是越亮越好能量守恒和反射比例很多人在第一次加入环境色时会犯同一个错误为了让氛围更明显把环境光强度调得很高。结果整个物体亮得像被洗过主光的投影也不见了。这是因为环境光的本质是“环境多次反射后的间接光”它的亮度理论上不应该超过直接光的贡献。否则就会出现物理上不合理的发光感。在 Three.js 中常用两组参数配合HemisphereLight的 intensity 控制环境光总量。DirectionalLight或SpotLight的 intensity 控制主光强度。renderer.toneMappingExposure控制最终输出的曝光。推荐的做法是先确定主光再慢慢加环境光。比如主光强度为 2半球光强度可以从 0.2 开始往上试不要一次拉到 2。光照单位在不同渲染器里不一致关键是看画面中暗部的比例和主光投影是否还清晰。主光负责立体感环境色负责情绪。环境色强度过高时立体感会被削弱环境色强度过低时情绪表达会缺失。需要找到两者平衡点。1.4 用半球光模型理解环境色的两个颜色方向半球光在工程实现上非常直观它假设场景上空有一个天空颜色脚下有一个地面颜色物体表面会根据法线方向在两者之间插值取色。比如一个球体上半部分偏天空色下半部分偏地面色中间过渡自然。这个模型很适合做氛围感调试因为它给了两个可控颜色参数含义氛围感影响天空颜色来自上方环境光的颜色决定物体上半部暗部和反射色地面颜色来自下方环境光的颜色决定物体底部和接触阴影的颜色强度环境光总量决定暗部脱离纯黑的程度主光强度直接光强度决定立体感和投影清晰度曝光最终亮度输出决定整体明暗和氛围倾向例如想做一个“深夜蓝色氛围”的场景天空色可以选#1b2a4a地面色选#101820强度给 0.4。这样物体暗部偏蓝但又不会发灰。想做一个“黄昏暖调”场景天空色可以选#ffb47a地面色选#2d1b13强度给 0.5物体轮廓会带上暖光和深色落地感。2. 环境准备与项目结构搭一个可调参的示例页面2.1 技术选型与版本说明为了把环境色讲具体我选择用原生 HTML/CSS/JS 加 Three.js 0.160.0 做演示。这个组合不需要构建工具打开浏览器就能运行适合学习阶段快速验证。实际项目如果使用 Vue、React 或不同 Three.js 版本核心思路不变只是文件引入方式和 import 路径要调整。下面所有代码只用于说明实现思路落地前要确认自己项目里的 Three.js 版本、依赖路径和浏览器兼容范围。版本号是示例不建议在未测试的情况下直接锁死生产版本。目录结构如下environment-color-demo/ ├── index.html ├── style.css └── scene.js如果后面要加载本地模型或纹理再加一个assets/目录。这里不涉及本地资源保持三个文件足够。2.2 本地运行方式可以直接双击index.html运行吗在只使用 CDN 脚本且不加载本地资源时大多数浏览器可以打开。但 Three.js 使用 ES Module 加载部分浏览器会要求安全的上下文或 MIME 类型所以推荐本地起一个静态服务器。在项目目录下任选一种方式# Python 3 python -m http.server 8080 # Node.js需要先安装 serve npx serve -l 8080 .然后访问http://localhost:8080。如果页面空白打开开发者工具的 Console优先看是否有模块加载失败或跨域报错。2.3 环境检查清单在开始写代码前建议先检查以下项目检查项学习环境生产环境浏览器 WebGL 支持Chrome / Edge / Firefox 最新版需要做机型矩阵和降级方案本地服务器python -m http.server即可Nginx / CDN / 静态资源部署Three.js 引入直接使用 CDN 方便建议下载到本地或通过包管理锁定版本颜色管理使用 sRGB 输出即可需要统一颜色空间和显示器校准调试工具浏览器 Console 加 React DevTools 可选需要日志、监控和性能分析这个清单看起来基础但很多环境色排错问题出在环境准备上。比如 CDN 无法访问或者静态资源服务器 MIME 类型不对会导致 Three.js 模块加载失败现象和代码报错一样很容易误导排查方向。3. 核心实现给页面和三维场景加入环境色3.1 先写一个 CSS 环境色示例用渐变和阴影建立颜色场在二维页面里环境色的表达方式和三维渲染不同但原理类似。用一个半透明渐变背景模拟周围环境光让卡片边缘和底部阴影带上环境色页面就会有“物体处于某个颜色环境中”的暗示。下面是index.html的基础结构!DOCTYPE html html langzh-CN head meta charsetUTF-8 / meta nameviewport contentwidthdevice-width, initial-scale1.0 / title环境色氛围感示例/title link relstylesheet href./style.css / /head body main classstage div classcard h2环境色卡片/h2 p背景渐变和卡片阴影都带有环境色倾向。/p /div /main /body /htmlstyle.css里加入环境色:root { --env-sky: rgba(78, 150, 255, 0.35); --env-ground: rgba(255, 100, 120, 0.18); } body { margin: 0; min-height: 100vh; background: radial-gradient(circle at 20% 30%, var(--env-sky), transparent 60%), radial-gradient(circle at 80% 80%, var(--env-ground), transparent 60%), #0f1118; display: flex; align-items: center; justify-content: center; } .card { max-width: 360px; padding: 32px; border-radius: 20px; background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.12); box-shadow: 0 30px 80px rgba(60, 120, 255, 0.25), 0 10px 30px rgba(0, 0, 0, 0.4); color: #f0f2f8; }这个示例里radial-gradient模拟了环境色从左上和右下两个方向照入画面box-shadow的冷蓝色则模拟近处反射光。卡片本身的背景保持半透明环境色就会透过卡片边缘形成氛围。关键点在于不要让卡片本身变成大面积蓝色而是让颜色出现在背景和阴影里。真实环境中物体固有颜色的改变主要发生在暗部、边缘和反射区域。整块物体直接刷成蓝色看起来像变色不像受环境色影响。3.2 在 Three.js 里加入主光、半球光和环境背景三维渲染请把style.css的卡片效果先放一边新建index.html的 Three.js 版本!DOCTYPE html html langzh-CN head meta charsetUTF-8 / meta nameviewport contentwidthdevice-width, initial-scale1.0 / titleThree.js 环境色示例/title style body { margin: 0; overflow: hidden; background: #0b0d14; } #controls { position: fixed; top: 16px; right: 16px; width: 260px; padding: 16px; border-radius: 12px; background: rgba(0, 0, 0, 0.7); color: #fff; font-size: 14px; z-index: 10; } #controls label { display: block; margin: 8px 0 4px; } #controls input { width: 100%; } /style /head body div idcontrols label天空颜色/label input typecolor idskyColor value#7ea8ff / label地面颜色/label input typecolor idgroundColor value#3d3440 / label半球光强度 span idhemiValue0.6/span/label input typerange idhemiIntensity min0 max2 step0.05 value0.6 / label曝光 span idexposureValue1.0/span/label input typerange idexposure min0.3 max2 step0.05 value1.0 / /div script typeimportmap { imports: { three: https://unpkg.com/three0.160.0/build/three.module.js, three/addons/: https://unpkg.com/three0.160.0/examples/jsm/ } } /script script typemodule src./scene.js/script /body /html然后创建scene.jsimport * as THREE from three; import { OrbitControls } from three/addons/controls/OrbitControls.js; const scene new THREE.Scene(); scene.background new THREE.Color(0x0b0d14); const camera new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 100 ); camera.position.set(3, 2, 5); camera.lookAt(0, 0, 0); const renderer new THREE.WebGLRenderer({ antialias: true }); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.toneMapping THREE.ACESFilmicToneMapping; renderer.toneMappingExposure 1.0; renderer.outputColorSpace THREE.SRGBColorSpace; document.body.appendChild(renderer.domElement); const controls new OrbitControls(camera, renderer.domElement); controls.enableDamping true; const torusKnot new THREE.Mesh( new THREE.TorusKnotGeometry(0.8, 0.25, 128, 16), new THREE.MeshStandardMaterial({ color: 0xd8d8d8, roughness: 0.4, metalness: 0.1, }) ); scene.add(torusKnot); const hemiLight new THREE.HemisphereLight( 0x7ea8ff, 0x3d3440, 0.6 ); scene.add(hemiLight); const dirLight new THREE.DirectionalLight(0xffffff, 2.2); dirLight.position.set(2, 3, 4); scene.add(dirLight); const skyColorInput document.getElementById(skyColor); const groundColorInput document.getElementById(groundColor); const hemiIntensityInput document.getElementById(hemiIntensity); const hemiValue document.getElementById(hemiValue); const exposureInput document.getElementById(exposure); const exposureValue document.getElementById(exposureValue); skyColorInput.addEventListener(input, () { hemiLight.color.set(skyColorInput.value); }); groundColorInput.addEventListener(input, () { hemiLight.groundColor.set(groundColorInput.value); }); hemiIntensityInput.addEventListener(input, () { hemiLight.intensity Number(hemiIntensityInput.value); hemiValue.textContent hemiLight.intensity.toFixed(2); }); exposureInput.addEventListener(input, () { renderer.toneMappingExposure Number(exposureInput.value); exposureValue.textContent renderer.toneMappingExposure.toFixed(2); }); window.addEventListener(resize, () { camera.aspect window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); function animate() { requestAnimationFrame(animate); torusKnot.rotation.y 0.005; torusKnot.rotation.x 0.001; controls.update(); renderer.render(scene, camera); } animate();控制面板是这套示例里最值得保留的部分。HemisphereLight的两个颜色都做了可调节项这样你不用改代码刷新页面就能直接观察不同环境色对氛围的影响。很多时候“不知道能不能体现氛围感”是因为没有对比而不是颜色不对。把参数暴露到运行时本身就是最好的验证方式。3.3 关键参数颜色、强度、曝光和色调映射上面代码里其实涉及四层参数每一层都会影响最终氛围感参数示例值作用过高表现过低表现HemisphereLight天空颜色#7ea8ff物体上半部环境色画面变蓝、发闷上半部偏黑HemisphereLight地面颜色#3d3440物体底部和落地阴影底部变脏底部死黑HemisphereLight.intensity0.6环境光总量画面发灰、投影变弱氛围感消失DirectionalLight.intensity2.2主光亮度过曝、亮部刺眼轮廓不清晰renderer.toneMappingExposure1.0最终曝光亮部溢出整体偏暗ACESFilmicToneMapping会把高光压下来暗部提亮一点比默认线性输出更适合看氛围。如果渲染器没有做颜色空间管理环境色看起来会偏灰或偏脏。这里需要特别注意HemisphereLight的强度单位。Three.js 的HemisphereLight强度不完全是物理辐射度量更多是调色用的比例值。所以不要死记“0.6 是标准值”要根据自己的模型、材质粗糙度、主光强度和屏幕亮度去试。实际项目中环境色参数建议放到一个对象里集中管理const envParams { skyColor: 0x7ea8ff, groundColor: 0x3d3440, hemiIntensity: 0.6, exposure: 1.0, background: 0x0b0d14, };后续可以很自然地把这个对象序列化到 JSON 或 URL 参数里方便设计师在不同配色方案间切换。3.4 进阶用环境贴图替代单色半球光半球光适合快速验证氛围但它只能提供两个方向色无法表达复杂环境反射。想要更真实的 PBR 反射需要在scene.environment里放一张环境贴图。Three.js 官方的示例经常使用RoomEnvironment来生成室内环境。用法如下import { RoomEnvironment } from three/addons/environments/RoomEnvironment.js; // 注意这段代码需要在 renderer 创建之后执行 const pmremGenerator new THREE.PMREMGenerator(renderer); scene.environment pmremGenerator.fromScene(new RoomEnvironment()).texture;环境贴图会直接影响 MeshStandardMaterial、MeshPhysicalMaterial 的漫反射和高光反射出现比较明显的“物体被周围环境照亮”的效果。单色半球光更像老式动画的打光方式环境贴图更像真实拍摄环境。如果不想引入 RoomEnvironment也可以把环境光颜色写到scene.environment对应的贴图里但普通单色贴图很难体现空间感实际价值不如半球光。对环境要求不高的小场景推荐先用半球光等需要做镜面反射或高光细节时再切环境贴图。4. 运行验证怎么判断环境色是否真的带来了氛围感4.1 用同一角度开关对比氛围感不是靠感觉判断的要用控制变量法。先把半球光强度调到 0截一张图记录主光和颜色分布。再把强度调到 0.4 或 0.6截第二张图。最后把曝光拉到 1.2 或 0.8 各截一张。同一个角度、同一个模型前后的差异会非常明显。对比时可以问自己三个问题暗部是不是还保留颜色倾向而不是变成纯黑物体轮廓和背景之间有没有出现明显的色块分离主光投影是否仍然存在有没有被环境光冲淡如果三个问题都成立那环境色已经发挥作用。如果只有一个成立比如暗部偏蓝天但是投影消失说明环境光强度过高需要回调。推荐的对比流程1. 固定相机位置和模型姿态。 2. 将环境光强度设为 0保存 baseline 图。 3. 依次调整环境光强度 0.2、0.4、0.6、0.8。 4. 每一步都保存截图。 5. 将多张图并排看不依赖滚动切换。这一步比任何理论都有效。很多“不知道能不能体现氛围感”的问题都是因为没有把环境光为 0 和不为 0 的结果放在一起看。4.2 用取色器检查暗部是不是发灰肉眼判断容易被屏幕亮度骗过可以用取色器读取物体暗部区域的 RGB 值。取色目标是模型受光面不与主光直接照射的地方比如球体的底部、圆环结背后的阴影。如果 RGB 三个通道数值接近比如#8a8a8a说明环境色没有明显色倾向氛围感会比较弱。如果三个通道有明显差值比如#6f7ca8说明环境色倾向于蓝紫氛围感成立。范围没有绝对标准因为不同设计风格差异很大。但有一个通用判断原则如果暗部发灰通常是环境色饱和度过低如果暗部发脏通常是地面色过暗、过饱和或者色调映射没处理好。想要透亮的环境色可以让暗部颜色保持一定亮度比如 RGB 最低通道不要小于 30最高通道不要超过 200 左右。太亮的暗部会让画面显得没有阴影太暗的暗部会失去氛围。4.3 把“氛围感”拆成可验证维度氛围感可以拆成三个可验证维度而不是一句模糊的判断维度判断方法参数关键词色相倾向暗部 RGB 是否与环境色方向一致天空色、地面色、环境贴图主色明暗层次物体从亮面到暗面是否有清晰过渡半球光强度、主光强度空间融合物体边缘与背景是否有自然过渡背景色、曝光、环境贴图强度实际落地时可以做一个更细致的验收清单环境光关闭时暗部是否接近纯黑。环境光打开后暗部是否出现预设色相。主光投影是否仍能被辨认。背景和物体的明暗关系是否协调。在高光和反射区域是否出现不合理的颜色溢出。在普通屏幕和深色模式下是否都能接受。有了这个清单就不会只凭“看起来还不错”来评审效果。4.4 快速效果对比表以下是一组常见调整方向供做参数实验时参考现象判断调整建议暗部死黑环境光贡献不足提高半球光强度或提高地面色亮度画面发灰环境光过强或主光不足降低半球光强度或提高主光强度投影不见环境光比例太高降低半球光强度到 0.2-0.4暗部带脏色地面色过暗过饱和选择低饱和、中等亮度的地面色白墙变蓝环境色溢出过强降低环境光强度、降低曝光或减少环境贴图强度亮部过曝曝光或主光过强降低 exposure 或 DirectionalLight.intensity这套表可以打印成速查表在之后不同项目中复用。环境色调试的本质就是不断在这些参数之间做权衡。5. 常见问题排查环境色加了之后发灰、发脏、过曝怎么办5.1 问题画面整体发灰物体没有立体感现象模型表面亮部和暗部区分不大连主光的投影都看不出来。可能原因有两个半球光强度太高或者曝光值偏高。排查时先不要动材质直接把hemiIntensity降到 0。如果画面立刻恢复立体感说明环境光比例太高。检查方式// 临时把环境光强度降到最低 hemiLight.intensity 0; renderer.render(scene, camera);如果降到 0 后画面变暗太多说明主光也偏低。正确做法是保持主光强度不变把环境光强度控制在 0.3 到 0.6 之间再通过曝光调节整体亮度。不要用环境光来充当补光环境光负责色温倾向立体感应该交给主光。5.2 问题暗部颜色“脏”而不是“透”现象阴影区域带一种说不清的灰褐色看起来像脏污。这种问题通常出在环境色取值上。很多同学为了表现“暗部”直接把地面色选成纯黑或者很暗的棕色。纯黑地面色会让底部暗部失去环境色倾向脏就是从这里来的。检查方式把打印出来或用取色器读取物体的暗部 RGB看它是否落在低饱和、低亮度的灰褐色区间。如果是需要调整地面色。推荐做法地面色不选纯黑选一个带有冷色或暖色倾向的深灰色。例如场景天空色地面色冷色氛围#bfd1ff#2d3546中性氛围#e8e8f0#3a3a3f暖色氛围#ffd9a0#332417这些值看起来饱和度不高但在暗部表现出来后会形成比较干净的色偏。避免使用#000000和#1a0000这类没有呼吸感的颜色。5.3 问题白墙或浅色材质被环境色染得过于明显现象模型本身是白色加入蓝色环境色后整个物体看起来都偏蓝亮部也带着明显蓝色。物理上环境色确实会影响白色物体但如果亮部也被环境色主导说明环境光强度太高或者颜色溢出严重。解决方案按顺序尝试降低hemiLight.intensity。降低renderer.toneMappingExposure。调整MeshStandardMaterial的roughness粗糙度越高环境色越容易均匀扩散。如果使用了环境贴图请降低环境贴图强度或选择更均匀的贴图。需要注意的是白色物体本身在环境色场景中应该出现色偏这是正常物理现象不用完全避免。关键是要控制色偏只出现在暗部和反射区而不是整块变成环境色的纯色。5.4 问题CSS 页面里文本被环境光晕干扰可读性下降二维页面中加入环境色的最大问题是背景渐变和 box-shadow 会干扰前景文本阅读。这时不要把环境色直接加到文字层的父容器上而是把环境色放到背景层再在文字下方加一层半透明遮罩。推荐结构.stage::before { content: ; position: absolute; inset: 0; background: radial-gradient(circle at 20% 30%, rgba(78, 150, 255, 0.35), transparent 60%), radial-gradient(circle at 80% 80%, rgba(255, 100, 120, 0.18), transparent 60%); z-index: 0; } .text-layer { position: relative; z-index: 1; backdrop-filter: blur(8px); background: rgba(0, 0, 0, 0.35); padding: 24px; border-radius: 16px; }这样环境色仍然在文字区域又有足够的对比度不会变成一张只有氛围看不清楚内容的页面。记住氛围感不能牺牲信息尤其在产品展示页中文本可读性优先级更高。5.5 问题Three.js 场景加载后画面全黑或报错现象页面只有一个纯色背景模型看不到。可能原因主要有四类相机视野不对、光源没加、Three.js 版本加载失败、模型材质和渲染器颜色空间不匹配。排查顺序建议打开浏览器 Console看有没有脚本加载错误。把scene.background设置成亮色确认渲染器正常工作。临时关闭toneMapping看模型是否出现。确认camera.lookAt(0,0,0)是否执行模型是否在相机视野内。确认光源已经scene.add并且类型和参数没有误设。网上很多“环境色加不进去”的问题最终都发现是光源没有加或者材质是全黑的。建议先把最简单的白色平板加一盏白灯跑通再逐步加入环境色这样排查范围会小很多。6. 生产环境建议把环境色从参数实验变成可维护的能力6.1 把环境色参数外置不要写死在代码里在示例 demo 里环境色直接写在scene.js中方便演示。但是生产项目里页面或场景可能有不同主题、不同活动、不同视觉规范写死颜色会导致每次上线都要找前端改代码。推荐做法是把环境色参数集中到一个配置对象或 JSON 文件里{ skyColor: #7ea8ff, groundColor: #3d3440, hemiIntensity: 0.6, dirLightColor: #ffffff, dirLightIntensity: 2.2, exposure: 1.0, background: #0b0d14 }前端启动时读取配置并把它应用到渲染器。这样可以做到设计同学调参数、前端同学只负责逻辑甚至可以通过管理后台刷新配置不需要发版。使用时注意 JSON 里的颜色应该统一使用 HEX 或带明确的 sRGB 转换避免不同环境显示不一致。6.2 建立氛围感验收清单生产环境不允许“我觉得好看就行”。在做环境色相关需求时可以建立这样一份验收清单环境光关闭和打开时暗部有明显色相变化但不破坏物体立体感。主光投影在环境光打开后仍可识别。暗部最低亮度不低于 30 左右且暗部不是死灰。白色物体整体没有超出设计预期的色偏。页面文本在小字号、低对比度背景下仍可读。移动端低性能设备下环境贴图或 CSS 渐变没有明显掉帧。不同屏幕的显示效果差异在可接受范围内。这份清单可以在每次环境色调优前打印出来逐项打勾。它比“再调亮一点”更管用因为它把模糊的感觉变成了具体判断。6.3 性能注意事项环境色在 CSS 和 Three.js 里都会消耗性能。CSS 中使用多层 radial-gradient 会产生较大的绘制面积移动端上如果动画帧率掉到 30fps 以下说明渐变层过多或阴影过大。Three.js 中使用环境贴图会显著增加显存占用尤其是 2K、4K 的全景纹理。推荐做法CSS 环境色优先用 2-3 层渐变不要用 8 层。阴影不使用超大模糊半径尽量用带透明度的色块或小尺寸阴影模拟。Three.js 环境贴图尺寸控制在 1024 或以下。低端设备或低电量模式可以通过配置关闭动态环境贴图刷新。环境色参数不要每帧更新只在用户交互或配置变化时更新。环境色是观感较强的视觉手段但如果拖慢性能最后只能被迫关闭反而浪费一轮适配成本。6.4 从环境色走向完整光照模型如果你已经能把环境色调出氛围感下一步可以向更完整的光照和材质方向扩展IBL基于图像的光照从环境贴图计算物体反射和漫反射。实时全局光照如 Light Probe、Reflection Probe 在场景中采集周围光照。后期处理Bloom、颜色分级、暗角这些效果会进一步强化氛围感。相机曝光动态曝光可以模拟人眼从暗环境到亮环境的适应过程。不过这些扩展依赖较重的技术栈学习时不要一步到位。先把半球光、环境贴图、曝光这三个概念玩熟已经能解决多数页面和三维场景的氛围问题。回到最开始的问题加入环境色能不能体现氛围感判断标准不在于一开始就看出“氛围好或不好”而在于你是否能控制环境色的强度、颜色和影响范围。能控制氛围感就是可调出来的不能控制再加颜色也只是碰运气。把参数暴露出来、把暗部取色检查当作常规动作你就不会再用“不知道能不能体现氛围感”这种提问方式去面对审查了。