在Unity的新PostProcessing堆栈的着色器中获得世界位置?

Phi*_*sen 6 shader unity-game-engine

如何在Unity的新PostProcessing着色器框架中获得所讨论像素的绝对xyz世界位置?非常感谢!

Shader "Hidden/Filter/Test" {
    HLSLINCLUDE
        #include "../../PostProcessing/Shaders/StdLib.hlsl"
        TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
        float4 Frag(VaryingsDefault i) : SV_Target {
            float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo);

            // what's the world position of this color pixel ...?

            return color;
        }
    ENDHLSL
    SubShader {
        Cull Off ZWrite Off ZTest Always
        Pass {
            HLSLPROGRAM
                #pragma vertex VertDefault
                #pragma fragment Frag
            ENDHLSL
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Sey*_*ali 6

Lece 在您的评论中说得对:

您缺少"UnityCG.cginc"大多数内置功能(包括访问UNITY_*宏)所需的 #include 。

但问题是,当您"UnityCG.cginc"在 Unity 内置着色器中使用 具有相同功能的后处理堆栈 2 冲突时,我决定在标准着色器统一中找到它:

统一归档着色器,你可以找到UNITY_MATRIX_MVPStandard\CGIncludes\UnityShaderVariables.cginc

#define UNITY_MATRIX_MVP mul(unity_MatrixVP, unity_ObjectToWorld)
Run Code Online (Sandbox Code Playgroud)

使用世界空间

Shader "Hidden/Filter/Test" {
    HLSLINCLUDE
        #include "../../PostProcessing/Shaders/StdLib.hlsl"
        #define UNITY_MATRIX_MVP mul(unity_MatrixVP, unity_ObjectToWorld)
        
        TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);

                struct v2f {
                  float4 vertex : SV_POSITION;
                  float3 worldPos : TEXCOORD0;
                  float2 texcoord : TEXCOORD1;
                  float2 texcoordStereo : TEXCOORD2;
              };

            struct appdata {
                  float4 vertex : POSITION;
              };

            v2f VertDefault(appdata v) {
                  v2f o;
  
                  o.worldPos = mul (unity_ObjectToWorld, v.vertex);
                  o.vertex = float4(v.vertex.xy, 0.0, 1.0);
                  o.texcoord = TransformTriangleVertexToUV(v.vertex.xy);

                #if UNITY_UV_STARTS_AT_TOP
                    o.texcoord = o.texcoord * float2(1.0, -1.0) + float2(0.0, 1.0);
                #endif

                    o.texcoordStereo = TransformStereoScreenSpaceTex(o.texcoord, 1.0);
                  return o;
              }

              float4 Frag(v2f i) : SV_Target {
                  float worldPos = i.worldPos;

                  float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo);

                  return float4(i.worldPos,1);
              }


            ENDHLSL
            SubShader {
            Cull Off ZWrite Off ZTest Always
            Pass {
            HLSLPROGRAM
                #pragma vertex VertDefault
                #pragma fragment Frag


            ENDHLSL
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

将世界位置添加到 StdLib.hlsl

您也可以将 worldpos 添加到StdLib.hlsl,您可以找到 It InPostProcessing-2\Assets\PostProcessing\Shaders然后更改这些行:

我修好了StdLib.hlsl,放在这里

#define UNITY_MATRIX_MVP mul(unity_MatrixVP, unity_ObjectToWorld)

struct VaryingsDefault
{
    float4 vertex : SV_POSITION;
    float2 texcoord : TEXCOORD0;
    float2 texcoordStereo : TEXCOORD1;
    float3 worldPos : TEXCOORD2;
};

VaryingsDefault VertDefault(AttributesDefault v)
{
    VaryingsDefault o;
    o.vertex = float4(v.vertex.xy, 0.0, 1.0);
    o.texcoord = TransformTriangleVertexToUV(v.vertex.xy);
    o.worldPos = mul (unity_ObjectToWorld, v.vertex);

#if UNITY_UV_STARTS_AT_TOP
    o.texcoord = o.texcoord * float2(1.0, -1.0) + float2(0.0, 1.0);
#endif

    o.texcoordStereo = TransformStereoScreenSpaceTex(o.texcoord, 1.0);

    return o;
}
Run Code Online (Sandbox Code Playgroud)

以这种方式使用世界空间很容易!

Shader "Hidden/Filter/Test" {
    HLSLINCLUDE
        #include "../../PostProcessing/Shaders/StdLib.hlsl"

        float4 Frag(VaryingsDefault i) : SV_Target {
            return float4(i.worldPos,1);//Using World Position!
        }


            ENDHLSL
            SubShader {
            Cull Off ZWrite Off ZTest Always
            Pass {
            HLSLPROGRAM
                #pragma vertex VertDefault
                #pragma fragment Frag


            ENDHLSL
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

更新

图片

https://www.youtube.com/watch?v=uMOOcmp6FrM

将此脚本附加到您的相机:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class DepthBuffToWorldPosDemo : MonoBehaviour
    {
        public Material material;
        private new Camera camera;
        private new Transform transform;
    
        private void Start()
        {
            camera = GetComponent<Camera>();
            transform = GetComponent<Transform>();
        }
    
         void OnRenderImage(RenderTexture source, RenderTexture destination)
        {
    
            // NOTE: code was ported from: https://gamedev.stackexchange.com/questions/131978/shader-reconstructing-position-from-depth-in-vr-through-projection-matrix
    
            var p = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false);
            p[2, 3] = p[3, 2] = 0.0f;
            p[3, 3] = 1.0f;
            var clipToWorld = Matrix4x4.Inverse(p * camera.worldToCameraMatrix) * Matrix4x4.TRS(new Vector3(0, 0, -p[2,2]), Quaternion.identity, Vector3.one);
            material.SetMatrix("clipToWorld", clipToWorld);
    
            Graphics.Blit(source, destination, material);
    
        }

}
Run Code Online (Sandbox Code Playgroud)

您可以使用 Unity 着色器或后处理着色器

统一着色器:

Shader "Hidden/DepthBuffToWorldPos"
{

    SubShader
    {
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 5.0
            
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float3 worldDirection : TEXCOORD1;
                float4 vertex : SV_POSITION;
            };

            float4x4 clipToWorld;

            v2f vert (appdata v)
            {
                v2f o;

                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;

                float4 clip = float4(o.vertex.xy, 0.0, 1.0);
                o.worldDirection = mul(clipToWorld, clip) - _WorldSpaceCameraPos;

                return o;
            }
            
            sampler2D_float _CameraDepthTexture;
            float4 _CameraDepthTexture_ST;

            float4 frag (v2f i) : SV_Target
            {
                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv.xy);
                depth = LinearEyeDepth(depth);
                float3 worldspace = i.worldDirection * depth + _WorldSpaceCameraPos;

                float4 color = float4(worldspace, 1.0);
                return color;
            }
            ENDCG
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

后处理堆栈着色器

Shader "Hidden/Filter/Test" {
        HLSLINCLUDE
             #include "../../PostProcessing/Shaders/StdLib.hlsl"
            #define UNITY_MATRIX_MVP mul(unity_MatrixVP, unity_ObjectToWorld)
            #include "HLSLSupport.cginc"
            #pragma fragmentoption ARB_precision_hint_nicest

            TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
            float4x4 clipToWorld;



                    struct v2f {
                      float4 vertex : SV_POSITION;
                     float3 worldDirection : TEXCOORD0;
                      float3 screenPos : TEXCOORD1;
                      float2 texcoord : TEXCOORD2;
                      float2 texcoordStereo : TEXCOORD3;

                  };
    
                struct appdata {
                      float4 vertex : POSITION;
                  };

                            sampler2D_float _CameraDepthTexture;
            float4 _CameraDepthTexture_ST;
    
                v2f VertDefault(appdata v) {
                      v2f o;
      
                      o.vertex = float4(v.vertex.xy, 0.0, 1.0);
                      o.texcoord = TransformTriangleVertexToUV(v.vertex.xy);

                                    float4 clip = float4(o.vertex.xy, 0.0, 1.0);
                o.worldDirection = mul(clipToWorld, clip) - _WorldSpaceCameraPos;
    
                    #if UNITY_UV_STARTS_AT_TOP
                        o.texcoord = o.texcoord * float2(1.0, -1.0) + float2(0.0, 1.0);
                    #endif

                      // Correct flip when rendering with a flipped projection matrix.
                      // (I've observed this differing between the Unity scene & game views)
                      o.screenPos.y *= _ProjectionParams.x;
                      o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                      o.screenPos = o.vertex.xyw;
    
                        o.texcoordStereo = TransformStereoScreenSpaceTex(o.texcoord, 1.0);
                      return o;
                  }
    
                  float4 Frag(v2f i) : SV_Target {
                float2 screenUV = (i.screenPos.xy / i.screenPos.z) * 0.5f + 0.5f;
                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,screenUV);
                depth = LinearEyeDepth(depth);
                float3 worldspace = i.worldDirection * depth + _WorldSpaceCameraPos;
                
                float4 color = float4(worldspace, 1.0);
                return color;
                  }
    
    
                ENDHLSL
                SubShader {
                Cull Off ZWrite Off ZTest Always
                Pass {
                HLSLPROGRAM
                    #pragma vertex VertDefault
                    #pragma fragment Frag
    
    
                ENDHLSL
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

将世界位置添加到 StdLib.hlsl

标准库固定文件

#define UNITY_MATRIX_MVP mul(unity_MatrixVP, unity_ObjectToWorld)
#include "HLSLSupport.cginc"
#pragma fragmentoption ARB_precision_hint_nicest

float4x4 clipToWorld;


struct VaryingsDefault
{
float4 vertex : SV_POSITION;
float3 worldDirection : TEXCOORD0;
float3 screenPos : TEXCOORD1;
float2 texcoord : TEXCOORD2;
float2 texcoordStereo : TEXCOORD3;
};



    sampler2D_float _CameraDepthTexture;
float4 _CameraDepthTexture_ST;



VaryingsDefault VertDefault(AttributesDefault v)
{
VaryingsDefault o;

o.vertex = float4(v.vertex.xy, 0.0, 1.0);
o.texcoord = TransformTriangleVertexToUV(v.vertex.xy);

float4 clip = float4(o.vertex.xy, 0.0, 1.0);
o.worldDirection = mul(clipToWorld, clip) - _WorldSpaceCameraPos;

#if UNITY_UV_STARTS_AT_TOP
o.texcoord = o.texcoord * float2(1.0, -1.0) + float2(0.0, 1.0);
#endif

// Correct flip when rendering with a flipped projection matrix.
// (I've observed this differing between the Unity scene & game views)
o.screenPos.y *= _ProjectionParams.x;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.screenPos = o.vertex.xyw;


o.texcoordStereo = TransformStereoScreenSpaceTex(o.texcoord, 1.0);
return o;
}
Run Code Online (Sandbox Code Playgroud)

以这种方式使用世界空间很容易!

Shader "Hidden/Filter/Test" {
        HLSLINCLUDE
            #include "../StdLib.hlsl"
           
    
                  float4 Frag(v2f i) : SV_Target {
                float2 screenUV = (i.screenPos.xy / i.screenPos.z) * 0.5f + 0.5f;
                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,screenUV);
                depth = LinearEyeDepth(depth);
                float3 worldspace = i.worldDirection * depth + _WorldSpaceCameraPos;
                
                float4 color = float4(worldspace, 1.0);
                return color;
                  }
    
    
                ENDHLSL
                SubShader {
                Cull Off ZWrite Off ZTest Always
                Pass {
                HLSLPROGRAM
                    #pragma vertex VertDefault
                    #pragma fragment Frag
    
    
                ENDHLSL
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)