RayMarching-渲染3D纹理时的伪影

发布于 2025-01-17 18:01:59 字数 4341 浏览 0 评论 0原文

我正在为客户开发一个项目,并尝试复制在 Unity Inspector 中完成的 3D 体渲染,以便我可以实时查看 3D 体数据的更改。 以下是最终输出的示例(有或没有透明度): https://i.sstatic.net/NtVbv.jpg 然而,当我使用 Unity 提供的默认 Raymarching 着色器的稍微修改版本进行实时渲染时 - 我的结果完全不同。 https://i.sstatic.net/0K2YA.jpg 以下是用于渲染 3D 纹理的着色器代码:

 Shader "Unlit/3DVolumeShader"
 {
 Properties
 {
     _Alpha ("Alpha", float) = 0.8
     _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 TEX_WIDTH 512
         #define TEX_HEIGHT 64
         #define TEX_LENGTH 384

         // Maximum amount of raymarching samples
         #define MAX_STEP_COUNT 128

         // Allowed floating point inaccuracy for hit detection
         #define EPSILON 0.00001f

         struct appdata
         {
             float4 vertex : POSITION;
         };

         struct v2f
         {
             float4 vertex : SV_POSITION;
             float3 objectVertex : TEXCOORD0;
             float3 vectorToSurface : TEXCOORD1;
         };

         float _Alpha;
         float _StepSize;

         StructuredBuffer<float4> DensityMap;
         
         v2f vert (appdata v)
         {
             v2f o;

             // Vertex in object space this will be the starting point of raymarching
             o.objectVertex = v.vertex;

             // Convert vertex in object space to camera coordinates
             o.vertex = UnityObjectToClipPos(v.vertex);

             // Calculate vector from camera to vertex in world space
             float3 worldVertex = mul(unity_ObjectToWorld, v.vertex).xyz;
             o.vectorToSurface = worldVertex - _WorldSpaceCameraPos;

             return o;
         }

         // This method blends colors based on their alpha transparency
         // If color.a == 1 then no blending will occur
         // Otherwise multiply the difference in the alpha's by the new color
         float4 BlendColors(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
         {
             // Start raymarching at the front surface of the object
             float3 rayOrigin = i.objectVertex;

             // Use vector from camera to object surface to get the ray direction
             float3 rayDirection = mul(unity_WorldToObject, float4(normalize(i.vectorToSurface), 1));

             float4 color = float4(0, 0, 0, 0);

             float3 bounds = float3(TEX_WIDTH, TEX_LENGTH, TEX_HEIGHT);
             float3 samplePosition = rayOrigin;

             // Raymarch through object space
             for (int i = 0; i < MAX_STEP_COUNT; i++)
             {
                 // Accumulate color only within unit cube bounds
                 if(max(abs(samplePosition.x), max(abs(samplePosition.y), abs(samplePosition.z))) < 0.5f + EPSILON)
                 {
                     // Sample the color at the position in our density map. Add an offset for UV coordinate transformation.
                     // float4 sampledColor = tex3D(_DensityMap, samplePosition + float3(0.5f, 0.5f, 0.5f));

                     float3 textureCoord = (samplePosition + float3(0.5f, 0.5f, 0.5f)) * bounds;
                     int index = int(textureCoord.x) + (int(textureCoord.y) * bounds.x) + (int(textureCoord.z) * bounds.x * bounds.y);

                     float4 sampledColor = DensityMap[index];
                     sampledColor.a *= _Alpha;

                     // Blend the colors based on alpha transparency
                     color = BlendColors(color, sampledColor);

                     samplePosition += rayDirection * _StepSize;
                 }
             }

             return color;
         }
         ENDCG
     }
 }
 }

我正在使用 raymarching 索引 3D 纹理数组,我认为这就是可能发生此问题的地方。我想知道 Unity 使用的缩放/坐标系统是否有问题。 我的纹理大小是 512x64x384,我正在渲染到缩放比例为 1x0.1x0.75 的立方体。 如果需要任何其他信息来解决此问题,请告诉我。

