别再只把RenderTexture当截图工具了Unity中这5个实战用法让你的游戏效果翻倍在Unity开发中RenderTexture常被简单地用作截图或后视镜的实现工具这无疑是对其强大功能的一种浪费。RenderTexture本质上是一个动态的、可编程的渲染画布能够将任何3D场景、特效或UI元素实时渲染到纹理上。这种特性为游戏开发打开了无数创意可能性的大门。本文将带你探索RenderTexture在游戏开发中的五种高级应用场景从动态环境反射到交互式UI从Shader特效到移动端优化再到动态光照烘焙每个案例都配有实用的代码片段和性能优化建议。1. 动态环境反射超越传统镜面效果大多数开发者使用RenderTexture实现简单的镜面或后视镜效果但它的潜力远不止于此。通过巧妙结合RenderTexture和Shader我们可以创造出令人惊叹的动态环境反射效果比如逼真的水面倒影或金属表面反射。1.1 实现动态水面反射传统的水面反射往往使用平面反射探针(Reflection Probe)但这种方法无法实时反映场景变化。使用RenderTexture可以创建完全动态的水面反射系统// 创建反射相机 Camera reflectionCamera new GameObject(ReflectionCamera).AddComponentCamera(); reflectionCamera.CopyFrom(mainCamera); reflectionCamera.enabled false; // 设置RenderTexture RenderTexture reflectionRT new RenderTexture(1024, 1024, 24); reflectionCamera.targetTexture reflectionRT; // 在LateUpdate中更新反射相机位置 void LateUpdate() { Vector3 cameraDirWorld mainCamera.transform.forward; Vector3 cameraUpWorld mainCamera.transform.up; Vector3 cameraPosWorld mainCamera.transform.position; // 计算反射相机位置和方向 float d -Vector3.Dot(waterPlane.normal, cameraPosWorld) - waterPlane.distance; Vector3 reflectionPos cameraPosWorld 2 * d * waterPlane.normal; reflectionCamera.transform.position reflectionPos; reflectionCamera.transform.LookAt(reflectionPos cameraDirWorld, cameraUpWorld); // 渲染到RenderTexture reflectionCamera.Render(); }在Shader中我们可以这样使用反射纹理sampler2D _ReflectionTex; float _ReflectionStrength; void surf (Input IN, inout SurfaceOutputStandard o) { // 基础颜色 fixed4 c tex2D(_MainTex, IN.uv_MainTex); // 反射颜色 float2 reflectionUV IN.screenPos.xy / IN.screenPos.w; fixed4 reflectionColor tex2D(_ReflectionTex, reflectionUV); // 混合基础色和反射色 o.Albedo c.rgb; o.Emission reflectionColor.rgb * _ReflectionStrength; o.Metallic _Metallic; o.Smoothness _Glossiness; }1.2 性能优化技巧动态反射虽然效果惊艳但对性能影响较大。以下是几个关键优化点分辨率控制反射不需要与原屏幕相同分辨率512x512甚至256x256通常就足够渲染层优化只反射必要的物体通过LayerMask过滤更新频率不需要每帧更新可以每2-3帧更新一次距离衰减根据相机与水面的距离调整反射质量反射质量与性能平衡参数表参数高质量设置平衡设置低性能消耗设置分辨率1024x1024512x512256x256更新频率每帧每2帧每3帧渲染距离100m50m30m反射物体全部主要场景关键物体抗锯齿4x MSAA2x MSAA关闭2. 交互式画中画UI与监控系统RenderTexture可以轻松实现游戏内的实时监控屏幕、安全摄像头或魔法镜子等效果。与简单的UI图片不同这些元素可以展示真实的游戏场景动态。2.1 创建动态监控屏幕public class SecurityCamera : MonoBehaviour { public RenderTexture cameraRT; public RawImage displayImage; private Camera securityCam; void Start() { // 创建安全摄像头 securityCam new GameObject(SecurityCamera).AddComponentCamera(); securityCam.targetTexture cameraRT; securityCam.cullingMask LayerMask.GetMask(SecurityView); securityCam.depth -10; // 确保在其他相机之前渲染 // 设置显示 displayImage.texture cameraRT; } void Update() { // 可以在这里添加摄像头移动或切换逻辑 } }2.2 高级应用多摄像头切换系统对于需要多个监控画面的游戏我们可以建立一个更复杂的系统public class SecuritySystem : MonoBehaviour { public RenderTexture[] cameraRTs; public RawImage[] displayScreens; public Camera[] securityCameras; private int currentRTIndex 0; void Start() { // 初始化所有摄像头和RenderTexture for(int i 0; i securityCameras.Length; i) { securityCameras[i].targetTexture cameraRTs[i]; securityCameras[i].enabled false; } // 启动第一个摄像头 SwitchCamera(0); } public void SwitchCamera(int index) { // 禁用当前摄像头 securityCameras[currentRTIndex].enabled false; // 启用新摄像头 currentRTIndex index; securityCameras[currentRTIndex].enabled true; // 更新所有屏幕显示 foreach(var screen in displayScreens) { screen.texture cameraRTs[currentRTIndex]; } } }提示对于监控系统可以考虑使用低帧率(15-20fps)来模拟真实监控效果同时节省性能。2.3 性能考量交互式UI系统需要考虑以下性能因素RenderTexture数量同时激活的RT越多性能消耗越大分辨率选择UI元素通常不需要高分辨率更新频率非关键UI可以降低更新频率Shader复杂度显示RT的材质应尽量简单3. Shader特效RenderTexture作为数据流RenderTexture不仅可以存储图像还可以作为自定义数据载体与Shader Graph结合创造出各种动态视觉效果。3.1 创建动态涂鸦墙想象一个玩家可以在墙面上实时涂鸦的效果public class GraffitiWall : MonoBehaviour { public RenderTexture graffitiRT; public Material wallMaterial; public BrushSettings brush; void Start() { // 初始化干净的涂鸦板 Graphics.Blit(Texture2D.whiteTexture, graffitiRT); wallMaterial.SetTexture(_GraffitiTex, graffitiRT); } void Update() { if(Input.GetMouseButton(0)) { RaycastHit hit; Ray ray Camera.main.ScreenPointToRay(Input.mousePosition); if(Physics.Raycast(ray, out hit) hit.collider.gameObject gameObject) { DrawAtPosition(hit.textureCoord); } } } void DrawAtPosition(Vector2 uv) { // 临时激活RT RenderTexture.active graffitiRT; // 设置绘制位置 GL.PushMatrix(); GL.LoadPixelMatrix(0, graffitiRT.width, graffitiRT.height, 0); // 绘制图形 Graphics.DrawTexture( new Rect(uv.x * graffitiRT.width - brush.size/2, (1-uv.y) * graffitiRT.height - brush.size/2, brush.size, brush.size), brush.texture, brush.mat); GL.PopMatrix(); RenderTexture.active null; } }在Shader Graph中我们可以这样使用涂鸦纹理创建Texture2D属性接收GraffitiTex使用Sample Texture 2D节点获取颜色与墙面基础色混合(如Multiply或Add)可以添加扭曲效果使涂鸦看起来更自然3.2 传送门扭曲效果RenderTexture非常适合实现传送门效果展示另一个场景的同时添加扭曲特效public class Portal : MonoBehaviour { public Transform linkedPortal; public Camera portalCamera; public RenderTexture portalRT; void Start() { portalCamera.targetTexture portalRT; GetComponentRenderer().material.SetTexture(_PortalTex, portalRT); } void Update() { // 更新传送门相机位置 Vector3 relativePos transform.InverseTransformPoint(Camera.main.transform.position); relativePos Vector3.Scale(relativePos, new Vector3(-1, 1, -1)); portalCamera.transform.position linkedPortal.TransformPoint(relativePos); // 更新旋转 Quaternion relativeRot Quaternion.Inverse(transform.rotation) * Camera.main.transform.rotation; portalCamera.transform.rotation linkedPortal.rotation * relativeRot; } }传送门Shader关键点使用RenderTexture作为基础纹理添加基于距离的扭曲效果(使用噪声纹理)边缘发光和粒子效果增强视觉冲击可以考虑添加时间参数实现动态扭曲4. 移动端优化智能使用低分辨率RT在移动设备上RenderTexture可以成为性能优化的利器特别是在后处理效果方面。4.1 低分辨率后处理全屏后处理在移动端代价高昂但通过RenderTexture我们可以实现智能降级public class MobilePostProcessing : MonoBehaviour { public Camera mainCamera; public Material postProcessMaterial; [Range(0.1f, 1f)] public float resolutionScale 0.5f; private RenderTexture halfResRT; void OnEnable() { int width (int)(Screen.width * resolutionScale); int height (int)(Screen.height * resolutionScale); halfResRT new RenderTexture(width, height, 0, RenderTextureFormat.DefaultHDR); mainCamera.targetTexture halfResRT; } void OnRenderImage(RenderTexture src, RenderTexture dest) { if(postProcessMaterial ! null) { Graphics.Blit(halfResRT, dest, postProcessMaterial); } else { Graphics.Blit(halfResRT, dest); } } void OnDisable() { mainCamera.targetTexture null; if(halfResRT ! null) { halfResRT.Release(); } } }4.2 动态分辨率调整根据设备性能动态调整RT分辨率public class DynamicResolution : MonoBehaviour { public float minScale 0.3f; public float maxScale 1.0f; public float targetFPS 60f; public float adjustmentSpeed 0.1f; private float currentScale 1f; private RenderTexture dynamicRT; private Camera mainCam; void Start() { mainCam Camera.main; UpdateRT(); } void Update() { // 计算当前FPS与目标差距 float fpsDelta (1f / Time.unscaledDeltaTime) - targetFPS; float scaleDelta Mathf.Clamp(fpsDelta * adjustmentSpeed / targetFPS, -0.1f, 0.1f); // 调整分辨率比例 currentScale Mathf.Clamp(currentScale scaleDelta, minScale, maxScale); UpdateRT(); } void UpdateRT() { if(dynamicRT ! null) { dynamicRT.Release(); } int width (int)(Screen.width * currentScale); int height (int)(Screen.height * currentScale); dynamicRT new RenderTexture(width, height, 24); mainCam.targetTexture dynamicRT; } void OnDestroy() { if(dynamicRT ! null) { dynamicRT.Release(); } } }4.3 移动端RenderTexture最佳实践使用RenderTexture.GetTemporary避免频繁创建销毁RT选择合适的格式移动端通常使用RGB565或ARGB4444减少带宽Mipmap考虑根据需求开启或关闭抗锯齿移动端通常可以关闭或使用FXAA释放时机不再使用的RT及时释放5. 动态光照烘焙到纹理RenderTexture可以用于烘焙动态光照信息实现一些特殊效果或优化静态场景的光照表现。5.1 实时光照贴图烘焙public class LightmapBaker : MonoBehaviour { public RenderTexture lightmapRT; public Camera bakingCamera; public LayerMask bakingLayers; void Start() { BakeLightmap(); } public void BakeLightmap() { // 设置烘焙相机 bakingCamera.targetTexture lightmapRT; bakingCamera.cullingMask bakingLayers; bakingCamera.RenderWithShader(LightmapShader, RenderType); // 将烘焙结果应用到场景材质 foreach(var renderer in FindObjectsOfTypeRenderer()) { if(renderer.gameObject.layer bakingLayers) { renderer.material.SetTexture(_Lightmap, lightmapRT); } } } }对应的Shader需要专门编写来输出光照信息Shader Custom/LightmapBaker { SubShader { Tags { RenderTypeOpaque } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include UnityCG.cginc struct v2f { float4 pos : SV_POSITION; float3 worldPos : TEXCOORD0; float3 normal : TEXCOORD1; }; v2f vert (appdata_base v) { v2f o; o.pos UnityObjectToClipPos(v.vertex); o.worldPos mul(unity_ObjectToWorld, v.vertex).xyz; o.normal UnityObjectToWorldNormal(v.normal); return o; } fixed4 frag (v2f i) : SV_Target { // 计算简单光照 float3 lightDir normalize(_WorldSpaceLightPos0.xyz); float NdotL max(0, dot(i.normal, lightDir)); // 输出光照信息 return fixed4(NdotL, NdotL, NdotL, 1); } ENDCG } } }5.2 应用场景昼夜循环系统动态光照烘焙特别适合昼夜循环系统可以在不增加实时计算负担的情况下实现高质量的光照变化public class DayNightCycle : MonoBehaviour { public Light sunLight; public float dayDuration 300f; // 秒 public RenderTexture[] lightmapRTs; public int bakeInterval 30; // 帧 private float currentTime; private int frameCount; void Update() { currentTime Time.deltaTime / dayDuration; currentTime % 1f; // 更新太阳位置 sunLight.transform.rotation Quaternion.Euler(currentTime * 360f - 90f, 0, 0); // 定期烘焙光照 if(frameCount bakeInterval) { frameCount 0; BakeCurrentLighting(); } } void BakeCurrentLighting() { // 根据时间选择不同的RT交替使用 RenderTexture rt lightmapRTs[Time.frameCount % lightmapRTs.Length]; // 设置光照参到Shader Shader.SetGlobalVector(_SunDirection, sunLight.transform.forward); Shader.SetGlobalColor(_SunColor, sunLight.color * sunLight.intensity); // 执行烘焙 Graphics.Blit(null, rt, bakingMaterial); // 应用到场景 Shader.SetGlobalTexture(_DynamicLightmap, rt); } }这种技术可以用于开放世界游戏的全局光照变化室内外混合场景的光照统一特殊天气效果的光照模拟性能敏感平台的静态光照优化5.3 性能与质量平衡动态光照烘焙需要在质量和性能之间找到平衡点烘焙频率根据光照变化速度调整分辨率选择大面积区域可用较低分辨率更新策略分帧更新不同区域混合技术与实时光照结合使用光照烘焙优化策略对比表策略优点缺点适用场景全场景每帧烘焙最高质量性能消耗大小场景或高端设备分区域轮换烘焙平衡性能可能有不一致中型场景时间或事件触发性能最优更新不及时变化缓慢的场景低分辨率烘焙性能好细节损失背景或远处区域
别再只把RenderTexture当截图工具了!Unity中这5个实战用法让你的游戏效果翻倍
发布时间:2026/5/26 5:52:22
别再只把RenderTexture当截图工具了Unity中这5个实战用法让你的游戏效果翻倍在Unity开发中RenderTexture常被简单地用作截图或后视镜的实现工具这无疑是对其强大功能的一种浪费。RenderTexture本质上是一个动态的、可编程的渲染画布能够将任何3D场景、特效或UI元素实时渲染到纹理上。这种特性为游戏开发打开了无数创意可能性的大门。本文将带你探索RenderTexture在游戏开发中的五种高级应用场景从动态环境反射到交互式UI从Shader特效到移动端优化再到动态光照烘焙每个案例都配有实用的代码片段和性能优化建议。1. 动态环境反射超越传统镜面效果大多数开发者使用RenderTexture实现简单的镜面或后视镜效果但它的潜力远不止于此。通过巧妙结合RenderTexture和Shader我们可以创造出令人惊叹的动态环境反射效果比如逼真的水面倒影或金属表面反射。1.1 实现动态水面反射传统的水面反射往往使用平面反射探针(Reflection Probe)但这种方法无法实时反映场景变化。使用RenderTexture可以创建完全动态的水面反射系统// 创建反射相机 Camera reflectionCamera new GameObject(ReflectionCamera).AddComponentCamera(); reflectionCamera.CopyFrom(mainCamera); reflectionCamera.enabled false; // 设置RenderTexture RenderTexture reflectionRT new RenderTexture(1024, 1024, 24); reflectionCamera.targetTexture reflectionRT; // 在LateUpdate中更新反射相机位置 void LateUpdate() { Vector3 cameraDirWorld mainCamera.transform.forward; Vector3 cameraUpWorld mainCamera.transform.up; Vector3 cameraPosWorld mainCamera.transform.position; // 计算反射相机位置和方向 float d -Vector3.Dot(waterPlane.normal, cameraPosWorld) - waterPlane.distance; Vector3 reflectionPos cameraPosWorld 2 * d * waterPlane.normal; reflectionCamera.transform.position reflectionPos; reflectionCamera.transform.LookAt(reflectionPos cameraDirWorld, cameraUpWorld); // 渲染到RenderTexture reflectionCamera.Render(); }在Shader中我们可以这样使用反射纹理sampler2D _ReflectionTex; float _ReflectionStrength; void surf (Input IN, inout SurfaceOutputStandard o) { // 基础颜色 fixed4 c tex2D(_MainTex, IN.uv_MainTex); // 反射颜色 float2 reflectionUV IN.screenPos.xy / IN.screenPos.w; fixed4 reflectionColor tex2D(_ReflectionTex, reflectionUV); // 混合基础色和反射色 o.Albedo c.rgb; o.Emission reflectionColor.rgb * _ReflectionStrength; o.Metallic _Metallic; o.Smoothness _Glossiness; }1.2 性能优化技巧动态反射虽然效果惊艳但对性能影响较大。以下是几个关键优化点分辨率控制反射不需要与原屏幕相同分辨率512x512甚至256x256通常就足够渲染层优化只反射必要的物体通过LayerMask过滤更新频率不需要每帧更新可以每2-3帧更新一次距离衰减根据相机与水面的距离调整反射质量反射质量与性能平衡参数表参数高质量设置平衡设置低性能消耗设置分辨率1024x1024512x512256x256更新频率每帧每2帧每3帧渲染距离100m50m30m反射物体全部主要场景关键物体抗锯齿4x MSAA2x MSAA关闭2. 交互式画中画UI与监控系统RenderTexture可以轻松实现游戏内的实时监控屏幕、安全摄像头或魔法镜子等效果。与简单的UI图片不同这些元素可以展示真实的游戏场景动态。2.1 创建动态监控屏幕public class SecurityCamera : MonoBehaviour { public RenderTexture cameraRT; public RawImage displayImage; private Camera securityCam; void Start() { // 创建安全摄像头 securityCam new GameObject(SecurityCamera).AddComponentCamera(); securityCam.targetTexture cameraRT; securityCam.cullingMask LayerMask.GetMask(SecurityView); securityCam.depth -10; // 确保在其他相机之前渲染 // 设置显示 displayImage.texture cameraRT; } void Update() { // 可以在这里添加摄像头移动或切换逻辑 } }2.2 高级应用多摄像头切换系统对于需要多个监控画面的游戏我们可以建立一个更复杂的系统public class SecuritySystem : MonoBehaviour { public RenderTexture[] cameraRTs; public RawImage[] displayScreens; public Camera[] securityCameras; private int currentRTIndex 0; void Start() { // 初始化所有摄像头和RenderTexture for(int i 0; i securityCameras.Length; i) { securityCameras[i].targetTexture cameraRTs[i]; securityCameras[i].enabled false; } // 启动第一个摄像头 SwitchCamera(0); } public void SwitchCamera(int index) { // 禁用当前摄像头 securityCameras[currentRTIndex].enabled false; // 启用新摄像头 currentRTIndex index; securityCameras[currentRTIndex].enabled true; // 更新所有屏幕显示 foreach(var screen in displayScreens) { screen.texture cameraRTs[currentRTIndex]; } } }提示对于监控系统可以考虑使用低帧率(15-20fps)来模拟真实监控效果同时节省性能。2.3 性能考量交互式UI系统需要考虑以下性能因素RenderTexture数量同时激活的RT越多性能消耗越大分辨率选择UI元素通常不需要高分辨率更新频率非关键UI可以降低更新频率Shader复杂度显示RT的材质应尽量简单3. Shader特效RenderTexture作为数据流RenderTexture不仅可以存储图像还可以作为自定义数据载体与Shader Graph结合创造出各种动态视觉效果。3.1 创建动态涂鸦墙想象一个玩家可以在墙面上实时涂鸦的效果public class GraffitiWall : MonoBehaviour { public RenderTexture graffitiRT; public Material wallMaterial; public BrushSettings brush; void Start() { // 初始化干净的涂鸦板 Graphics.Blit(Texture2D.whiteTexture, graffitiRT); wallMaterial.SetTexture(_GraffitiTex, graffitiRT); } void Update() { if(Input.GetMouseButton(0)) { RaycastHit hit; Ray ray Camera.main.ScreenPointToRay(Input.mousePosition); if(Physics.Raycast(ray, out hit) hit.collider.gameObject gameObject) { DrawAtPosition(hit.textureCoord); } } } void DrawAtPosition(Vector2 uv) { // 临时激活RT RenderTexture.active graffitiRT; // 设置绘制位置 GL.PushMatrix(); GL.LoadPixelMatrix(0, graffitiRT.width, graffitiRT.height, 0); // 绘制图形 Graphics.DrawTexture( new Rect(uv.x * graffitiRT.width - brush.size/2, (1-uv.y) * graffitiRT.height - brush.size/2, brush.size, brush.size), brush.texture, brush.mat); GL.PopMatrix(); RenderTexture.active null; } }在Shader Graph中我们可以这样使用涂鸦纹理创建Texture2D属性接收GraffitiTex使用Sample Texture 2D节点获取颜色与墙面基础色混合(如Multiply或Add)可以添加扭曲效果使涂鸦看起来更自然3.2 传送门扭曲效果RenderTexture非常适合实现传送门效果展示另一个场景的同时添加扭曲特效public class Portal : MonoBehaviour { public Transform linkedPortal; public Camera portalCamera; public RenderTexture portalRT; void Start() { portalCamera.targetTexture portalRT; GetComponentRenderer().material.SetTexture(_PortalTex, portalRT); } void Update() { // 更新传送门相机位置 Vector3 relativePos transform.InverseTransformPoint(Camera.main.transform.position); relativePos Vector3.Scale(relativePos, new Vector3(-1, 1, -1)); portalCamera.transform.position linkedPortal.TransformPoint(relativePos); // 更新旋转 Quaternion relativeRot Quaternion.Inverse(transform.rotation) * Camera.main.transform.rotation; portalCamera.transform.rotation linkedPortal.rotation * relativeRot; } }传送门Shader关键点使用RenderTexture作为基础纹理添加基于距离的扭曲效果(使用噪声纹理)边缘发光和粒子效果增强视觉冲击可以考虑添加时间参数实现动态扭曲4. 移动端优化智能使用低分辨率RT在移动设备上RenderTexture可以成为性能优化的利器特别是在后处理效果方面。4.1 低分辨率后处理全屏后处理在移动端代价高昂但通过RenderTexture我们可以实现智能降级public class MobilePostProcessing : MonoBehaviour { public Camera mainCamera; public Material postProcessMaterial; [Range(0.1f, 1f)] public float resolutionScale 0.5f; private RenderTexture halfResRT; void OnEnable() { int width (int)(Screen.width * resolutionScale); int height (int)(Screen.height * resolutionScale); halfResRT new RenderTexture(width, height, 0, RenderTextureFormat.DefaultHDR); mainCamera.targetTexture halfResRT; } void OnRenderImage(RenderTexture src, RenderTexture dest) { if(postProcessMaterial ! null) { Graphics.Blit(halfResRT, dest, postProcessMaterial); } else { Graphics.Blit(halfResRT, dest); } } void OnDisable() { mainCamera.targetTexture null; if(halfResRT ! null) { halfResRT.Release(); } } }4.2 动态分辨率调整根据设备性能动态调整RT分辨率public class DynamicResolution : MonoBehaviour { public float minScale 0.3f; public float maxScale 1.0f; public float targetFPS 60f; public float adjustmentSpeed 0.1f; private float currentScale 1f; private RenderTexture dynamicRT; private Camera mainCam; void Start() { mainCam Camera.main; UpdateRT(); } void Update() { // 计算当前FPS与目标差距 float fpsDelta (1f / Time.unscaledDeltaTime) - targetFPS; float scaleDelta Mathf.Clamp(fpsDelta * adjustmentSpeed / targetFPS, -0.1f, 0.1f); // 调整分辨率比例 currentScale Mathf.Clamp(currentScale scaleDelta, minScale, maxScale); UpdateRT(); } void UpdateRT() { if(dynamicRT ! null) { dynamicRT.Release(); } int width (int)(Screen.width * currentScale); int height (int)(Screen.height * currentScale); dynamicRT new RenderTexture(width, height, 24); mainCam.targetTexture dynamicRT; } void OnDestroy() { if(dynamicRT ! null) { dynamicRT.Release(); } } }4.3 移动端RenderTexture最佳实践使用RenderTexture.GetTemporary避免频繁创建销毁RT选择合适的格式移动端通常使用RGB565或ARGB4444减少带宽Mipmap考虑根据需求开启或关闭抗锯齿移动端通常可以关闭或使用FXAA释放时机不再使用的RT及时释放5. 动态光照烘焙到纹理RenderTexture可以用于烘焙动态光照信息实现一些特殊效果或优化静态场景的光照表现。5.1 实时光照贴图烘焙public class LightmapBaker : MonoBehaviour { public RenderTexture lightmapRT; public Camera bakingCamera; public LayerMask bakingLayers; void Start() { BakeLightmap(); } public void BakeLightmap() { // 设置烘焙相机 bakingCamera.targetTexture lightmapRT; bakingCamera.cullingMask bakingLayers; bakingCamera.RenderWithShader(LightmapShader, RenderType); // 将烘焙结果应用到场景材质 foreach(var renderer in FindObjectsOfTypeRenderer()) { if(renderer.gameObject.layer bakingLayers) { renderer.material.SetTexture(_Lightmap, lightmapRT); } } } }对应的Shader需要专门编写来输出光照信息Shader Custom/LightmapBaker { SubShader { Tags { RenderTypeOpaque } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include UnityCG.cginc struct v2f { float4 pos : SV_POSITION; float3 worldPos : TEXCOORD0; float3 normal : TEXCOORD1; }; v2f vert (appdata_base v) { v2f o; o.pos UnityObjectToClipPos(v.vertex); o.worldPos mul(unity_ObjectToWorld, v.vertex).xyz; o.normal UnityObjectToWorldNormal(v.normal); return o; } fixed4 frag (v2f i) : SV_Target { // 计算简单光照 float3 lightDir normalize(_WorldSpaceLightPos0.xyz); float NdotL max(0, dot(i.normal, lightDir)); // 输出光照信息 return fixed4(NdotL, NdotL, NdotL, 1); } ENDCG } } }5.2 应用场景昼夜循环系统动态光照烘焙特别适合昼夜循环系统可以在不增加实时计算负担的情况下实现高质量的光照变化public class DayNightCycle : MonoBehaviour { public Light sunLight; public float dayDuration 300f; // 秒 public RenderTexture[] lightmapRTs; public int bakeInterval 30; // 帧 private float currentTime; private int frameCount; void Update() { currentTime Time.deltaTime / dayDuration; currentTime % 1f; // 更新太阳位置 sunLight.transform.rotation Quaternion.Euler(currentTime * 360f - 90f, 0, 0); // 定期烘焙光照 if(frameCount bakeInterval) { frameCount 0; BakeCurrentLighting(); } } void BakeCurrentLighting() { // 根据时间选择不同的RT交替使用 RenderTexture rt lightmapRTs[Time.frameCount % lightmapRTs.Length]; // 设置光照参到Shader Shader.SetGlobalVector(_SunDirection, sunLight.transform.forward); Shader.SetGlobalColor(_SunColor, sunLight.color * sunLight.intensity); // 执行烘焙 Graphics.Blit(null, rt, bakingMaterial); // 应用到场景 Shader.SetGlobalTexture(_DynamicLightmap, rt); } }这种技术可以用于开放世界游戏的全局光照变化室内外混合场景的光照统一特殊天气效果的光照模拟性能敏感平台的静态光照优化5.3 性能与质量平衡动态光照烘焙需要在质量和性能之间找到平衡点烘焙频率根据光照变化速度调整分辨率选择大面积区域可用较低分辨率更新策略分帧更新不同区域混合技术与实时光照结合使用光照烘焙优化策略对比表策略优点缺点适用场景全场景每帧烘焙最高质量性能消耗大小场景或高端设备分区域轮换烘焙平衡性能可能有不一致中型场景时间或事件触发性能最优更新不及时变化缓慢的场景低分辨率烘焙性能好细节损失背景或远处区域