Unity 3D:基于玩家垂直位置调整场景光照的高效方案问询
解决方案
方案1:使用URP后处理调整全局亮度(推荐)
这是最简洁高效的方式,完全不需要修改场景光照组件,直接通过后处理层统一控制整个画面的亮度:
- 确保你的项目使用URP管线,并安装
Post Processing包(Package Manager中搜索安装)。 - 在场景中创建一个
Global Volume对象,添加Color Adjustments后处理组件。 - 编写脚本监听角色的Y轴高度,动态调整
Color Adjustments中的Brightness参数:
using UnityEngine; using UnityEngine.Rendering.Universal; public class HeightBasedBrightness : MonoBehaviour { public Transform player; public Volume globalVolume; public float minHeight = 0f; // 最低高度对应最亮 public float maxHeight = 200f; // 最高高度对应最暗 public float maxBrightness = 1f; public float minBrightness = -0.8f; private ColorAdjustments _colorAdjustments; void Start() { globalVolume.profile.TryGet(out _colorAdjustments); } void Update() { float heightRatio = Mathf.Clamp01((player.position.y - minHeight) / (maxHeight - minHeight)); float targetBrightness = Mathf.Lerp(maxBrightness, minBrightness, heightRatio); _colorAdjustments.brightness.value = targetBrightness; } }
- 优势:性能开销极低,所有物体(包括角色、场景、UI)都会同步变暗,无需单独修改每个物体的材质。
- 注意:如果用内置管线,可以替换为
Image Effect中的Color Correction组件,逻辑一致。
方案2:Shader全局变量控制物体亮度
如果需要更精细的控制(比如某些物体不受亮度影响),可以通过自定义Shader实现:
- 编写一个基础Shader(以Unlit为例),添加全局亮度控制变量:
Shader "Custom/HeightControlledUnlit" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float _GlobalBrightness; // 全局亮度变量 v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); col.rgb *= _GlobalBrightness; // 应用亮度调整 return col; } ENDCG } } }
- 将场景中需要受亮度影响的物体材质替换为这个Shader,然后在脚本中更新全局变量:
using UnityEngine; public class HeightBasedShaderBrightness : MonoBehaviour { public Transform player; public float minHeight = 0f; public float maxHeight = 200f; public float maxBrightness = 1f; public float minBrightness = 0.3f; void Update() { float heightRatio = Mathf.Clamp01((player.position.y - minHeight) / (maxHeight - minHeight)); float targetBrightness = Mathf.Lerp(maxBrightness, minBrightness, heightRatio); Shader.SetGlobalFloat("_GlobalBrightness", targetBrightness); } }
- 优势:可以灵活选择哪些物体受亮度影响,Shader层面计算性能优异。
- 注意:如果使用Standard Shader,可以通过修改Shader变体或使用材质的
Emission/Albedo颜色乘子实现类似效果,但自定义Shader更直接。
方案3:调整环境光强度(适合实时光照场景)
如果你需要保留场景的光照层次(比如阴影),可以直接调整全局环境光强度:
- 编写脚本监听角色高度,动态修改环境光强度:
using UnityEngine; public class HeightBasedAmbientLight : MonoBehaviour { public Transform player; public float minHeight = 0f; public float maxHeight = 200f; public float maxAmbientIntensity = 1f; public float minAmbientIntensity = 0.2f; void Update() { float heightRatio = Mathf.Clamp01((player.position.y - minHeight) / (maxHeight - minHeight)); float targetIntensity = Mathf.Lerp(maxAmbientIntensity, minAmbientIntensity, heightRatio); RenderSettings.ambientIntensity = targetIntensity; // 如需同步方向光强度,可添加以下代码 // GetComponent<Light>().intensity = targetIntensity; } }
- 优势:无需额外依赖,适合简单实时光照场景。
- 注意:如果场景中有烘焙光照,此方法无法影响烘焙部分,需配合实时光照使用。
为什么不推荐移动Sun?
移动方向光会触发Unity实时光照重新计算(包括阴影),每帧更新会带来不必要的性能开销,且你的Sun被2D背景遮挡,完全没必要通过移动光源模拟亮度变化。上述方案均为GPU层面的批量计算,性能开销可忽略不计。
内容的提问来源于stack exchange,提问作者Colin Andy
相关产品推荐
相关产品推荐

