Search Unity

Render Texture Distance to World Pos

Discussion in 'Shaders' started by Lycake, Feb 1, 2020.

  1. Lycake

    Lycake

    Joined:
    Jun 8, 2013
    Posts:
    7
    Hello,

    I am using a shader on a render texture. I only want that effect, if the vertex is in range of a specific point in the scene. For that to work, I need to know the original world position of that vertex/pixel.

    As far as I can tell, I need to calculate from the screenspace back to worldspace. For that I guess I need something like a Camera2World and projection matrix that I give via scipt to the shader, aswell as the depth to that pixel from the camera and then... do some calculations. However, I am at a loss at what matrix I need to give to the shader exactly, how to get the depth to a pixel and how to calculate it properly.

    I tried to use camera.cameraToWorldMatrix together with something like LinearEyeDepth of the _CameraDepthTexture, but I can't seem to get it to work. I find it really difficult to debug shaders :/

    Any help would be much appreciated.
    Thank you!
     
  2. Namey5

    Namey5

    Joined:
    Jul 5, 2013
    Posts:
    188
    To find the world space position of a pixel in a post-processing shader (which is how I read this scenario), you can find the view-space positions of the 4 far-plane frustum corners in the vertex shader (so that they will be blended per-fragment, thus giving us per-pixel view directions). Multiplying this by [0,1] linear depth gives you the view-space position of the pixel, which can then be transformed to world space, i.e;

    Code (CG):
    1. ...
    2.  
    3. float4x4 _InvProjectionMatrix;    //Pass this in via 'camera.projectionMatrix.inverse'
    4. float4x4 _ViewToWorld;    //Pass this in via 'camera.cameraToWorldMatrix'
    5.  
    6. struct v2f
    7. {
    8.     float4 pos : SV_POSITION;
    9.     float2 uv : TEXCOORD0;
    10.     float4 viewDir : TEXCOORD1;
    11. };
    12.  
    13. v2f vert (appdata v)
    14. {
    15.     v2f o;
    16.     o.pos = UnityObjectToClipPos (v.vertex);
    17.     o.uv = v.uv;
    18.     o.viewDir = mul (_InvProjectionMatrix, float4 (o.uv * 2.0 - 1.0, 1.0, 1.0));
    19.     return o;
    20. }
    21.  
    22. half4 frag (v2f i) : SV_Target
    23. {
    24.     float depth = Linear01Depth (tex2D (_CameraDepthTexture, i.uv).r);
    25.  
    26.     //Perspective divide and scale by depth to get view-space position
    27.     float3 viewPos = (i.viewDir.xyz / i.viewDir.w) * depth;
    28.     //Transform to world space
    29.     float3 worldPos = mul (_ViewToWorld, float4 (viewPos, 1));
    30.  
    31.     //Fill a sphere around the origin
    32.     return 1.0 - saturate (distance (0, worldPos));
    33. }
    34.  
    35. ...
     
  3. Lycake

    Lycake

    Joined:
    Jun 8, 2013
    Posts:
    7
    Thank you so very much! You not only understood my question, but also provided a perfect answer.

    This line was the deal breaker in my previous attempts:
    Code (CSharp):
    1. o.viewDir = mul (_InvProjectionMatrix, float4 (o.uv * 2.0 - 1.0, 1.0, 1.0));
    I couldn't get it to work the way it should. My math was wrong somehow.

    Thanks again!