Monday, November 16, 2009

graphics pipeline

It's important to know how shaders work with the graphics pipeline, because the "shader model" of graphics programming is totally different from the "fixed function model"! MSDN says here http://msdn.microsoft.com/en-us/library/ms800169.aspx

"The following user-mode display driver functions are not called by the Direct3D runtime when the vertex shader is enabled
  • * MultiplyTransform
  • * SetTransform
  • * SetMaterial
  • * SetLight
  • * CreateLight
  • * DestroyLight


This means that when you use shaders, you have to compute lighting and transformations! DirectX will also ignore flags like D3DRS_LIGHTING and texture state flags when you use shaders. When you program using the shader model, your shader program has responsibilities!

Contrast the API for the fixed function model, which uses the D3D device functions, with the shader model, which is similar but passeses parameters to your shader effects through the shader interface

IDirect3DDevice9::SetTexture vs ID3DXEffect::SetTexture
IDirect3DDevice9::SetTransform vs ID3DXEffect::SetMatrix
IDirect3DDevice9::SetLight vs ID3DXEffect::SetValue

I'll go over the exact responsibilities of shaders in your program. The MSDN page on the graphics pipeline says has some really important things about this - http://msdn.microsoft.com/en-us/library/ee415715(VS.85).aspx and I will use this gamasutra article for base code - http://www.gamasutra.com/features/20030418/engel_02.shtml



1) "The vertex-shader (VS) stage processes vertices ... performing per-vertex operations such as transformations, morphing, skinning, and per-vertex lighting."

Therefore, the vertex shader is typically responsible for worldview transformations and also calculating light values. The vertex shader sets up a VS_OUTPUT struct that contains transformed vertex information that is rasterized and passed to the pixel shader. The vertex shader outputs a VS_OUTPUT structure

struct VS_OUTPUT
{
float4 Pos : POSITION;
float3 Light : TEXCOORD0;
float3 Norm : TEXCOORD1;
};

VS_OUTPUT VS(float4 Pos : POSITION, float3 Normal : NORMAL)
{
VS_OUTPUT Out = (VS_OUTPUT)0;
Out.Pos = mul(Pos, matWorldViewProj); // transform Position wrt worldview
Out.Light = vecLightDir; // output light vector
Out.Norm = normalize(mul(Normal, matWorld)); // transform normal wrt world
return Out;
}

2) "A pixel shader is a program that combines texture data, per-vertex values, and other data to produce per-pixel outputs...Pixel shader inputs are interpolated from the vertex attributes of the primitive being rasterized"

We basically receive a VS_OUTPUT from our vertex shader as our pixel shader input, but the vertex data is interpolated. We use the NORMAL value to calculate lighting in our pixel shader, because the NORMAL in our pixel shader is interpolated from the rasterizer for our little pixel! The pixel shader outputs is a RGBA

float4 PS(float3 Light: TEXCOORD0, float3 Norm : TEXCOORD1) : COLOR
{
float4 diffuse = { 1.0f, 0.0f, 0.0f, 1.0f};
float4 ambient = {0.1, 0.0, 0.0, 1.0};
return ambient + diffuse * saturate(dot(Light, Norm));
}

Note: The POSITION register is not valid in the pixel shader, we are using pixels and not 3D space, but we still use the NORMAL data for lighting. The rasterization stage that converts our vertex shader data into pixel shader data is interesting. See the wikipedia page is good http://en.wikipedia.org/wiki/rasterization

No comments:

Post a Comment