Friday, May 6, 2011

HLSL and a cool Direct3D debugging tool

I worked on the rendering system today.  Because of the way I handle errors, there is a class for the D3D object, the device, vertex declarations, vertex buffers, vertex shaders, and pixel shaders.  This is a little inconvenient, as the following code shows:

m_renderer->GetDevice()->BeginScene();
hResult = m_renderer->GetDevice()->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
if (hResult != D3D_OK)
{
    throw (CException("Could not draw the triangle.\r\n\r\nError Code: 0x%08X", hResult));
}
m_renderer->GetDevice()->EndScene();


I'm considering having the classes manage global variables rather than member variables.  That way, I can access the global directly in other parts of the code rather than through an object.  I may try that in the next iteration.

Today marks the first time I have ever written and used a shader.  This is something I have been wanting to do for a while, and it opens up some very interesting possibilities.  For example, I can now make the screen fade to grey.  I can also prevent players from being able to get around the darkness in a game by banding dark colors (I am currently working out how to do this exactly).

One thing which was a bit annoying for me while researching HLSL (a programming language you can use to write shaders) was being unable to find a simple, basic shader example.  So here is a set of bare-bones, pass-through shaders which will hopefully help someone who wants to learn how to write shaders:

// ***** Vertex Shader *****
struct tVSInput
{
    float3 pos        : POSITION;
    float4 diffuse    : COLOR;
};

struct tVSOutput
{
    float4 pos        : POSITION;
    float4 diffuse    : COLOR;
};

tVSOutput main(tVSInput input)
{
    tVSOutput output;
   
    output.pos.xyz = input.pos.xyz;
    output.pos.w = 1;
    output.diffuse = input.diffuse;
   
    return (output);
}

// *****

// ***** Pixel Shader *****
struct tVSOutput
{
    float4 pos        : POSITION;
    float4 diffuse    : COLOR;
};

float4 main(tVSOutput input) : COLOR
{
    return (input.diffuse);
}

// *****

I should probably note that this is my first time writing these, so an expert may take issue with something in there.  However, both shaders work perfectly fine in the tests I have ran, and they are nice and simple to read.

On the subject of shaders; if you use a shader model 3.0 vertex shader, you apparently need to also use a shader model 3.0 pixel shader.  If you use a 2.0 vertex shader (or lower I am assuming), you can let the fixed function pipeline take care of the pixel shader part.  Before I figured this out, I was a bit confused as to why the triangle I was using as a test wasn't appearing.

If you are using Direct3D, I highly recommend trying out PIX.  PIX is a free utility that comes with the SDK.  You can find it in the utilities folder in the SDK installation directory.  It is pretty much a debugger for Direct3D; it monitors how the program you attach it to uses Direct3D and gives you a report after the program closes.  It gives you a list of all created resources and the arguments used when creating them, you can take snapshots at runtime and later view what calls were made during that snapshot, and quite a bit more from the looks of it.

No comments:

Post a Comment