Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

What is screenPos.w ?

Discussion in 'Shaders' started by killer777, Jan 20, 2019.

  1. killer777

    killer777

    Joined:
    Mar 23, 2013
    Posts:
    5
    I'm a noobie at shader programming and am trying to learn to create intersect highlight effect. but I can't understand some of the concepts and unfortunately, no one answered these questions before (or I couldn't find).

    - so does anybody know what exactly stored in screenPos.w at following code part?

    - and if an object distance to viewer pos is 20 so LinearEyeDepth will return 20?

    upload_2019-1-20_22-6-45.png
     
    Last edited: Jan 20, 2019
    rockin likes this.
  2. daxiongmao

    daxiongmao

    Joined:
    Feb 2, 2016
    Posts:
    385
    Unity's shaders are available online as a separate download. Get them and then you can find the ComputeScreenPos function and see what it's storing in w.
    Having them is very valuable if you are going to be making a lot of your own shaders.
    Get the ones for your version of unity.
     
    ruzgames and thekevinyu like this.
  3. killer777

    killer777

    Joined:
    Mar 23, 2013
    Posts:
    5
    How can I see what ComputeScreenPos is storing in w?
     
  4. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Deleted User likes this.
  5. nat42

    nat42

    Joined:
    Jun 10, 2017
    Posts:
    353
    Not sure if it's more or less confusing but I think those are in a way kind of all the same things. The matrices that do graphics transforms are done in such a way that the w coordinate distinguishes vectors and positions (which I think partially explains the lighting use) by their w value and post transform leaves a value in w that can be used for perspective divide.
     
  6. killer777

    killer777

    Joined:
    Mar 23, 2013
    Posts:
    5
    but what exactly stored in at this particular code, what ComputeScreenPos store in w?
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    11,889
    CompiteScreenPos doesn’t actually do anything to the .w, or even the .z components. Those are just the clip space z and w values that are passed in passed out straight.

    So the question is what are those values? Well, z is the clip space depth, which is a range of 0.0 to w for Direct3D (and most other graphics APIs) and -w to w in OpenGL. So what's w? It's the world scaled view depth.

    That's it. It's a quirk of projection matrices and the resulting clip space that the w is just the view space depth. If you have a quad as a child object of an unscaled camera game game object, the transform's z position shown in the inspector will match the w of the in shader clip position.

    Why gets into the whole perspective divide stuff and 4 dimensional spaces, so we'll ignore that for now.
     
    rockin, ruzgames, PrimalCoder and 5 others like this.
  8. killer777

    killer777

    Joined:
    Mar 23, 2013
    Posts:
    5
    thank you so much for your useful and in detail reply. So can i say w is the distance from camera? or It's the depth between camera and vertex?

    and my other question is what LinearEyeDepth return? depth again between viewer and objects with world unit but not very precise?
     
    Last edited: Jan 21, 2019
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    11,889
    It’s depth, not distance, from camera origin to vertex, assuming a perspective projection matrix that’s focused on the camera’s origin, which most perspective projection matrices are calculated to be. And certainly the Unity camera’s perspective projection matrix is unless manually overridden.

    LinearEyeDepth takes the depth from the non-linear depth buffer and converts it to linear eye depth, which is roughly identical to the clip space w in precision. It’s also the same value you get from the COMPUTE_EYEDEPTH macro when in the vertex function, though that’s calculated by applying the world and view matrices to the object space vertex position.

    So why all of the different versions of this?

    When using anything but the usual projection matrix, w component of the clip space position is not the view/eye depth. In fact when it’s an orthographic camera it’s a constant value. So if you need the linear depth for something and want to make sure your shader supports all projection matrix types, you can’t rely on the w being the depth. Plus, you often want to know the depth of a vertex in the fragment shader prior to calculating the clip space position. So that’s where COMPUTE_EYEDEPTH comes in.

    What about LinearEyeDepth? That’s taking the value from the non-linear depth buffer and converting it into linear depth as I mentioned above. This is often the depth from the camera depth texture rather than some value interpolated from the current shader’s vertex stage. But you could get it the depth buffer value for a mesh from the input.pos.z value in the above shader, as that”s what that value holds in the fragment shader. But that’s extra math, including a divide that can be costly on some hardware. So it’s often better passed separately. Plus the conversion from non-linear depth buffer to linear depth buffer is actually broken in Unity if you’re using something other than a default perspective projection matrix since that function assumes some stuff (mainly that you are using a default projection matrix) so it can simplify the math.

    But wait, I said you can access the input.pos, which is the same as the output.pos from the vertex function, which means the input.pos.w holds the linear depth! Right? Nope. Even assuming a perspective matrix this isn’t the case. The value you output from the vertex function is in clip space, but that same variable input into the fragment shader has been transformed into window space by the GPU. The x and y are now the screen pixel position, z is the non-linear depth buffer (which has a 0.0 to 1.0 range for all graphics APIs, remember I said clip space is 0.0 to w on some, and -w to w on otheres), and the w is 1.0. Yes, just 1.0, always. That’s because it’s the w component after the GPU applied the perspective divide, which is dividing the whole float4 value by the w, and any non zero number divided by itself is 1.0.

    Now let’s look at why specifically the ComputeScreenPos passes the w value. This is so it can apply the perspective divide to the interpolated position. When using a non-orthographic projection, a screen space interpolated float3 position won’t interpolate the way you’d expect in 3D space. You’ll get odd warping and stretching of the value between the vertices as they’re being interpolated linearly in 2D screen space, not in 3D view space. Remember all that weird texture warping from old PS1 games? It’s that. Using a perspective divide let’s you interpolate a float4 value and correct the “2D” linear interpolation to take into account the perspective making they work as you would expect them to. So really that’s all it’s there for.

    So, the shader example above is making use of the w component as an optimization, by assuming the use of a perspective matrix, they know that value used to correct for perspective interpolation is also the view depth.
     
    rockin, dspmania, PrimalCoder and 7 others like this.
  10. sylon

    sylon

    Joined:
    Mar 5, 2017
    Posts:
    246
    @bgolus, i think i am going to collect all your posts and put them in a book :)
    Really appreciate the time you take to answer all these questions.
     
    riveranb, dspmania, JmprDev and 2 others like this.
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    11,889
    I hope you edit them for grammatical errors. ;)
     
    lexusinator, brn and sylon like this.
  12. killer777

    killer777

    Joined:
    Mar 23, 2013
    Posts:
    5
    @bgolus you are awesome, thanks for all this information. :)