I am working on a project for a client and I am trying to replicate the 3D volume rendering done in the Unity Inspector so I can view changes to 3D volume data in real-time.
Here is an example of what the final output should look like (with and without transparency):
https://i.sstatic.net/NtVbv.jpg
However, when I render this in real-time using a slightly modified version of the default Raymarching shader provided by Unity - my results are quite different.
https://i.sstatic.net/0K2YA.jpg
Here is the shader code being used to render the 3D texture:

 Shader "Unlit/3DVolumeShader"
 {
 Properties
 {
     _Alpha ("Alpha", float) = 0.8
     _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 TEX_WIDTH 512
         #define TEX_HEIGHT 64
         #define TEX_LENGTH 384

         // Maximum amount of raymarching samples
         #define MAX_STEP_COUNT 128

         // Allowed floating point inaccuracy for hit detection
         #define EPSILON 0.00001f

         struct appdata
         {
             float4 vertex : POSITION;
         };

         struct v2f
         {
             float4 vertex : SV_POSITION;
             float3 objectVertex : TEXCOORD0;
             float3 vectorToSurface : TEXCOORD1;
         };

         float _Alpha;
         float _StepSize;

         StructuredBuffer<float4> DensityMap;
         
         v2f vert (appdata v)
         {
             v2f o;

             // Vertex in object space this will be the starting point of raymarching
             o.objectVertex = v.vertex;

             // Convert vertex in object space to camera coordinates
             o.vertex = UnityObjectToClipPos(v.vertex);

             // Calculate vector from camera to vertex in world space
             float3 worldVertex = mul(unity_ObjectToWorld, v.vertex).xyz;
             o.vectorToSurface = worldVertex - _WorldSpaceCameraPos;

             return o;
         }

         // This method blends colors based on their alpha transparency
         // If color.a == 1 then no blending will occur
         // Otherwise multiply the difference in the alpha's by the new color
         float4 BlendColors(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
         {
             // Start raymarching at the front surface of the object
             float3 rayOrigin = i.objectVertex;

             // Use vector from camera to object surface to get the ray direction
             float3 rayDirection = mul(unity_WorldToObject, float4(normalize(i.vectorToSurface), 1));

             float4 color = float4(0, 0, 0, 0);

             float3 bounds = float3(TEX_WIDTH, TEX_LENGTH, TEX_HEIGHT);
             float3 samplePosition = rayOrigin;

             // Raymarch through object space
             for (int i = 0; i < MAX_STEP_COUNT; i++)
             {
                 // Accumulate color only within unit cube bounds
                 if(max(abs(samplePosition.x), max(abs(samplePosition.y), abs(samplePosition.z))) < 0.5f + EPSILON)
                 {
                     // Sample the color at the position in our density map. Add an offset for UV coordinate transformation.
                     // float4 sampledColor = tex3D(_DensityMap, samplePosition + float3(0.5f, 0.5f, 0.5f));

                     float3 textureCoord = (samplePosition + float3(0.5f, 0.5f, 0.5f)) * bounds;
                     int index = int(textureCoord.x) + (int(textureCoord.y) * bounds.x) + (int(textureCoord.z) * bounds.x * bounds.y);

                     float4 sampledColor = DensityMap[index];
                     sampledColor.a *= _Alpha;

                     // Blend the colors based on alpha transparency
                     color = BlendColors(color, sampledColor);

                     samplePosition += rayDirection * _StepSize;
                 }
             }

             return color;
         }
         ENDCG
     }
 }
 }

I am using raymarching to index into the 3D texture array, which is where I think this issue might be occurring. I'm wondering if I might have something wrong with the scaling/coordinate system that Unity uses.
My texture size is 512x64x384 and I am rendering to a cube with scaling 1x0.1x0.75.
Please let me know if there is any additional information required to solve this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文