【问题标题】:Get world position in shader of Unity's new PostProcessing stack?在 Unity 的新 PostProcessing 堆栈的着色器中获取世界位置?
【发布时间】:2018-05-13 02:23:05
【问题描述】:

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

【问题讨论】:

  • 如果传入一个深度缓冲区,可以反转相机的投影矩阵来计算每个片段的世界位置。
  • 伊恩,谢谢,我的问题是,每当我尝试从这些不同的示例中复制和粘贴时,我都会收到大量随机错误(例如,现在点击您的链接,“未声明的标识符 'UNITY_MATRIX_MVP'在第 27 行(在 d3d11 上)”,但这只是其中之一),而且我正在一个接一个地陷入错误的兔子洞。您是否碰巧有一个适用于 PostProcessing2Beta 框架的完整示例?
  • Rutter,听起来很有趣,你有工作代码示例吗?谢谢!
  • 我目前没有过多地使用着色器,所以不,我没有示例。但是 未声明的标识符 错误可能是由于 Unity 已丢弃它并用其他东西替换它。

标签: unity3d shader


【解决方案1】:

Lece 在你的 cmets 中说得对:

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

但问题是当您在 Unity 内置着色器中使用 "UnityCG.cginc" PostProcessing stack 2 与相同功能冲突时。所以我决定在标准着色器统一中找到它:

Unity Archive shader 你可以找到UNITY_MATRIX_MVPStandard\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

您也可以将 worldpos 添加到 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;
}

这样使用世界空间很容易!

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

更新

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 着色器或后处理着色器

统一着色器:

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

这样使用世界空间很容易!

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

【讨论】:

  • 谢谢!但是现在我不能再让“i.texcoordStereo”来获取该世界位置的颜色,如“float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo);”?请帮忙?
  • 另一个问题,我需要把UnityShaderVariables.cginc放到我的项目中吗?还是只是为了参考/信息,我不需要它?
  • @PhilippLenssen 不,我只是在上面的着色器中使用#define UNITY_MATRIX_MVP mul(unity_MatrixVP, unity_ObjectToWorld)。测试上面的着色器之一它应该可以正常工作。
  • @PhilippLenssen 我已修复它请测试它。
  • 谢谢!这修复了 textcoordStereo 找不到的问题,但 i.worldPos 现在仍然不适用于固定的绝对 worldPos - 但适用于相对屏幕位置,基于相机指向的位置。因此,如果我使用以下示例,那么它将始终将相机视图的下半部分涂成黑色,与实际对象世界位置无关: float4 Frag(v2f i) : SV_Target { float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i .texcoordStereo); if (i.worldPos.y > 0) { color = float4(0,0,0,1); } 返回颜色; } 帮助?
【解决方案2】:

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

我使用此处详述的旧方法(未与后处理堆栈集成)进行了测试,这很有效。 - https://github.com/zezba9000/UnityMathReference/tree/master/Assets/Shaders/DepthBuffToWorldPos

在后处理堆栈中重新创建相同的结果给了我不同的结果。经过一番摸索,我发现唯一不同的数据是i.worldDirection,默认情况下它基于v.vertex.xy。我将其更改为 i.texcoord.xy*2-1,它非常适合我。


这里是代码(cs+shader)

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

【讨论】:

  • i.texcoord.xy*2-1 也为我工作。但现在我不知道我在做什么。即使是最初的“DepthBuffToWorldPos”也充满了魔力,但现在感觉我真的只是在添加随机乘法。 ?
  • 这有点奇怪,因为TransformTriangleVertexToUv 正好相反:float2 uv = (vertex + 1.0) * 0.5; 所以我猜使用v.vertex.xy 会起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-14
  • 2018-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多