1
\$\begingroup\$

I am following this tutorial. I am confused as to why the VertexShader is being called each time for the PixelShader. I was under the assumption the VertexShader is called only 6 times during the pipeline. Additionally, what is the order in which the shaders are being called.

Horizontalblur.fx

////////////////////////////////////////////////////////////////////////////////
// Filename: horizontalblur.fx
////////////////////////////////////////////////////////////////////////////////


/////////////
// GLOBALS //
/////////////
matrix worldMatrix;
matrix viewMatrix;
matrix projectionMatrix;

Texture2D shaderTexture;

float screenWidth;


///////////////////
// SAMPLE STATES //
///////////////////
SamplerState SampleType
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};


//////////////
// TYPEDEFS //
//////////////
struct VertexInputType
{
    float4 position : POSITION;
    float2 tex : TEXCOORD0;
};

struct PixelInputType
{
    float4 position : SV_POSITION;
    float2 tex : TEXCOORD0;
    float2 texCoord1 : TEXCOORD1;
    float2 texCoord2 : TEXCOORD2;
    float2 texCoord3 : TEXCOORD3;
    float2 texCoord4 : TEXCOORD4;
    float2 texCoord5 : TEXCOORD5;
    float2 texCoord6 : TEXCOORD6;
    float2 texCoord7 : TEXCOORD7;
    float2 texCoord8 : TEXCOORD8;
    float2 texCoord9 : TEXCOORD9;
};


////////////////////////////////////////////////////////////////////////////////
// Vertex Shader
////////////////////////////////////////////////////////////////////////////////
PixelInputType HorizontalBlurVertexShader(VertexInputType input)
{
    PixelInputType output;
    float texelSize;


    // Change the position vector to be 4 units for proper matrix calculations.
    input.position.w = 1.0f;

    // Calculate the position of the vertex against the world, view, and projection matrices.
    output.position = mul(input.position, worldMatrix);
    output.position = mul(output.position, viewMatrix);
    output.position = mul(output.position, projectionMatrix);

    // Store the texture coordinates for the pixel shader.
    output.tex = input.tex;

    // Determine the floating point size of a texel for a screen with this specific width.
    texelSize = 1.0f / screenWidth;

    // Create UV coordinates for the pixel and its four horizontal neighbors on either side.
    output.texCoord1 = input.tex + float2(texelSize * -4.0f, 0.0f);
    output.texCoord2 = input.tex + float2(texelSize * -3.0f, 0.0f);
    output.texCoord3 = input.tex + float2(texelSize * -2.0f, 0.0f);
    output.texCoord4 = input.tex + float2(texelSize * -1.0f, 0.0f);
    output.texCoord5 = input.tex + float2(texelSize *  0.0f, 0.0f);
    output.texCoord6 = input.tex + float2(texelSize *  1.0f, 0.0f);
    output.texCoord7 = input.tex + float2(texelSize *  2.0f, 0.0f);
    output.texCoord8 = input.tex + float2(texelSize *  3.0f, 0.0f);
    output.texCoord9 = input.tex + float2(texelSize *  4.0f, 0.0f);

    return output;
}


////////////////////////////////////////////////////////////////////////////////
// Pixel Shader
////////////////////////////////////////////////////////////////////////////////
float4 HorizontalBlurPixelShader(PixelInputType input) : SV_Target
{
    float weight0, weight1, weight2, weight3, weight4;
    float normalization;
    float4 color;

    // Create the weights that each neighbor pixel will contribute to the blur.
    weight0 = 1.0f;
    weight1 = 0.9f;
    weight2 = 0.55f;
    weight3 = 0.18f;
    weight4 = 0.1f;

    // Create a normalized value to average the weights out a bit.
    normalization = (weight0 + 2.0f * (weight1 + weight2 + weight3 + weight4));

    // Normalize the weights.
    weight0 = weight0 / normalization;
    weight1 = weight1 / normalization;
    weight2 = weight2 / normalization;
    weight3 = weight3 / normalization;
    weight4 = weight4 / normalization;

    // Initialize the color to black.
    color = float4(0.0f, 0.0f, 0.0f, 0.0f);

    // Add the nine horizontal pixels to the color by the specific weight of each.
    color += shaderTexture.Sample(SampleType, input.texCoord1) * weight4;
    color += shaderTexture.Sample(SampleType, input.texCoord2) * weight3;
    color += shaderTexture.Sample(SampleType, input.texCoord3) * weight2;
    color += shaderTexture.Sample(SampleType, input.texCoord4) * weight1;
    color += shaderTexture.Sample(SampleType, input.texCoord5) * weight0;
    color += shaderTexture.Sample(SampleType, input.texCoord6) * weight1;
    color += shaderTexture.Sample(SampleType, input.texCoord7) * weight2;
    color += shaderTexture.Sample(SampleType, input.texCoord8) * weight3;
    color += shaderTexture.Sample(SampleType, input.texCoord9) * weight4;

    // Set the alpha channel to one.
    color.a = 1.0f;

    return color;
}


////////////////////////////////////////////////////////////////////////////////
// Technique
////////////////////////////////////////////////////////////////////////////////
technique10 HorizontalBlurTechnique
{
    pass pass0
    {
        SetVertexShader(CompileShader(vs_4_0, HorizontalBlurVertexShader()));
        SetPixelShader(CompileShader(ps_4_0, HorizontalBlurPixelShader()));
        SetGeometryShader(NULL);
    }
}
\$\endgroup\$
5
\$\begingroup\$

The vertex shader is called only 6 times, if you're drawing a full-screen quad using two triangles.

I'm guessing that you're getting confused because the outputs of the vertex shader (here, the PixelInputType struct) are being fed as inputs to the pixel shader. What's going on is that those values are being linearly interpolated between the vertices, to generate values for each pixel in the triangle.

For example, if the vertex shader outputs a value of 4 for one vertex, and 7 for another vertex, then each pixel in the triangle will get a value intermediate between 4 and 7, depending on where it is relative to the vertices. The pixel values change smoothly and linearly from 4 to 7 as you move across the triangle. This is calculated automatically by the hardware for each variable output by the vertex shader - such as position, normal, texture coordinates, etc.

The vertex shader runs first, and outputs the clip-space positions of the vertices, as well as all the values to be interpolated. The hardware rasterizer then uses that information to determine which pixels are part of the triangle, and the pixel shader is then called once for each of those pixels, passing in interpolated versions of all the variables output from the vertex shader.

\$\endgroup\$
  • \$\begingroup\$ You mean that the output.texCoord1...9 will change outside of being set by the VertexShader from the 6 times it is called? \$\endgroup\$ – bluejamesbond Nov 25 '13 at 5:32
  • \$\begingroup\$ @mk1 Yes. Each time the pixel shader is called, it will see values of those variables that have been interpolated between the values that were set by the vertex shader. \$\endgroup\$ – Nathan Reed Nov 25 '13 at 5:38

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.