1. 先把天空盒在项目里的真实角色搞清楚
很多人第一次接触 Unity 天空盒,都是被“背景太丑”这个需求推着走的:场景摆完,摄像机里一片灰蓝,随手找一张全景图往材质上一挂,背景好看了,事情就算结束。但只要项目稍微往前走一步——角色需要金属反射、场景需要环境光、策划要求白天切到黄昏——你就会发现天空盒远不只是块背景板。它同时是用 Unity 天空盒(SkyBox)参与环境光照计算、反射探针烘焙、后处理曝光平衡的一整套环境数据入口,改一个参数,画面里所有材质的质感都会跟着变。
这篇内容面向的是已经能打开编辑器、能拖物体、但对渲染管线一知半解的同学,也适合做了几个小 Demo 却说不清“为什么我的金属球是黑的”的开发者。我会从素材准备、材质创建、Lighting 设置、反射与环境光、运行时动态切换、性能预算,一路讲到我自己踩过的那些坑。所有步骤都能直接照着复现,参数会给出具体数值和计算依据,不做“差不多就行”的糊弄。看完你应该能做到:拿到任何形态的天空盒素材都能正确导入,知道每个参数动一下会发生什么,并且能解释清楚为什么金属材质突然有了细节。
有一个认知要先立起来:在 Unity 里,天空盒是一个材质(Material),而不是一个场景物体。它通过RenderSettings.skybox这个全局引用被渲染系统读取,同时被 Lighting 窗口当作环境光和高光反射的数据源。这意味着两件事,第一,它不跟着场景物体走,切换场景时默认是全局共享的;第二,改它的时候你改的是“整个世界的光照环境”,而不是某面墙的颜色。理解了这一点,后面所有的配置逻辑就顺了。
1.1 它不只是背景,而是环境光与反射的数据源
Unity 的默认光照模型里,物体受光来自三部分:直接光照、环境光(Ambient)、反射(Specular 的间接部分)。天空盒同时供给了后两者。Lighting 窗口把 Environment Lighting 的 Source 设成 Skybox 时,引擎会从天空盒的六个面采样并做球谐压缩(SH),生成一组低频的环境光数据,这就是为什么你把天空盒从阴天换成晴天,场景里背光的角落会整体变亮。
环境反射同理。PBR 材质的高光颜色其实是从一张预先卷积过的立方体贴图里采样出来的,而这张图的源头就是天空盒。所以你给金属球一个纯黑天空盒,它立刻变成一颗死气沉沉的煤球;换成带云层和亮斑的天空盒,球面马上出现层次。这个因果关系一定要建立起来,否则你会一直在材质面板里瞎调 roughness 却找不到原因。
顺带说一个容易被忽视的点:天空盒的亮度直接参与后处理曝光的计算。自动曝光(Auto Exposure)会根据画面平均亮度调整整体明暗,天空盒占了屏幕一大半面积,它亮一档,整个场景就暗一档。如果你发现调完天空盒后模型突然发灰,先别怀疑材质,去看看曝光设置。
1.2 四种素材形态怎么选,先想清楚再动手
Unity 支持的天空盒形态大概有四类,选择哪一类决定了你后面所有的导入流程。我按实际项目里的使用频率排一下。
| 形态 | 所需素材 | 优点 | 代价 | 适用场景 |
|---|---|---|---|---|
| 六面图(6 Sided) | 6 张正方形贴图 | 可控性最强,可单独替换某一面 | 素材制作麻烦,接缝需处理 | 有美术产出、要求高质量固定天空 |
| Cubemap 资源 | 一张 Cube 型纹理 | 导入即用,支持卷积与接缝修复 | 编辑期不便单独改某面 | 主流选择,绝大多数项目 |
| 全景图(Panoramic) | 一张 2:1 等距柱状图 | 素材最容易获取,一张图搞定 | 采样有极点畸变,两侧接缝 | 快速原型、写实照片背景 |
| 程序化(Procedural) | 无,纯参数 | 零素材,可实时调太阳方位 | 风格化明显,不适合写实 | 白盒阶段、风格化项目 |
选型的判断标准其实就一条:你的素材从哪来。如果是从全景相机拍的或者网上找的 360 度图,用 Panoramic;如果美术给的是一套六面渲染图,用 6 Sided;如果只有一个已经打包好的 cubemap 文件,用 Cubemap。程序化天空盒我会在第三节单独说,它在白盒阶段是真的好用。
2. 素材准备:规格、命名与导入设置
素材这一关是最容易出问题的地方,因为大部分教程只告诉你“拖进去”,不告诉你为什么拖进去之后天空盒颜色不对、边缘有黑线、旋转 90 度。这一节把这些细节拆开讲。
2.1 六面图的命名规则与尺寸预算
六面图最大的坑在命名。Unity 在导入 Cubemap 时有一套自动识别规则,靠文件名后缀判断哪张图对应哪个方向,常见约定是_PX、_NX、_PY、_NY、_PZ、_NZ,分别对应 +X、-X、+Y、-Y、+Z、-Z 六个方向。如果你直接按“前、后、左、右、上、下”命名,导入面板里的 Mapping 自动识别会失败,只能手动一张张往槽位里拖,六张图拖错两张的概率相当高。
我个人的习惯是:在素材目录里就把文件改成SkyName_PX.png这样的形式,导入时 Texture Shape 选 Cube,Mapping 选 Auto,让引擎自己认。认不出来的时候不要硬拖,退回去检查命名,通常就是后缀不匹配或者某张图尺寸不一致。
尺寸方面,六面图必须是正方形,且六张尺寸一致。常见规格是每面 1024 或 2048。这里有个显存预算要算清楚,以 2048 为例:
- 未压缩 RGBA32:2048 × 2048 × 4 字节 × 6 面 ≈96 MB
- 开启 Mipmap 后还要乘约 1.33,接近128 MB
- 压缩为 BC1(0.5 字节/像素,约 4bpp):2048 × 2048 × 0.5 × 6 ≈12 MB
- HDR 格式 BC6H(8bpp,1 字节/像素):约24 MB
结论很直白:天空盒必须压缩。一个不压缩的 2K 六面天空盒能吃掉一百多兆显存,在移动端是灾难级的。桌面端用 BC1(有损、8 位)或 BC6H(HDR),移动端用 ETC2 或 ASTC,具体看平台支持。
2.2 Cubemap 导入面板逐项过一遍
把一张 Cube 型纹理选中,Inspector 里有一堆选项,我只挑真正影响画面的说。
Texture Shape必须是 Cube,这是前提。Mapping决定引擎如何把一张平面图切成六面,Auto 依赖命名,其余选项(Cross 十字布局、Latitude-Longitude、Mirrored Ball)对应不同的展开方式,跟素材的实际格式对上才行,对不上就会出现画面错位。Convolution Type是很多人忽略的关键项,它决定导入时是否预计算模糊版本,选项通常是 None、Specular(光泽反射用)、Diffuse(漫反射环境光用),选 Specular 或 Diffuse 会显著增加导入时间与内存,但能让反射更平滑。Fixup Edge Seams专门用来修 mipmap 产生的边缘接缝,代价是导入慢一点,值得开。
提示:如果项目里天空盒只是背景,不参与反射和环境光的精细计算,Convolution Type 选 None 可以省一大截内存和导入时间,代价是金属材质的高光会显得脏。反过来,如果场景里大面积金属,建议选 Specular。
压缩格式在平台覆盖(Platform Override)里单独设置。不要相信默认值,Unity 对 Cube 纹理的默认压缩在部分平台会退化成不压缩,导入后去 Inspector 底部看一眼实际格式和内存占用,这一步能省掉后期一半的性能问题。
sRGB 勾选要和项目色彩空间对上。项目在 Linear 色彩空间(现在基本都是)时,作为“颜色”使用的天空盒贴图必须勾 sRGB,否则整体会发灰发暗,怎么调曝光都救不回来。这个坑我踩过不止一次,症状是天空盒看着“蒙了一层灰”,把 sRGB 一勾立刻通透。
2.3 全景图的宽高比与极点问题
全景图(等距柱状投影)用起来最省事,一张 2:1 的图就能铺满整个天空。规范是宽度必须是高度的两倍,5120×2560、4096×2048 都行。宽高比对不上,材质里就会出现拉伸或者上下留黑边。
采样方式上,材质会把它映射成经纬度布局,代价是两极附近有明显畸变,正上方和正下方会像被捏住一样收缩。如果你的项目里摄像机经常抬头看天(比如飞行、登山类),全景图的顶部会被放大得很糊,这时候要么提高分辨率,要么改用六面图。还有一个隐蔽问题:全景图左右边缘要无缝衔接,素材本身接缝没处理好,旋转天空盒的时候会在某个角度看到一条竖线,这个只能靠素材阶段修。
3. 材质与场景设置:让天空盒正确出现在画面里
素材准备好了,接下来是把它变成“世界背景”的过程。这里涉及三个位置:材质资产、Lighting 窗口、摄像机。三个地方任何一个没配好,天空盒都不会正常显示。
3.1 新建材质、选对 Shader、逐个参数理解
在 Project 窗口右键 Create > Material,命名成M_Sky_Day这类清晰的名字(后期动态切换会感谢自己)。Inspector 顶部 Shader 下拉里找到 Skybox 分类,里面就是那四个:6 Sided、Cubemap、Panoramic、Procedural。选哪个取决于你的素材形态,不是随便挑。
以最常用的Skybox/Panoramic为例,参数含义如下。Mapping 选 Latitude Longitude Layout 用于全景图,选 6 Sided 则是把六张图分别塞进去。Image Type 有 360 Degrees 和 180 Degrees 两档,半景图选 180 后还要指定镜像方向,方向选错会看到画面左右颠倒或者上下颠倒。Rotation 是绕 Y 轴的旋转角度,用来把太阳挪到想要的位置。Exposure 相当于亮度倍增,默认 1.3 左右,调高会整体提亮但也更容易过曝。
Skybox/6 Sided的槽位就是 Front/Back/Left/Right/Up/Down 六张贴图,新版本材质面板同样提供 Rotation 与 Exposure。如果你用的版本没有 Rotation 参数,可以在脚本里直接改 Shader 属性_Rotation,效果一样。
Skybox/Cubemap最简单,只有一个 Cubemap 槽位加 Exposure、Rotation,把导入好的 Cube 纹理拖进去就完事。
这里有个操作细节值得单说:材质上改的是“这份材质实例”的参数,不是原始贴图。所以你可以用同一张 Cubemap 做出白天、黄昏、夜晚三份材质,只改 Exposure 和 Rotation,素材只占一份显存。这个做法在需要多时段切换的项目里非常省。
3.2 Lighting 窗口里那几项,决定天空盒能不能“发光”
材质做完,很多人会卡在“材质里明明有图,场景里就是不亮”。原因几乎都在这里:Lighting 窗口没有引用这份材质。
打开 Window > Rendering > Lighting,Environment 标签下第一项就是 Skybox Material,把刚做的材质拖进去。这一步做完,Scene 视图的背景立刻变了。但真正影响画面的是下面两组设置。
Environment Lighting 的 Source 默认是 Skybox,意思是环境光从天空盒采样。Intensity 是环境光强度倍率,默认 1。如果场景里背光面死黑,可以先试着把这个值提到 1.2 到 1.5,比去改每个材质的间接光强度高效得多。Ambient Mode 在实时与烘焙之间切换,涉及光照贴图流程,后面单独说。
Environment Reflections 的 Source 同样指向 Skybox,Resolution 决定反射贴图的边长,默认 128,这个值直接决定金属表面反射的清晰度。128 在近景金属上会明显糊,我一般给到 256,性能敏感的场景保持 128。Intensity 是反射强度,Bounces 是反射迭代次数。
注意:Resolution 从 128 提到 256,反射贴图的内存占用是四倍增长。六面 256 的立方体贴图压缩后大约 0.75 MB,六面 512 则是 3 MB 左右,看起来不多,但配合多个反射探针后会迅速堆起来,移动端要克制。
3.3 摄像机 Clear Flags:别让天空盒被别的东西盖住
材质和 Lighting 都对了,画面里还是没天空,八成是摄像机的问题。摄像机的 Clear Flags 必须设为 Skybox,此时它会先清屏再绘制天空盒。如果设成 Solid Color,背景就是纯色,天空盒再好看也看不到。如果设成 Depth Only 或 Don't Clear,通常是多相机叠加场景用的,此时天空盒由底层相机负责。
多相机叠加的做法是:主相机 Clear Flags = Skybox,负责画背景和主场景;UI 相机或武器相机 Clear Flags = Depth Only,只画自己那层,Depth 值调大。这样天空盒只渲染一次,后面的相机不重复绘制全屏背景,省填充率。
还有一个容易忽略的点:远裁剪面。天空盒本身一般不受 Far 值影响,但场景里物体会被裁,地平线和远景雾会对不上。我习惯把主相机 Far 设到 1000 以上,做室外场景时给到 3000,配合雾效掩盖远处的裁剪边界。
3.4 程序化天空盒:白盒阶段的临时方案
Skybox/Procedural 是我在白盒阶段最常用的东西,因为它不需要任何素材。参数有 Sun(指定一盏平行光作为太阳)、Sun Size(太阳视角大小)、Sun Size Convergence(边缘收敛程度)、Atmosphere Thickness(大气厚度,直接决定天空是湛蓝还是浑浊发白)、Sky Tint(天空底色)、Ground(地面颜色)、Exposure(曝光)。
调参逻辑很直观:Atmosphere Thickness 往 0.6 走,天空会偏向深空蓝,像高原;往 2 以上走,会变成雾蒙蒙的灰白,适合阴天。Sky Tint 稍微偏黄绿一点能模拟沙尘。Ground 颜色要跟场景地面的整体色调接近,否则地平线会出现一条突兀的分界,这在大量 Demo 里都能看到。
程序化天空盒的另一个价值是它可以实时驱动太阳方位。把平行光的 Transform 指给 Sun 槽位,旋转平行光,天空里的太阳位置和光晕会跟着动。做昼夜循环的原型时,这套能省下大量素材工作。缺点是风格化太明显,写实项目最终还是得换贴图。
顺带提一句 Quality 设置。Project Settings > Quality 里每一档画质都可以单独指定 Skybox 材质与 Sun 光源,这意味着你可以让低画质档用 1K 素材、高画质档用 4K 素材,不需要写任何代码。这个功能用的人不多,但在需要在不同配置机器上跑的 Demo 里非常好使。
4. 反射与环境光:天空盒真正干活的地方
到这一节才算进入正题。前面所有配置都是为了让天空盒“显示出来”,而这一节讲的是它怎么影响画面里的每一个物体。
4.1 反射分辨率和强度怎么定
环境反射的本质是一张预先算好的立方体贴图。引擎在运行时(或者烘焙时)把天空盒渲染到这个立方体贴图里,然后每个 PBR 材质根据粗糙度采样不同 mip 层级。粗糙度高采样模糊层级,粗糙度低采样清晰层级。所以你会发现同一个天空盒,粗糙的橡胶反射出大片色块,光滑的金属反射出清晰云纹。
Resolution 定成多少,取决于最容易露馅的那个物体。如果场景里有大面积金属且在近景,256 是底线;如果只有零散的金属构件,128 足够。Intensity 一般保持 1,只有在天空盒亮度与实际光照严重不匹配时才动它,比如夜晚场景想让反射更弱,可以降到 0.6。
这里有个我一直坚持的做法:先把天空盒和反射定下来,再做材质。反过来做的话,你调好的材质在某天换天空盒之后会全部失真。这个顺序在团队协作里尤其重要,最好在项目规范里写死。
4.2 Reflection Probe 与天空盒的分工
很多同学会问,有了天空盒的反射,还要反射探针干嘛。答案是精度。天空盒提供的反射假设“周围环境无限远”,对于开阔室外场景是合理的,但对于走廊、房间、车底这类封闭或近场环境,反射出来的东西完全不对。
正确做法是在关键位置摆 Reflection Probe,把天空盒作为它的背景来源之一。探针会渲染周围一圈的实际场景,包括天空盒,合成一张局部立方体贴图。这样墙边的金属箱子反射出来的是墙和天空,而不是“远处的天空”。探针的 Type 用 Baked 时配合烘焙,用 Realtime 时每帧或按需刷新。
选 Baked 还是 Realtime 的判断很简单:场景静态就用 Baked,有动态物体(比如会开走的车)需要出现在反射里才用 Realtime,并且把 Refresh Mode 设成 Via Scripting,只在需要时手动刷新,别用 Every Frame,那个开销在移动端相当可观。
4.3 换了天空盒记得重新烘焙,这是一个高频事故
这是我最想强调的一条。当你使用烘焙光照(Baked GI 或 Mixed)时,天空盒贡献的环境光会被烘进光照贴图和光照探针里。你把天空盒从白天换成黄昏,场景里的静态物体不会自动变暗,因为它们的间接光是贴图里存着的旧数据。
正确流程是:换完天空盒材质 → Lighting 窗口点 Generate Lighting → 等烘焙完成。动态物体走光照探针的也要重新烘焙探针。这件事在开发后期很容易漏,表现是“编辑器里预览正常,真机上静态物体全都过亮”,排查起来要花很久。
如果项目是纯实时 GI,就不存在这个问题,但运行时改天空盒之后要手动调一次DynamicGI.UpdateEnvironment()让环境光探针刷新,这个接口后面会写。它的开销不小,绝对不要每帧调。
5. 运行时动态切换与过渡的写法
固定天空盒只是入门,真正在项目里用起来,八成会遇到“进入不同区域换天空”或者“白天渐变到夜晚”的需求。这一节给可以直接抄的代码。
5.1 最简切换:改全局引用再刷新环境光
核心就两行:给RenderSettings.skybox赋材质,然后刷新环境光。
using UnityEngine; public class SkyboxSwitcher : MonoBehaviour { public Material daySky; public Material nightSky; void Start() { RenderSettings.skybox = daySky; // 首次设置后刷新一次环境光,否则环境光还是旧的 DynamicGI.UpdateEnvironment(); } public void SwitchToNight() { RenderSettings.skybox = nightSky; DynamicGI.UpdateEnvironment(); } }这里有两个实操要点。第一,直接赋值会引用工程里的原始材质资产,如果你在运行时改了材质的参数(比如旋转),改动会写回资产,退出播放模式后仍然保留,下次打开工程发现材质被改花了。稳妥做法是先new Material(daySky)克隆一份再赋给RenderSettings.skybox。第二,DynamicGI.UpdateEnvironment()会重新计算球谐环境光,有一定耗时,切换频繁的场景要有节制地调。
5.2 平滑过渡:插值加节流刷新
想要白天渐变到黄昏,最直接的办法是用Material.Lerp在两个同 Shader 的材质之间插值。
using UnityEngine; public class SkyboxBlend : MonoBehaviour { public Material daySky; public Material nightSky; [Range(0f, 1f)] public float blend = 0f; public float duration = 10f; Material runtimeSky; float timer = 0f; float elapsed = 0f; void Start() { // 克隆一份,避免污染原始资产 runtimeSky = new Material(daySky); RenderSettings.skybox = runtimeSky; DynamicGI.UpdateEnvironment(); } void Update() { if (elapsed < duration) { elapsed += Time.deltaTime; blend = Mathf.Clamp01(elapsed / duration); runtimeSky.Lerp(daySky, nightSky, blend); // 环境光刷新做节流,每 0.25 秒一次足够 timer += Time.deltaTime; if (timer >= 0.25f) { timer = 0f; DynamicGI.UpdateEnvironment(); } } } }Material.Lerp的前提是两个材质用的是同一个 Shader,属性名对得上,否则插值结果会乱七八糟。另外它对贴图属性的插值是“按属性存在与否”处理的,不是真的做像素混合,所以六面图之间渐变可能出现中途跳变。真要做高质量的昼夜过渡,通常是写一个自定义 Shader,在 shader 里对两张 cubemap 采样后按权重混合,或者干脆用一张带时间维度的贴图。原型阶段用Material.Lerp完全够。
节流那一段是我实测下来的经验:不节流的话,每帧刷新环境光会让帧率直接掉一半,尤其在移动端。0.2 到 0.25 秒一次的频率,肉眼看不出延迟。
5.3 旋转天空盒:让云动起来
想让天空“活”起来,最省成本的方式是缓慢旋转。天空盒材质有_Rotation属性,直接设浮点值即可。
void Update() { float angle = Time.time * 0.3f % 360f; RenderSettings.skybox.SetFloat("_Rotation", angle); }速度别太快,0.2 到 0.5 度每秒比较自然,云层缓慢移动的感觉就出来了。超过 2 度每秒会让人晕。这个操作本身几乎不花钱,因为只是改了一个 uniform 变量,顶点着色器里做旋转,代价可以忽略。
需要注意,旋转天空盒之后,环境反射的方位也和实际场景对不上了。如果场景里有明确的太阳方向和阴影,旋转天空盒会让阴影方向看起来“不对”。处理办法是把平行光的方向也跟着转,或者干脆只在不强调光照一致性的场景里用这招。
6. 性能、平台与管线差异
天空盒的性能问题通常不在“渲染”,而在“显存”和“填充率”。这一节按平台和管线分别说。
6.1 显存与填充率的两笔账
显存那笔账前面算过了,2048 六面不压缩接近 128 MB,压缩后十几兆。除了显存,还有填充率:天空盒是每帧全屏覆盖一次,分辨率越高,采样带宽压力越大。移动端 1080p 屏幕上,天空盒的全屏绘制大约占总渲染开销的 5% 到 10%,如果在低端机上用了 4K 素材加未压缩格式,这个比例会失控。
我一般遵循三条规则。第一,移动端六面图每面不超过 1024;第二,一定开压缩,桌面 BC1/BC6H,移动端 ASTC 6×6;第三,如果天空盒只在开场出现,考虑在进入室内场景时把它切成纯色,RenderSettings.skybox换成一个极简材质,反射贴图也跟着变小,这一招对内存吃紧的设备很有效。
6.2 URP 与 HDRP 的配置位置不一样
标准渲染管线(Built-in)里,天空盒走RenderSettings.skybox,Lighting 窗口设置环境光,这套流程上面讲的就是。
URP 大体一致,Lighting 窗口的 Environment 部分依然有效,天空盒材质照常挂。区别在于 URP 的相机设置更细,部分版本里需要在相机组件上确认 Background Type 是 Skybox。另外 URP 的反射探针行为略有差异,Resolution 的设置位置在 Lighting 窗口的 Environment Reflections 里,逻辑不变。
HDRP 则是另一套东西,完全不走RenderSettings.skybox。它用 Volume 系统,加一个 Visual Environment 组件指定 Sky Type,再加 HDRISky 或 Physically Based Sky 组件。如果你按 Built-in 的教程在 HDRP 项目里到处找 Skybox Material 槽位,是找不到的。这个差异让不少从 Built-in 迁过来的同学卡了半天,务必提前确认管线类型。
6.3 移动端与立体渲染的额外注意
移动端除了纹理预算,还要注意天空盒的 shader 变体。某些自定义天空盒 shader 会引入额外关键字,参与打包时把变体数量撑大。用官方自带的那四个 Skybox shader 一般不会有这个问题,但如果美术给了自定义 shader,记得在 Shader Variant 收集里检查一下。
如果是双目立体渲染的项目,天空盒的渲染要注意左右眼的一致性。基线偏移在无限远的天空盒上应该被忽略,否则会出现“远处景物跳动”的鬼影。主流 XR 插件对官方 Skybox shader 都做了处理,自定义 shader 就需要自己确保顶点变换里忽略 eye offset,这一点在做立体内容时是必须验证的。
还有一个细节:天空盒在 Scene 视图和 Game 视图的显示是分开控制的。Scene 视图右上角有个天空盒开关,关掉之后编辑起来更清爽(尤其是场景里有半透明物体的时候)。这个开关不影响运行时表现,别以为关掉之后运行时就没了。
7. 常见问题速查与排查思路
下面这张表是我这些年被问得最多的问题,以及实际排查顺序。遇到问题时从上往下试,基本能定位到原因。
| 现象 | 最可能原因 | 排查动作 |
|---|---|---|
| 场景背景是纯色,没有天空 | Lighting 窗口没挂材质 / 相机 Clear Flags 不对 | 先看 Lighting > Environment 的 Skybox 槽,再检查主相机 |
| 天空盒发灰、发暗、像蒙了层雾 | 贴图 sRGB 未勾选,或项目是 Linear 空间但贴图按 Gamma 处理 | 选中贴图勾上 sRGB,重新导入 |
| 天空盒过曝、云层一片白 | Exposure 过高,或 HDR 素材未按 HDR 格式导入 | 材质 Exposure 降到 1 左右,检查是否为 BC6H |
| 六面接缝处有细黑线 | mipmap 边缘渗色 | 开 Fixup Edge Seams,或 Texture Wrap Mode 改 Clamp |
| 全景图两极严重拉伸变形 | 等距柱状投影的固有畸变 | 提高分辨率,或改用六面图 |
| 全景图左右有一条竖线 | 素材本身接缝没处理 | 回素材阶段修,或在材质里旋转避开镜头朝向 |
| 金属材质反射不清、糊成一团 | Environment Reflections 的 Resolution 过低 | 128 提到 256,重新生成 |
| 换天空盒后静态物体亮度不对 | 烘焙光照未更新 | Lighting 窗口重新 Generate Lighting |
| 运行时切天空盒,环境光没变 | 没调DynamicGI.UpdateEnvironment() | 在赋值后调一次,注意节流 |
| 运行时改了材质,退出播放后参数被改花 | 直接引用了原始材质资产 | 先new Material()克隆再赋值 |
| HDRP 项目找不到 Skybox 槽位 | HDRP 用 Volume 的 Sky 组件 | 加 Visual Environment + HDRISky |
| 天空盒只在编辑器可见,打包后没有 | 材质没进打包资源 / AssetBundle 未包含 | 检查资源引用链与打包清单 |
7.1 颜色不对先查色彩空间,别急着调参数
“天空盒颜色不对”这个症状下面藏着多种原因,我的排查顺序永远是:先确认贴图 sRGB 勾选状态,再确认项目色彩空间,最后才动 Exposure。因为前两者是配置错误,调 Exposure 只能掩盖问题,换个场景又会崩。
项目色彩空间在 Player Settings 里,现在基本都是 Linear。Linear 空间下,所有“颜色”语义的贴图都要勾 sRGB,引擎会在采样时做线性化。没勾的话,颜色会被当作已经是线性值直接使用,结果就是整体偏暗偏灰,暗部细节糊成一片。反过来,把法线图、遮罩图这类数据贴图勾了 sRGB,也会出问题,只是症状更隐蔽。
7.2 接缝与黑边的三种处理路径
六面图接缝是经典问题。第一层原因是贴图本身边缘没对齐,这只能靠素材修。第二层是 mipmap 生成时相邻面互相渗色,Unity 的 Fixup Edge Seams 就是干这个的。第三层是 Wrap Mode 设成了 Repeat,边缘采样到了对面去,改成 Clamp 通常立竿见影。
全景图的黑边多半是宽高比不对,或者 Image Type 选错(把 180 的图当 360 用)。检查素材实际像素尺寸,确认是严格的 2:1,这个问题基本就没了。
7.3 打包后才出问题,往资源引用上想
编辑器里一切正常,打包后天空盒没了,这几乎都是资源没被打进去。原因可能是材质是通过代码动态加载的,没在任何场景或 Resources 目录里被引用,打包时被剔除了。解决办法是把材质放进 Resources 目录,或者在某个被引用的 ScriptableObject 里持有引用,或者干脆在建包配置里显式包含。
这个坑在 AssetBundle 项目里更常见,天空盒材质被单独打成一个包,但包没被加载,运行时RenderSettings.skybox就是空的。排查方式是在真机日志里打一行Debug.Log(RenderSettings.skybox == null),一目了然。
我个人在实际操作中的体会是,天空盒这个功能看似简单,真正花时间的从来不是“怎么挂上去”,而是挂上去之后环境光、反射、曝光之间那套连锁反应。我建议你在项目初期就把天空盒定下来,把 Lighting 窗口的所有参数截图存档,后面任何一次画面异常,先拿这张截图对一遍,比漫无目的地调材质快得多。另外,如果你正在做需要多时段切换的项目,早点把两份材质和切换脚本搭起来,别等到后期再补,那时候烘焙、探针、后处理参数全都缠在一起,改动成本会翻好几倍。