Raymarching着色器以RenderTexture为目标时无法渲染的问题
Unity Raymarching体积渲染RenderTexture无输出问题修复
问题描述
从Unity官方Texture3D文档获取的Raymarching着色器,直接挂载到材质并赋予Texture3D后可正常渲染;但通过相机渲染到RenderTexture时,RenderTexture无任何内容输出。
材质渲染结果

RenderTexture渲染结果

问题原因分析
- 射线方向计算错误:Shader中转换世界空间向量到物体空间时,错误使用点向量(w=1)而非方向向量(w=0),导致射线方向被物体平移变换干扰,无法正确进入体积采样范围。
- RenderTexture资源未释放:脚本中每次创建临时RenderTexture但未释放,易引发资源泄漏和渲染状态异常。
- 着色器参数传递不全:使用
RenderWithShader时仅全局设置了_Texture3D,_Alpha、_StepSize等参数未赋值,可能影响采样叠加效果。
修复方案
1. 修复Shader射线方向计算
修改Shader中vert函数内的射线方向代码:
原代码:
float3 rayDirection = mul(unity_WorldToObject, float4(normalize(i.vectorToSurface), 1));
修改为:
float3 rayDirection = mul(unity_WorldToObject, float4(normalize(i.vectorToSurface), 0));
解释:方向向量无需平移变换,将w分量设为0,确保矩阵乘法仅应用旋转和缩放,避免射线方向偏移。
2. 修复脚本RenderTexture资源泄漏
在OnRenderImage方法的Graphics.Blit后添加释放代码:
Graphics.Blit(m_volumeTex, dst); // 释放临时RenderTexture RenderTexture.ReleaseTemporary(m_volumeTex);
3. 完善着色器参数传递(可选)
若需自定义采样参数,在脚本中添加全局参数设置:
// 在Shader.SetGlobalTexture之后添加 Shader.SetGlobalFloat("_Alpha", alpha); // alpha为自定义变量 Shader.SetGlobalFloat("_StepSize", stepSize); // stepSize为自定义变量
完整修复后的Shader代码
Shader "Test/basic_VolumeRendering" { Properties { _Texture3D("Texture3D", 3D) = "white" {} _Alpha("Alpha", float) = 0.02 _StepSize("Step Size", float) = 0.01 } SubShader { Tags { "Queue" = "Transparent" "RenderType" = "Transparent" } Blend One OneMinusSrcAlpha LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #define MAX_STEP_COUNT 128 #define EPSILON 0.00001f struct appdata { float4 vertex : POSITION; }; struct v2f { float4 vertex : SV_POSITION; float3 objectVertex : TEXCOORD0; float3 vectorToSurface : TEXCOORD1; }; sampler3D _Texture3D; float4 _MainTex_ST; float _Alpha; float _StepSize; v2f vert(appdata v) { v2f o; o.objectVertex = v.vertex; float3 worldVertex = mul(unity_ObjectToWorld, v.vertex).xyz; o.vectorToSurface = worldVertex - _WorldSpaceCameraPos; o.vertex = UnityObjectToClipPos(v.vertex); return o; } float4 BlendUnder(float4 color, float4 newColor) { color.rgb += (1.0 - color.a) * newColor.a * newColor.rgb; color.a += (1.0 - color.a) * newColor.a; return color; } fixed4 frag(v2f i) : SV_Target { float3 rayOrigin = i.objectVertex; float3 rayDirection = mul(unity_WorldToObject, float4(normalize(i.vectorToSurface), 0)); float4 color = float4(0, 0, 0, 0); float3 samplePosition = rayOrigin; for (int stepIdx = 0; stepIdx < MAX_STEP_COUNT; stepIdx++) { if (max(abs(samplePosition.x), max(abs(samplePosition.y), abs(samplePosition.z))) < 0.5f + EPSILON) { float4 sampledColor = tex3D(_Texture3D, samplePosition + float3(0.5f, 0.5f, 0.5f)); sampledColor.a *= _Alpha; color = BlendUnder(color, sampledColor); samplePosition += rayDirection * _StepSize; } } return color; } ENDCG } } }
完整修复后的脚本代码
using UnityEngine; [ExecuteInEditMode] public class Volume_Renderer_Debug : MonoBehaviour { public Shader volumeShader; public Texture3D data; public float alpha = 0.02f; public float stepSize = 0.01f; private Camera m_camera = null; private Camera m_cameraCopy = null; private GameObject cameraCopyObj = null; void Awake() { m_camera = GetComponent<Camera>(); if (cameraCopyObj != null) { DestroyImmediate(cameraCopyObj); } cameraCopyObj = new GameObject("cameraCopy"); cameraCopyObj.hideFlags = HideFlags.DontSave; cameraCopyObj.transform.parent = transform; cameraCopyObj.transform.localPosition = Vector3.zero; m_cameraCopy = cameraCopyObj.AddComponent<Camera>(); m_cameraCopy.CopyFrom(m_camera); m_cameraCopy.clearFlags = CameraClearFlags.SolidColor; m_cameraCopy.enabled = false; } void OnDestroy() { DestroyImmediate(cameraCopyObj); } void OnPreRender() { m_camera.cullingMask = 0; } void OnRenderImage(RenderTexture src, RenderTexture dst) { RenderTexture m_volumeTex = RenderTexture.GetTemporary(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); m_cameraCopy.targetTexture = m_volumeTex; m_cameraCopy.backgroundColor = new Color(0.7f, 0.5f, 0.7f, 0.0f); m_cameraCopy.clearFlags = CameraClearFlags.Color; m_cameraCopy.cullingMask = 1 << LayerMask.NameToLayer("Volume"); Shader.SetGlobalTexture("_Texture3D", data); Shader.SetGlobalFloat("_Alpha", alpha); Shader.SetGlobalFloat("_StepSize", stepSize); m_cameraCopy.RenderWithShader(volumeShader, null); Graphics.Blit(m_volumeTex, dst); RenderTexture.ReleaseTemporary(m_volumeTex); } }
内容的提问来源于stack exchange,提问作者HTTRCH
相关产品推荐
相关产品推荐

