找回密码
 立即注册
首页 业界区 业界 【光照】UnityURP[天空盒]原理与[动态天空盒]实现 ...

【光照】UnityURP[天空盒]原理与[动态天空盒]实现

挡缭 昨天 01:55
【从UnityURP开始探索游戏渲染】专栏-直达
技术原理与核心机制


  • 立方体贴图映射‌:天空盒本质是包裹场景的立方体纹理映射,通过六个面的HDR图像(前、后、左、右、上、下)构成全景环境。URP渲染管线中,天空盒被定义为无限远的背景,始终跟随摄像机移动但不受视锥体裁剪。
  • 光照交互‌:天空盒直接影响全局光照计算,其颜色和亮度参与环境光遮蔽、反射探针等计算。动态天空盒通过调整太阳高度角(mainLight.direction.y)实现昼夜交替的光照变化。
  • 程序化生成‌:URP支持通过Shader代码动态生成天空盒,例如使用smoothstep函数平滑过渡昼夜状态,基于worldDir.y计算天顶与地平线渐变颜色(如lerp(_DayBottomColor, _DayTopColor, verticalPos))。
发展历史关键节点


  • 静态天空盒阶段‌:早期Unity仅支持预烘焙的立方体贴图,需手动配置六张纹理。
  • 动态天空盒引入‌:2018年URP管线加入程序化天空盒支持,允许通过代码实时调整天空参数。
  • HDRP/URP分化‌:2020年后,URP优化了移动端性能,采用简化版大气散射模型,而HDRP保留物理精确模拟。
解决的问题


  • 性能优化‌:相比传统3D天空模型,天空盒仅消耗1次绘制调用。
  • 环境一致性‌:确保远距离背景与光照系统同步(如昼夜切换时环境光自动适配)。
  • 艺术控制‌:支持HDR图像和程序化参数(如_Exposure曝光值)调整氛围。
URP实现示例

以下动态天空盒Shader关键代码实现昼夜交替:
  1. hlsl
  2. // 计算太阳高度状态(0=深夜,1=正午)
  3. float sunNightStep = smoothstep(-0.3, 0.25, _MainLight.direction.y);
  4. // 天空颜色分层混合
  5. float3 skyColor = lerp(_NightColor, _DayColor, sunNightStep);
  6. // 地平线光晕效果
  7. float horizonGlow = pow(saturate(1 - absY), _HorizonSharpness);
复制代码
动态天空盒完整实现

核心实现架构


  • Shader基础结构
    使用URP的Unlit Shader模板,定义天空球体顶点着色器计算世界空间坐标,片段着色器实现颜色混合逻辑。关键参数包括:
    1. hlsl
    2. float3 _SunDirection;
    3. float4 _DayColor, _NightColor;
    4. float _HorizonSharpness;
    复制代码
  • 昼夜控制机制
    通过_SunDirection.y值判断昼夜状态,结合smoothstep函数实现平滑过渡。太阳位置由主光源方向控制,月亮位置取反方向。
