XNA Creators Club Online
Page 1 of 1 (4 items)
Sort Posts: Previous Next

Using projected vertex position Z as distance?

Last post 11/03/2008 3:00 PM by floydzep. 3 replies.
  • 11/03/2008 11:59 AM

    Using projected vertex position Z as distance?

    Hello, I'm learning vertex shaders and I'm not sure if this would work...I'm trying to optimize stuff and to calculate my fog I need the distance from the eye to the vertex...Is it possible to use the projected Z coordinate as the distance such as the example below? Thanks for your time!

    Can i use this:
    Out.Pos = mul( In.Pos,  cWorldViewProj );
    Out.Fog.x = saturate( (cFogRange.y - Out.Pos.z) * cFogRange.z );


    Instead of this:
    float len = distance( cViewPos_OS, In.Pos.xyz );
    Out.Fog.x = saturate( (cFogRange.y - len) * cFogRange.z );
  • 11/03/2008 1:00 PM In reply to

    Re: Using projected vertex position Z as distance?

    The output Z value from the perspective transform is in a 4d homogeneous coordinate system (don't worry too much what that means: you rarely need to bother with it).

    To get this into sensible values, you need to divide Z by W. That will give you a normalized value ranging 0-1. You certainly can use that for fog computations, but the units will be kind of funky since the near and far clip planes have already been factored in during the projection transform, so you'll need to express your fog range as fractions of the distance between the near and far clip. Can be kind of a pain to tweak if adjusting the far clip plane also affects your fog settings!

    I'd stick with your current version. If you really care about shaving a few cycles off the vertex shader you can factor out a bunch of the range computations onto the CPU and get that down to just a single float4 dot product in the vertex shader, but vertex shader computation is so rarely the bottleneck on modern graphics cards, it is rarely worth bothering with that.
    XNA Framework Developer - blog - homepage
  • 11/03/2008 2:45 PM In reply to

    Re: Using projected vertex position Z as distance?

    Actually, the output Z value is usually quite sensible. If your near field is 0, then the output Z is exactly the Z depth in camera space. As Zn grows, there is an increasing amount of bias, in that values at Zn will be 0, but values at Zf will still be Zf, so there's a "stretching" of this space. This is for non-infinite projection matrices, as seen here:
    http://msdn2.microsoft.com/en-us/library/bb206260(VS.85).aspx
    As you can see, you can easily un-warp the value by adding (Zn*Zf/(Zf-Zn)) and then multiplying by ((Zf-Zn)/Zf), which gives you the world-space distance along the Z depth radius from the camera.

    Another common value to use is the Z value of the output of the WORLDVIEW matrix.

    A third common value to use is the vertex value of the output of the WORLD matrix, and dot it with the world-space camera forward vector.

    A fourth common value to use is the plain vertex value, dotted with the object-space camera forward vector.

    All of these will give you basically the same value : world space Z depth distance. Unfortunately, this will cause some warping of fog at the edges of the screen -- basically, something will be less in fog when at the edge of the screen, than when in the center of the screen. Unless you are horribly shader limited, I would suggest using radial fog, where you actually use the distance calculation.

    Jon Watte, Direct3D MVP
    Tweets, occasionally
    kW X-port 3ds Max .X exporter
    kW Animation source code
  • 11/03/2008 3:00 PM In reply to

    Re: Using projected vertex position Z as distance?

    Thanks for the great answers, it makes sense to me now. I will just continue using the correctly calculated distance and if the vert shaders start to bog down my app I'll consider using the optimized projected z with the precision loss.

    One more thing, is it safe to store the vertex shader Fog value in the z of the texture coordinate, like so?

    struct VS_OUT
    {
        float4   Pos              : POSITION;
        float3   TexAndFog   : TEXCOORD0;
    };

    Out.TexAndFog.xy = In.Tex0;
    Out.TexAndFog.z = saturate( (cFogRange.y - distance( cViewPos_OS, In.Pos.xyz )) * cFogRange.z );

    Would that be *correct* and worth the optimization of not using another texcoord semantic for the fog?...seems to work...hehe, not sure if the interpoland here will do what i think it should...
Page 1 of 1 (4 items) Previous Next