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

时间:2018-03-23 15:52:51

标签: unity3d shader

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
        }
    }
}

2 个答案:

答案 0 :(得分:4)

Lece在你的评论中说道:

  

您错过了#include "UnityCG.cginc",这是大多数内置功能所必需的,包括访问UNITY_*宏。

但问题是当你使用"UnityCG.cginc" PostProcessing堆栈2使用相同的函数时,在Unity内置着色器中,我决定在标准着色器统一中找到它:

Unity Archive shader中,您可以在UNITY_MATRIX_MVP

中找到Standard\CGIncludes\UnityShaderVariables.cginc
#define UNITY_MATRIX_MVP mul(unity_MatrixVP, unity_ObjectToWorld)

使用世界空间

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
        }
    }
}

将世界位置添加到StdLib.hlsl

此外,您可以将世界广告添加到StdLib.hlsl,您可以在PostProcessing-2\Assets\PostProcessing\Shaders中找到它然后更改这些行:

我修复了StdLib.hlsl,然后我放了here

#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;
}

这样使用World Space很容易!

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
        }
    }
}

更新

Image

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);

        }

}

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

Unity Shader:

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
        }
    }
}

后处理堆栈着色器

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
            }
        }
    }

将世界位置添加到StdLib.hlsl

StdLibFixed.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;
}

这样使用World Space很容易!

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
            }
        }
    }

答案 1 :(得分:3)

我有很多问题,不确定这是否适合所有人(在2017.3.1p1测试Mac w / Metal)但我遇到了与上述相同的问题 - 移动或旋转相机会导致世界空间位置变化非常奇怪。

我使用旧方法(未与Post Processing堆栈集成)进行测试,这里有详细说明。 - https://github.com/zezba9000/UnityMathReference/tree/master/Assets/Shaders/DepthBuffToWorldPos

在Post Processing堆栈中重新创建它会给我带来不同的结果。经过一番探讨,我发现唯一不同的数据是i.worldDirection,默认情况下基于v.vertex.xy。我将其更改为i.texcoord.xy*2-1,这对我来说非常有效。

以下是代码(cs +着色器)

DrawWorldSpacePosition.cs

using System;
using UnityEngine;
using UnityEngine.Rendering.PostProcessing;

[Serializable]
[PostProcess(typeof(DrawWorldSpacePositionRenderer), PostProcessEvent.AfterStack, "Custom/DrawWorldSpacePosition")]
public sealed class DrawWorldSpacePosition : PostProcessEffectSettings
{
}

public sealed class DrawWorldSpacePositionRenderer : PostProcessEffectRenderer<DrawWorldSpacePosition>
{
    public override void Render(PostProcessRenderContext context)
    {
        var sheet = context.propertySheets.Get(Shader.Find("Hidden/Custom/DrawWorldSpacePosition"));

        var camera = context.camera;

        var p = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false);// Unity flips its 'Y' vector depending on if its in VR, Editor view or game view etc... (facepalm)
        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);
        sheet.properties.SetMatrix("clipToWorld", clipToWorld);

        context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
    }
}

DrawWorldSpacePosition.shader

Shader "Hidden/Custom/DrawWorldSpacePosition"
{
    HLSLINCLUDE

        #include "../PostProcessing/Shaders/StdLib.hlsl"

        TEXTURE2D_SAMPLER2D(_CameraDepthTexture, sampler_CameraDepthTexture);

        uniform float4x4 clipToWorld;

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

        VaryingsExtended Vert(AttributesDefault v)
        {
            VaryingsExtended o;
            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);

            float4 clip = float4(o.texcoord.xy*2-1, 0.0, 1.0);
            o.worldDirection = mul(clipToWorld, clip) - _WorldSpaceCameraPos;
            return o;
        }

        float4 Frag(VaryingsExtended i) : SV_Target
        {
            float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, i.texcoordStereo);
            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 Vert
                #pragma fragment Frag

            ENDHLSL
        }
    }
}