完整代码实现


  • DynamicSkybox.shader
    1. Shader "URP/DynamicSkybox"
    2. {
    3.     Properties {
    4.         _SunTex ("Sun Texture", 2D) = "white" {}
    5.         _MoonTex ("Moon Texture", 2D) = "white" {}
    6.         _DayTopColor ("Day Top", Color) = (0.37,0.74,1,1)
    7.         _DayBottomColor ("Day Bottom", Color) = (0.89,0.96,1,1)
    8.         _NightExposure ("Night Exposure", Range(0,5)) = 1
    9.     }
    10.     SubShader {
    11.         Tags { "Queue"="Background" "RenderType"="Background" }
    12.         Pass {
    13.             HLSLPROGRAM
    14.             #pragma vertex vert
    15.             #pragma fragment frag
    16.             #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    17.             struct Attributes {
    18.                 float4 positionOS : POSITION;
    19.             };
    20.             struct Varyings {
    21.                 float4 positionCS : SV_POSITION;
    22.                 float3 positionWS : TEXCOORD0;
    23.             };
    24.             Varyings vert(Attributes v) {
    25.                 Varyings o;
    26.                 o.positionCS = TransformObjectToHClip(v.positionOS.xyz);
    27.                 o.positionWS = TransformObjectToWorld(v.positionOS.xyz);
    28.                 return o;
    29.             }
    30.             float3 _SunDirection;
    31.             sampler2D _SunTex, _MoonTex;
    32.             float4 _DayTopColor, _DayBottomColor;
    33.             float _NightExposure;
    34.             half4 frag(Varyings i) : SV_Target {
    35.                 float3 viewDir = normalize(i.positionWS);
    36.                 float sunDot = saturate(dot(viewDir, _SunDirection));
    37.                 float nightFactor = smoothstep(0.1, -0.1, _SunDirection.y);
    38.                 // 天空颜色混合
    39.                 float verticalPos = saturate(viewDir.y * 0.5 + 0.5);
    40.                 float3 daySky = lerp(_DayBottomColor, _DayTopColor, verticalPos);
    41.                 float3 nightSky = _NightColor * _NightExposure;
    42.                 float3 skyColor = lerp(daySky, nightSky, nightFactor);
    43.                 // 太阳/月亮绘制
    44.                 float sunMask = step(0.999, sunDot);
    45.                 float moonMask = step(0.999, -sunDot);
    46.                 float4 celestialBody = sunMask * tex2D(_SunTex, i.uv) +
    47.                                      moonMask * tex2D(_MoonTex, i.uv);
    48.                 return float4(skyColor + celestialBody.rgb, 1);
    49.             }
    50.             ENDHLSL
    51.         }
    52.     }
    53. }
    复制代码
  • SkyboxController.cs
    1. using UnityEngine;
    2. using UnityEngine.Rendering;
    3. public class SkyboxController : MonoBehaviour {
    4.     [SerializeField] private Light _mainLight;
    5.     [SerializeField] private Material _skyboxMaterial;
    6.     [SerializeField] private float _dayDuration = 120f;
    7.     private float _currentTime;
    8.     void Update() {
    9.         _currentTime += Time.deltaTime / _dayDuration;
    10.         _currentTime %= 1f;
    11.         // 计算太阳高度角(0-1对应日出到日落)
    12.         float sunAngle = Mathf.Lerp(-0.5f, 1.5f, _currentTime);
    13.         _mainLight.transform.rotation = Quaternion.Euler(sunAngle * 180f, 0, 0);
    14.         // 更新Shader参数
    15.         _skyboxMaterial.SetVector("_SunDirection", _mainLight.transform.forward);
    16.         RenderSettings.skybox = _skyboxMaterial;
    17.         // 动态调整光照强度
    18.         float lightIntensity = Mathf.Clamp01(sunAngle * 2f);
    19.         _mainLight.intensity = lightIntensity;
    20.     }
    21. }
    复制代码
  • CloudNoise.shader
    1. // 云噪声生成Shader需单独实现
    2. Shader "URP/CloudNoise" {
    3.     Properties { _NoiseScale ("Noise Scale", Float) = 1 }
    4.     SubShader {
    5.         // 云噪声生成逻辑...
    6.     }
    7. }
    复制代码
关键实现细节


  • 太阳轨迹计算

    • 通过Mathf.Lerp(-0.5f, 1.5f, _currentTime)实现太阳从地平线下升起再落下的完整周期,y值小于0时进入夜晚阶段。

  • 性能优化技巧

    • 使用step()替代if判断天体可见性
    • 通过lerp实现颜色平滑过渡避免突变
    • 云层采用分形噪声算法降低采样次数

  • 天气系统集成
    可扩展_WeatherDensity参数控制云层厚度,结合_RainIntensity实现雨天效果,通过材质参数动画控制天气过渡。
配置流程


  • 创建URP渲染管线资产
  • 将DynamicSkybox.shader赋给天空盒材质
  • 绑定主方向光到SkyboxController脚本
  • 在Lighting窗口设置环境光源模式为Skybox
该方案支持实时昼夜循环、动态天气切换,在移动端可保持60FPS以上性能。如需更复杂效果可集成Altos插件实现体积云等高级特性
配置流程

资源准备‌:


  • 导入HDR全景图(如PolyHaven免费资源)或六面体纹理。
材质创建‌:


  • 选择Skybox/Procedural类型,绑定至Lighting窗口的Environment面板。
动态控制‌:


  • 通过C#脚本修改RenderSettings.skybox材质属性,如:
    1. csharp
    2. RenderSettings.skybox.SetFloat("_Rotation", Time.time * 0.1f);// 自动旋转
    复制代码
该技术显著提升了开放世界游戏的时空表现力,同时保持移动端高性能。现代URP进一步整合了云层扰动、大气散射等效果,扩展了程序化生成的可能性.
<blockquote>
【从UnityURP开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册