Posts tonen met het label introduction. Alle posts tonen
Posts tonen met het label introduction. Alle posts tonen

donderdag 18 augustus 2011

Introduction to HLSL - Part 3

Diffuse lighting
In this part we're going to add some simple diffuse lighting. The new lines compared to the previous part are marked in bold.
// 1: Application inputs
float4x4 object_to_world: WORLD;
float4x4 object_to_clip: WORLDVIEWPROJECTION;
float3 light_pos: LIGHT_POS;
float3 light_color: LIGHT_COLOR;

float3x3 object_to_world3x3 = (float3x3)object_to_world;

// 2: Structures
struct vs_in {
   float4 pos_object: POSITION;
   float3 normal_object: NORMAL;
};

struct ps_in {
   float4 pos_clip: POSITION;
   float3 normal_world: TEXCOORD0;
   float3 light_world: TEXCOORD1;
};

// 3: Vertex Shaders
ps_in vs_main(vs_in input) {
   ps_in output;
   output.pos_clip = mul(input.pos_object, object_to_clip);
   output.normal_world =
      mul(input.normal_object, object_to_world3x3);
   float4 pos_world = mul(input.pos_object, object_to_world);
   output.light_world = light_pos - pos_world.xyz;
   return output;
}

// 4: Pixel Shaders
float4 ps_main(ps_in input) : COLOR {
   float3 result = light_world;
   float3 normal_world = normalize(input.normal_world);
   float3 light_world = normalize(input.light_world);
   result *= saturate(dot(normal_world, light_world));
   return float4(result, 1.f);
}

// 5: Techniques
technique main {
   pass p0 {
      VertexShader = compile vs_3_0 vs_main();
      PixelShader = compile ps_3_0 ps_main();
   }
}
In this example we add the normals (in object space) as inputs to the vertex shader. The vertex shader turns them into world space. Note that the full 4-by-4 transformation matrix includes translation, rotation and scale. For the transformation of normals we are only really interested in the rotation, so we use a reduced 3-by-3 matrix for the transformation. The vertex shader also calculates the vector from the surface of the object to the light source (in world space) and passes this information on to the pixel shader.

dinsdag 16 augustus 2011

Introduction to HLSL - Part 2

Our first shader
In this part we take the two critical lines of the last part (marked bold) and turn it into a complete HLSL shader. In this introduction I target Shader Model 3.0 which is compatible with DirectX 9.0c.
// These are comments
// 1: Application inputs
float4x4 object_to_clip: WORLDVIEWPROJECTION;

// 2: Structures
struct vs_in {
   float4 pos_object: POSITION;
};

struct ps_in {
   float4 pos_clip: POSITION;
};

// 3: Vertex Shaders
ps_in vs_main(vs_in input) {
   ps_in output;
   output.pos_clip = mul(input.pos_object, object_to_clip);
   return output;
}

// 4: Pixel Shaders
float4 ps_main(ps_in input) : COLOR {
   return float4(1.f, 1.f, 1.f, 1.f);
}

// 5: Techniques
technique main {
   pass p0 {
      VertexShader = compile vs_3_0 vs_main();
      PixelShader  = compile ps_3_0 ps_main();
   }
}
The shader code consists of 5 parts. The application inputs, the structures used (for input and output), the vertex shader(s), the pixel shader(s) and the technique(s). The vertex shader is executed for each vertex in the model and does the minimum it has to do, transform the model into clip space. The pixel shader is executed for each pixel and simply returns a fully opaque white pixel in this case. In the next part we'll add some diffuse lighting.

maandag 15 augustus 2011

Introduction to HLSL - Part 1

Naming conventions
 

In programming it's good practice to name your variables logically. Often I see this practice not executed in shader writing. That's why I'm starting with some variable naming conventions I like to adhere to. One of the most basic things a shader has to do is to transform the rendered object from object space into clip space. I'll come back to mathematics behind this, but for now it's enough to know that this transformation can be done by a single matrix multiplication. The matrix in question has the input semantic WORLDVIEWPROJECTION. The code for the transformation is commonly written as:
float4x4 wvp: WORLDVIEWPROJECTION;
out.pos = mul(in.pos, wvp);
In this code we find two distinct variables that are both named pos. The one in the in structure is the position in object space, while the one in the out structure is the position in clip space. The first naming convention I adhere to is to add the space a vector is in as a suffix. So we update the transformation above into this one:
float4x4 wvp: WORLDVIEWPROJECTION;
out.pos_clip = mul(in.pos_object, wvp);
Next lets look at the variable wvp. These three letters are a logical shorthand of WorldViewProjection, but what is the function of this variable in our code? We will almost always use this matrix to convert a vector from object space into clip space. So we'll call the variable object_to_clip instead. We'll also lengthen in and out a little bit to input and output:
float4x4 object_to_clip: WORLDVIEWPROJECTION;
output.pos_clip = mul(input.pos_object, object_to_clip);
This concludes the first part of the introduction to HLSL. In the next part we'll take this must have piece of code and extend it into our first full HLSL shader.