Altering vertex positions in the Vertex shader using constant buffer variables

Started by
4 comments, last by MJP 12 years, 10 months ago
I'm creating a screen-space quad for which I can just specify four clip-space coordinates when I create the quad and the code does all the rest for me. I also want the ability to dynamically move and resize these around the screen.

I thought, rather than create and alter vertex buffers at run-time, I could just leave position info out of the vertex buffer entirely and specify the coordinates to use with a constant buffer instead. Then I can just send the coodinates of the corners to the GPU (four float2s) before I draw. My intention was to have the vertex shader pick these up and set the vertices to the appropriate values.

A problem I hit was how to get the vertex shader to use a different coordinate for each vertex in the primitive. The solution I came up with was to have the screen space positions in an array in a constant buffer and have a static int representing the offset into this array. I then increment this static variable after each vertex has been processed, and have it loop back to zero once it reaches 4.

I thought this would work elegantly but it doesn't seem to be incrementing the offset. I've run it though PIX and it doesn't even seem to be compiling the offset factor into the shader code at all. Am I doing something wrong, or is there just no way to do it like this? Or am I being stupid doing it like this at all?

Here is my shader code:



// SHADER_QUAD

static int PosArrayCounter;

cbuffer posArray
{
float2 Positions[4];
};

Texture2D Image;

struct VS_OUTPUT
{
float4 PosH : SV_POSITION;
float2 Tex : TEXCOORD1;

};

SamplerState samLinear
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};

VS_OUTPUT VS(float2 Tex : TEXCOORD)
{
VS_OUTPUT output = (VS_OUTPUT)0;

output.PosH = float4(Positions[PosArrayCounter], 1, 1);
output.Tex = Tex;
PosArrayCounter++;
if (PosArrayCounter > 3)
{
PosArrayCounter = 0;
}
return output;
}

float4 PS( VS_OUTPUT input ) : SV_Target
{
float4 colour = Image.Sample(samLinear, input.Tex);

return colour;
}

//--------------------------------------------------------------------------------------
technique10 Render
{
pass P0
{
SetVertexShader( CompileShader( vs_4_0, VS() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, PS() ) );

}
}

Advertisement
Yeah you can't increment a persistant variable like that in a vertex shader. The GPU will process many vertices in parallel rather than 1 at a time, and to make that sort of massively parallel programming easier for the for the programmer the runtime doesn't let different shader instances (threads) communicate with each other. The one exception is compute shaders, which can do so through shared memory.

Anway there's a really simple solution to your problem, which is to use SV_VertexID. This will give you the 0-3 index of the vertex you're processing, which you can use to look up the position from your constant buffer. In fact you can have no vertex buffer at all if you want, and put your texture coordinates in the constant buffer as well.
Ah, excellent, thanks.
Hmm... how do I get the vertex shader to pick up the SV_VertexID value? Pass it into the VS as a parameter? Do I then have to include it in the input layout or can I leave it out of there?

So far my google-fu has been fruitless.
You could add another 1 float (or 1 int or whatever) element to your vertex and use that as an index into the constant buffer array.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Just pass it in to your vertex shader entry point, it doesn't need to be part of your input layout. The runtime will automatically generate it and pass it to your shader.


struct VSInput
{
float4 Position : POSITION;
float2 TexCoord : TEXCOORD;
uint VertexID : SV_VertexID;
};

VSOutput VSMain(in VSInput input)
{
...
}

This topic is closed to new replies.

Advertisement