- 程序化(Procedural) 是指不依赖逐个手工制作内容,而是通过规则、数学函数、噪声、算法和参数,自动生成视觉效果、形状、分布或变化过程的一种实现方式。
- 它的优势通常是减少手工制作成本、提高复用性和可调性,并在不依赖大量定制资源的前提下,较高效率地构建丰富的场景表现
项目演示:
资源
教学资源
- 关于Unity自带的4种天空盒材质教程:Skyboxes in Unity
- 用Shader Graph转换为天空盒材质的教程:How To Create A Simple Skybox Shader – Unity 6 *UPDATED*
- Reference:追逐星辰 ✨ |Unity URP 着色器图
素材资源
它是一个实用的辅助贴图,带有网格,用于在展开3D网格时比较网格上的像素密度。网上找到的版本颜色通常太刺眼了
其具备:
- 数字是为了方便判断映射方向和镜像。
- 我加了圆形,比方形更适合发现变形。
- 非常细的网格纹理便于检查细节。
- 我给大块涂了颜色,这样能显示完整纹理的重复位置。
- 它是高4K分辨率的。



ShaderGraph创建
- 首先创建子Shader graph分别做天空盒的各个部分Create – shader graph – sub graph
- 再Create – ShaderGraph – Buildin(6版本后已改为URP) – unlit Shader Graph(无论URP还是HDRP必须使用Build in否则skybox不能正常工作),将各个sub graph导入
- shader编辑好后Create – Rendering – Material(不能直接material?)
- 在Window – Rendering – lighting – Environment – skybox Material中拖入创建的材质球
- 修改Material中在ShaderGraph中暴露的参数,在ShaderGraph再修改是改的默认参数
Shader Graph节点
Voronoi
- 用来根据输入的二维坐标
UV,生成一种**“细胞状 / 斑点状 / 裂纹状 / 点分布状”**的程序化图案- AngleOffset 用于改变 Voronoi 内部随机分布的角度特征,让图案样式发生变化
- CellDensity 控制 Voronoi 单元的密度,值越大点越多越细,值越小点越少越大。
Saturate
- 会把输入值强制限制在
0 到 1之间,防止灰度超出正常范围- 避免后续处理过亮或过暗失控
One Minus
- 会用
1 - 输入值的方式把黑白关系反转- 在星空 shader 里它常用来把 Voronoi 原本的亮暗结构翻转,让星点中心更容易被提取出来。
Power
- 把输入值做幂运算,用来强化或压缩亮度分布
- A 是底数,也就是你想被调整的原始灰度值
- B 是指数,值越大越会把大部分灰度压暗,只留下少量高亮区域。
- 在星空 shader 里它通常用来把 Voronoi 结果压成少量亮星点,从而形成真正的星星效果。
Tiling And Offset
- 用来控制 UV 的缩放和平移
- 控制 UV 在 X 和 Y 方向上的缩放倍数,也就是图案铺得多密或多疏
- 控制 UV 在 X 和 Y 方向上的平移量,也就是图案往哪里移动
Main Light Direction
- 会输出场景里“主方向光”的世界空间、已归一化方向向量;主方向光优先取投射阴影的方向光,否则取第一个不投射阴影的方向光
- 让太阳跟着场景里的
Directional Light走
- 让太阳跟着场景里的
View Direction
- 输出的是“当前像素朝向相机的方向”
原理说明
用一个 Directional Light 负责真实打光,用 Shader Graph 负责把天空、星星、太阳、月亮、月亮光晕、云和雾画出来,再用一个脚本统一控制这些参数在白天、黄昏、夜晚之间切换
sub shader – SKYBOX UV
- 因为SKYBOX材质不是普通模型贴图,不能直接靠物体自带UV。
先用世界空间方向算一套“天空专用 UV”,这样后面的渐变、星星、云和雾,都会稳定地贴在天空上,而不是跟着模型表面拉伸
Unlit Shader – SKyBox4
Sky Gradient
- 根据天空 UV 的垂直分量,在地平线颜色和天空顶部颜色之间做插值
- 越靠近地平线,颜色越接近
HorizonColor - 越靠近天顶,颜色越接近
SkyColor
- 越靠近地平线,颜色越接近
Stars
- 用程序化噪声生成随机星点分布
- Voronoi 这种程序化节点先做出随机分布,再通过
Saturate、One Minus、Power把它压成很多小亮点,最后再乘一个StarIntensity控制它在不同时间段的强弱
Sun Shape / Moon Shape
- 是把月亮方向和当前像素的观察方向进行比较;如果两者足够接近,说明这个像素位于月亮所在的天空区域,后续再通过阈值处理把这块区域提取成月亮圆盘
- 当前像素(指的是天空盒贴图的UV)朝哪个方向看,用
View Direction - 太阳朝哪个方向,用
_SunDirection - 月亮不是单独建模,而是用两个圆的布尔差做出来的,所以形状控制比较轻量,也更适合参数化编辑
Moon Glow
- 在月亮本体外面再叠一层更大、更软的月牙形遮罩,让月亮看起来像发光体
- 不是“把月亮边缘变模糊”,而是额外画了一层更柔和的外发光
Cloud
- 用噪声和时间偏移做出会流动的云层
- 先采样噪声 用
Wind Speed控制 UV 偏移 让噪声在天空上移动 再配合Cloud Mask让云主要出现在天空某个高度区域
Fog
- 在靠近地平线的位置增加一层雾化过渡
- 本质上还是利用天空 UV 的高度信息:
- 越接近地平线,雾越明显
- 越远离地平线,雾越弱
- 雾不是场景里的体积雾,而是天空 Shader 里的一层高度相关遮罩,用来柔化天空和地平线的交界
SkyBodiesDayNightController.cs
- 场景里只有一个真实主光源
- 太阳和月亮只是 Shader 画出来的两个天体圆盘
- 太阳/月亮的“看得见”是天空表现
- 场景真实明暗只有一个主光源负责(可通过夜晚加环境光解决晚上没有光源的问题)
- 月亮方向永远是太阳方向的相反数
- 先让主光源在天空中转起来,再根据它的方向反推当前是白天、黄昏还是夜晚。
- 脚本里会根据
time01算出主光源的俯仰角: 0附近是午夜0.25是日出0.5是正午0.75是日落
- 脚本里会根据
- 用太阳高度算“白天 / 黄昏 / 夜晚”权重
1表示太阳在头顶0表示太阳在地平线- 太阳在地平线下面时,高度本来就会是负数
- 然后再通过
dayStart/dayEnd和duskStart/duskEnd这些阈值,算出三个权重:day01dusk01night01从而实现平滑切换
- 脚本里定义了一个
SkyPreset,里面包括:- 天空颜色 地平线颜色 星星强度 太阳颜色和强度 月亮颜色和强度 月亮光晕颜色和强度 云颜色和强度 雾颜色 主光源颜色和强度。
- 用三套美术预设描述白天、黄昏、夜晚,再根据当前太阳高度去做平滑插值
- 比在 Shader Graph 里直接写死逻辑更好维护。
参数说明:
待做
除了星星外 + 一个银河?
给月亮一个贴图






