news 2026/8/24 3:04:11

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【光照】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关键代码实现昼夜交替:

hlsl

// 计算太阳高度状态(0=深夜,1=正午)

float sunNightStep = smoothstep(-0.3, 0.25, _MainLight.direction.y);

// 天空颜色分层混合

float3 skyColor = lerp(_NightColor, _DayColor, sunNightStep);

// 地平线光晕效果

float horizonGlow = pow(saturate(1 - absY), _HorizonSharpness);

动态天空盒完整实现

核心实现架构

‌Shader基础结构‌

使用URP的Unlit Shader模板,定义天空球体顶点着色器计算世界空间坐标,片段着色器实现颜色混合逻辑。关键参数包括:

hlsl

float3 _SunDirection;

float4 _DayColor, _NightColor;

float _HorizonSharpness;

‌昼夜控制机制‌

通过_SunDirection.y值判断昼夜状态,结合smoothstep函数实现平滑过渡。太阳位置由主光源方向控制,月亮位置取反方向。

完整代码实现

DynamicSkybox.shader

Shader "URP/DynamicSkybox"

{

Properties {

_SunTex ("Sun Texture", 2D) = "white" {}

_MoonTex ("Moon Texture", 2D) = "white" {}

_DayTopColor ("Day Top", Color) = (0.37,0.74,1,1)

_DayBottomColor ("Day Bottom", Color) = (0.89,0.96,1,1)

_NightExposure ("Night Exposure", Range(0,5)) = 1

}

SubShader {

Tags { "Queue"="Background" "RenderType"="Background" }

Pass {

HLSLPROGRAM

#pragma vertex vert

#pragma fragment frag

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

struct Attributes {

float4 positionOS : POSITION;

};

struct Varyings {

float4 positionCS : SV_POSITION;

float3 positionWS : TEXCOORD0;

};

Varyings vert(Attributes v) {

Varyings o;

o.positionCS = TransformObjectToHClip(v.positionOS.xyz);

o.positionWS = TransformObjectToWorld(v.positionOS.xyz);

return o;

}

float3 _SunDirection;

sampler2D _SunTex, _MoonTex;

float4 _DayTopColor, _DayBottomColor;

float _NightExposure;

half4 frag(Varyings i) : SV_Target {

float3 viewDir = normalize(i.positionWS);

float sunDot = saturate(dot(viewDir, _SunDirection));

float nightFactor = smoothstep(0.1, -0.1, _SunDirection.y);

// 天空颜色混合

float verticalPos = saturate(viewDir.y * 0.5 + 0.5);

float3 daySky = lerp(_DayBottomColor, _DayTopColor, verticalPos);

float3 nightSky = _NightColor * _NightExposure;

float3 skyColor = lerp(daySky, nightSky, nightFactor);

// 太阳/月亮绘制

float sunMask = step(0.999, sunDot);

float moonMask = step(0.999, -sunDot);

float4 celestialBody = sunMask * tex2D(_SunTex, i.uv) +

moonMask * tex2D(_MoonTex, i.uv);

return float4(skyColor + celestialBody.rgb, 1);

}

ENDHLSL

}

}

}

SkyboxController.cs

using UnityEngine;

using UnityEngine.Rendering;

public class SkyboxController : MonoBehaviour {

[SerializeField] private Light _mainLight;

[SerializeField] private Material _skyboxMaterial;

[SerializeField] private float _dayDuration = 120f;

private float _currentTime;

void Update() {

_currentTime += Time.deltaTime / _dayDuration;

_currentTime %= 1f;

// 计算太阳高度角(0-1对应日出到日落)

float sunAngle = Mathf.Lerp(-0.5f, 1.5f, _currentTime);

_mainLight.transform.rotation = Quaternion.Euler(sunAngle * 180f, 0, 0);

// 更新Shader参数

_skyboxMaterial.SetVector("_SunDirection", _mainLight.transform.forward);

RenderSettings.skybox = _skyboxMaterial;

// 动态调整光照强度

float lightIntensity = Mathf.Clamp01(sunAngle * 2f);

_mainLight.intensity = lightIntensity;

}

}

CloudNoise.shader

// 云噪声生成Shader需单独实现

Shader "URP/CloudNoise" {

Properties { _NoiseScale ("Noise Scale", Float) = 1 }

SubShader {

// 云噪声生成逻辑...

}

}

关键实现细节

‌太阳轨迹计算‌

通过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材质属性,如:

csharp

RenderSettings.skybox.SetFloat("_Rotation", Time.time * 0.1f);// 自动旋转

该技术显著提升了开放世界游戏的时空表现力,同时保持移动端高性能。现代URP进一步整合了云层扰动、大气散射等效果,扩展了程序化生成的可能性.

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/24 8:18:03

基于Java+ vue在线考试系统(源码+数据库+文档)

在线考试 目录 基于springboot vue在线考试系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取: 基于springboot vue在线考试系统 一、前言 博主介绍:✌️大…

作者头像 李华
网站建设 2026/8/24 8:57:41

ysyx:pa3.1批处理系统

了让管理员事先准备好一组程序, 让计算机执行完一个程序之后, 就自动执行下一个程序,提出了批处理系统的思想。处理系统的关键, 就是要有一个后台程序, 当一个前台程序执行结束的时候, 后台程序就会自动加载一个新的前台程序来执行,这样的一个后台程序, …

作者头像 李华
网站建设 2026/8/24 14:29:53

基于springboot + vue高考志愿填报系统(源码+数据库+文档)

高考志愿填报 目录 基于springboot vue学生成绩管理系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取: 基于springboot vue高考志愿填报系统 一、前言 博主介绍&…

作者头像 李华
网站建设 2026/8/24 3:04:15

6-2集合的不重复特性应用(案例:提取唯一值记录)

案例:提取每天一笔销售记录原数据与结果:代码:function test(){Range("a2","a11").NumberFormatLocal"0";//改单元格属性为数值型var arrRange("a2:d11").Value();Range("a2","a11").Numbe…

作者头像 李华
网站建设 2026/8/23 13:50:27

电脑核心参数一次讲透

还在对着 CPU 型号、显存容量、屏幕刷新率一头雾水?买笔记本怕被商家忽悠,选参数总踩坑?这篇硬核干货,把电脑核心硬件参数掰开揉碎讲清楚,小白也能秒懂,帮你选本不踩雷! CPU型号 CPU系列型号是指…

作者头像 李华
网站建设 2026/8/23 21:50:12

YOLOv11目标检测完整教程:5个关键技巧实现COCO数据集最佳性能

YOLOv11目标检测完整教程:5个关键技巧实现COCO数据集最佳性能 【免费下载链接】ultralytics ultralytics - 提供 YOLOv8 模型,用于目标检测、图像分割、姿态估计和图像分类,适合机器学习和计算机视觉领域的开发者。 项目地址: https://gitc…

作者头像 李华