news 2026/6/10 19:15:14

【光照】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/6/10 8:33:11

直接给各位上点轨迹跟踪的干货。这次咱们玩个能自定义参考轨迹的二自由度MPC控制器,重点说说怎么让这铁疙瘩在不同路况下都跟得稳当。先整杯咖啡,咱们边调参边唠

可自定义期望轨迹的二自由动力学 MPC 跟踪控制 可以外部导入轨迹 知道x y s 即纵向位置 横向位置 位移量即可 请注意 要跟踪不同的轨迹,同一参数可能效果不一样 因此需要自己调参数保证控制效果最佳: Q矩阵增大可以保证侧向位置跟踪效果变好&#xff0c…

作者头像 李华
网站建设 2026/6/10 10:58:28

33、利用TiMidity搭建卡拉OK系统全攻略

利用TiMidity搭建卡拉OK系统全攻略 1. TiMidity基础介绍 TiMidity本质上是一款MIDI播放器,并非专门的卡拉OK播放器,不过它具备一定的可扩展性,经过配置后也能用于卡拉OK场景。默认情况下,它仅播放MIDI音乐并打印歌词。例如,运行以下命令: $timidity ../54154.mid执行…

作者头像 李华
网站建设 2026/6/9 19:40:20

骨髓来源抑制细胞(MDSC)

骨髓来源抑制细胞(Myeloid-derived suppressor cells, MDSC)分为粒形/多核形MDSCs(G-MDSC或PMN-MDSC)与MNP样MDSCs(M-MDSC)。单核吞噬细胞(Mononuclear phagocytes (MNPs))包括单核细胞、巨噬细胞和树突状细…

作者头像 李华
网站建设 2026/6/10 10:51:11

14、邮件系统的插件、安全及配置全解析

邮件系统的插件、安全及配置全解析 在当今数字化的时代,邮件系统是我们日常工作和生活中不可或缺的一部分。无论是个人用户收发邮件,还是企业进行业务沟通,一个稳定、安全且功能丰富的邮件系统至关重要。下面将详细介绍邮件系统相关的插件、安全防护以及配置方法。 一、Sq…

作者头像 李华
网站建设 2026/6/10 3:11:16

22、Procmail 正则表达式及高级应用全解析

Procmail 正则表达式及高级应用全解析 正则表达式简介 正则表达式是处理数据的强大工具。在 Procmail 中,正则表达式的实现与其他 UNIX 实用程序略有不同。Procmail 的匹配默认情况下不区分大小写,除非使用 D 标志,并且默认使用多行匹配。 简单来说,正则表达式可以理解为…

作者头像 李华