Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

World Space position in a post processing shader

Discussion in 'Shaders' started by Chickenlord, Dec 5, 2011.

  1. Chickenlord

    Chickenlord

    Joined:
    May 13, 2011
    Posts:
    381
    Hi,

    how can i get the world space position based on the uvs and the depth in a post processing shader? In a script you have the ViewportToWorldPoint method which does the job and i assumed the cameraToWorldMatrix would help me out. But strangely it doesn't. So if anybody knows how to get this working, it would be quite nice.

    Cheers
    Chicken
     
  2. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
  3. Chickenlord

    Chickenlord

    Joined:
    May 13, 2011
    Posts:
    381
    Thanks a lot. Looks like i missed this thread before. Hopefully this will solve all my problems :D
     
  4. ArminRigo

    ArminRigo

    Joined:
    May 19, 2017
    Posts:
    19
    This is quite an old question with various responses, but I failed to find one that works. Here is an approach that worked for me, including with VR, to find the world position for every pixel in a post-processing shader.

    NOTE: this does not work with the single-pass rendering of stereo.

    1. make sure the camera renders the depth texture (a depth+normals texture probably works too, but has got less depth precision):

    Code (CSharp):
    1.  
    2.         GetComponent<Camera>().depthTextureMode = DepthTextureMode.Depth;
    3.  
    2. send the inverse projection*view matrix to the shader---this is written inside a MonoBehaviour component attached to the camera, and ``mat`` is a material with your shader:

    Code (CSharp):
    1.  
    2.     private void OnRenderImage(RenderTexture source, RenderTexture destination)
    3.     {
    4.         var camera = GetComponent<Camera>();
    5.         mat.SetMatrix("_ViewProjectInverse", (camera.projectionMatrix * camera.worldToCameraMatrix).inverse);
    6.  
    7.         Graphics.Blit(source, destination, mat);
    8.     }
    9.  
    3. the shader itself:

    Code (CSharp):
    1.  
    2. Shader "Hidden/NewImageEffectShader"
    3. {
    4.     Properties{
    5.         _MainTex("Base (RGB)", 2D) = "white" {}
    6.     }
    7.     SubShader{
    8.         Pass{
    9.             CGPROGRAM
    10.             #pragma vertex vert
    11.             #pragma fragment frag
    12.             #include "UnityCG.cginc"
    13.             sampler2D _MainTex;
    14.             sampler2D _CameraDepthTexture;
    15.             float4x4 _ViewProjectInverse;
    16.  
    17.             struct appdata {
    18.                 float4 vertex : POSITION;
    19.                 float2 uv : TEXCOORD0;
    20.             };
    21.             struct v2f {
    22.                 float4 pos : SV_POSITION;
    23.                 float2 uv : TEXCOORD0;
    24.                 float3 worldDirection : TEXCOORD1;
    25.             };
    26.          
    27.             v2f vert(appdata i)
    28.             {
    29.                 v2f o;
    30.                 o.pos = UnityObjectToClipPos(i.vertex);
    31.                 o.uv = i.uv;
    32.                 float4 D = mul(_ViewProjectInverse, float4((i.uv.x) * 2 - 1, (i.uv.y) * 2 - 1, 0.5, 1));
    33.                 D.xyz /= D.w;
    34.                 D.xyz -= _WorldSpaceCameraPos;
    35.                 float4 D0 = mul(_ViewProjectInverse, float4(0, 0, 0.5, 1));
    36.                 D0.xyz /= D0.w;
    37.                 D0.xyz -= _WorldSpaceCameraPos;
    38.                 o.worldDirection = D.xyz / length(D0.xyz);
    39.                 return o;
    40.             }
    41.             float4 frag(v2f i) : COLOR
    42.             {
    43.                 float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
    44.                 depth = LinearEyeDepth(depth);
    45.                 /* World position of some random point along this ray */
    46.                 float3 WD = i.worldDirection;
    47.                 /* Multiply by 'depth' */
    48.                 WD *= depth;
    49.                 /* That's our world-coordinate position! */
    50.                 float3 W = WD + _WorldSpaceCameraPos;
    51.              
    52.                 /* Demo: multiply the pixel by frac(W.x), giving x-aligned bands of shadow */
    53.                 float4 c = tex2D(_MainTex, i.uv);
    54.                 c.rgb *= frac(W.x);
    55.                 return c;
    56.             }
    57.             ENDCG
    58.         }
    59.     }
    60. }
    61.  
     
    Last edited: Jun 27, 2018
    chingwa and Przemyslaw_Zaworski like this.
  5. chingwa

    chingwa

    Joined:
    Dec 4, 2009
    Posts:
    3,789
    @ArminRigo Thanks! I had been using a custom Blit() function to calculate worldPosition in post-process for a long time, but could not use my custom Blit in a Command Buffer, so had to find a different method for that. This worked perfectly!