1
\$\begingroup\$

I'm having a lot of trouble with shadow mapping, and I believe I've found the problem. When passing vectors from the vertex shader to the pixel shader, does the hardware automatically change any of the values based on the semantic?

I've compiled a barebones pair of shaders which should illustrate the problem.

Vertex shader :

struct Vertex {
    float3 position : POSITION;
};

struct Pixel {
    float4 position : SV_Position;
    float4 light_position : POSITION;
};

cbuffer Matrices {
    matrix projection;
};

Pixel RenderVertexShader(Vertex input) {
    Pixel output;
    output.position = mul(float4(input.position, 1.0f), projection);
    output.light_position = output.position;
    // We simply pass the same vector in screenspace through different semantics.
    return output;
}

And a simple pixel shader to go along with it:

struct Pixel {
    float4 position : SV_Position;
    float4 light_position : POSITION;
};

float4 RenderPixelShader(Pixel input) : SV_Target {
    // At this point, (input.position.z / input.position.w) is a normal depth value.
    // However, (input.light_position.z / input.light_position.w) is 0.999f or similar.
    // If the primitive is touching the near plane, it very quickly goes to 0.

    return (0.0f).rrrr;
}

How is it possible to make the hardware treat light_position in the same way which position is being treated between the vertex and pixel shaders?

This differrence is almost exclusive to the Z component, as the X and Y values of light_position are behaving as expected.

EDIT: Aha! (input.position.z) without dividing by W is the same as (input.light_position.z / input.light_position.w). Not sure why this is.

EDIT 2: Dividing (output.light_position) by (output.light_position.w) in the vertex shader causes really odd behavior, where (input.light_position.z / input.light_position.w) will be either 0 or 1 based on the camera's position and angle.

EDIT 3: Moving the projection multiplication into the pixel shader doesn't seem to make any difference. This means that the hardware is doing something to the SV_Position semantic which is critical to make it work.

EDIT 4: (input.light_position.z / input.light_position.w) IS behaving like depth, it's just that the precision seems to have decreased unbelievably. Only does it approach 0 once it's primitive literally intersects the near plane.

\$\endgroup\$
  • \$\begingroup\$ could you add an image, and your pixelshader source code? And also dont forget that you have to divide your position thats no the System Semantic for position with it´s W component. the hardware does that for you on the system semantics. \$\endgroup\$ – Tordin Jun 4 '14 at 7:48
  • \$\begingroup\$ Did you try to increase your near plane? That generally helps. \$\endgroup\$ – catflier Jun 4 '14 at 16:07
  • \$\begingroup\$ You know, if you divide xyzw (instead of xyz) by w, it will not matter if the hardware divides by w again... because w will be 1.0. Not sure how relevant that is here, but that is one reason you should divide the enitre vector by w, not just the first 3-components. That said, w is usually assigned 1/w when the hardware does this division (clip-space -> NDC) so that you can reverse the transformation. \$\endgroup\$ – Andon M. Coleman Jun 5 '14 at 2:45
  • \$\begingroup\$ Changed everything as I made a smaller program which narrowed down the problem. \$\endgroup\$ – object Jun 6 '14 at 15:35
0
\$\begingroup\$

Turns out, the depth values were correct the whole time. I was looking at a bad image for reference, where objects would get darker as they got further away from you. Of course, this is completely incorrect.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.