web-dev-qa-db-ja.com

Unityの新しいPostProcessingスタックのシェーダーで世界の位置を取得しますか?

Unityの新しいPostProcessingシェーダーフレームワークの1つは、問題のピクセルの絶対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
        }
    }
}
6
Philipp Lenssen

Leceはあなたのコメントで正しく言った:

"UnityCG.cginc"マクロへのアクセスを含むほとんどの組み込み機能に必要な#includeUNITY_*がありません。

しかし、問題は、"UnityCG.cginc" PostProcessingスタック2を使用する場合、Unityの組み込みシェーダーで同じ関数と競合するため、標準のシェーダーユニティで見つけることにしました。

nity Archiveシェーダー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を修正し、 ここ

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

更新

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

私はこれに関して多くの問題を抱えていて、これがすべての人にとっての修正であるかどうかはわかりません(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 +シェーダー)

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