DirectX:Direct3D:Tutorials:Shaders Introduction

From GPWiki

Tutorial by Nicholas Gorski [GMan]

Contents

Introduction

This series will describe how to use the assembly shader language. It was introduced by Microsoft in the release of DirectX8. By DirectX9, shaders had become HLSL, a high-level C-like language. It compiles to assembly shader. There is a ton of information about HLSL on Google (your friend). I believe that there is not nearly enough low-level stuff around. After all, not everyone has hardware support for HLSL.

This series will use Vertex Shader version 1.1 and Pixel Shader version 1.0-1.4 (Depends on what you need to do).

HLSL uses Vertex Shader 2.0 and Pixel Shader 2.0. There is no Vertex Shader 1.2-1.9, nor Pixel Shader 1.5-1.9.

For those of you using OpenGL, there is also an OGL shader language (GLSL) used to create Vertex/Pixel Shaders. This article uses DirectX only. I'm sure someone out there would like to know about OpenGL shaders...*hint*

What is it?

Assembly shader (just shader from now on) is an assembly like language that runs on the Graphics Processing Unit (GPU, otherwise known as video card). Before DX8, (i.e. DX7), all rendering pipelines were "fixed". You fed it vertices, it transformed them (move, rotate, project onto screen), then filled them in (pixels). This became very limiting, and programmers wanted more control.

With the advent of programmable GPU's, programmers had much more freedom to display graphics. Vertex manipulation could be controlled by the programmer rather than DirectX. Pixels could now be filled in any way you could possibly want.

Vertex & Pixel Shaders

So, what exactly are these magical names? They are the names of the two types of programs you can run on the GPU.

Vertex Shaders

In the last section you saw how DX transformed your vertices for you. If you wanted to manipulate them yourself, you would use a Vertex Shader. It is strange, however, that Vertex Shaders don't actually shade things, Pixel Shaders do...

A Vertex Shader program is run on every single vertex passed to the GPU. If you do not assign a Vertex Shader to DX, it does it for you, just like in a fixed-function graphics pipeline. However, the moment you assign a Vertex Shader to the device, you are in charge of rotating, translating, scaling, and all sorts of fun stuff.

Pixel Shaders

Pixel Shaders are where most of the graphical effects and such are achieved. After all, you can only do so much with a vertex. Pixel Shaders are the actual pixels drawn to the screen. This program is run on every single pixel drawn to screen. That is why it is very important to keep the size of it down. You may have noticed that Vertex Shaders(VS's) have only 1.0 & 1.1 as versions. However, Pixel Shaders(PS), have 1.0 through 1.4. That is because the actual pixels are much more important (for graphical effects) than vertices. So it's only fair that PS's have more upgrades than VS's.

Enough Talk, Show Me Something

Getting Started With Vertex Shaders

All right, calm down. Before we dive into the complex Pixel Shader stuff, we'll start with Vertex Shaders.

Vertex Shaders can be used for many things. For example, before programmable GPU's, Mesh Skinning was done on the CPU. However, when the workload is put on the GPU, the CPU has more time to work on more important things, like AI. Also, the GPU tends to have faster math operations than CPU's, so the trade-off is a great choice.

Because you can control the vertices, each vertex can be handled seperately. This allows for more detailed vertex tweaking allowing things like Facial Expressions and Water to be implemented much easier and faster.

Vertex Shader History

A little history of Vertex Shaders:

DirectX7 and below:
    No Support
DirectX8.0:
    Version 1.0
DirectX8.1:
    Version 1.1 - Added a register
DirectX9.0:
    Version 2.0 - HLSL

Setup

Before you can use Vertex Shaders, you need to define what data each vertex contains. You've probably already done this before. Some Visual Basic psuedo-code:

Private Type VERTEX
    x As Single
    y As Single
    z As Single
End Type
 
Const VERTEX_FVF = (D3DFVF_XYZ)

or in C++:

struct VERTEX
{
   FLOAT x, y, z;
};
 
#define VERTEX_FVF (D3DFVF_XYZ) 

These both tell DirectX that each vertex has x,y and z coordinates.

How you setup DirectX to accept Shaders is different for each language. I am only showing you how to make the actual Shaders, not how to setup DirectX.

The Syntax

Now for the cool part. This is where we program the Vertex Shader. For this sample, the vertex needs x,y, and z, and shown above.

Don't hurt me, but there is one more thing you must know before you can start. (It does have to do with the actual programming, though). You see, by itself a Shader is nothing but commands. They have no meaning by themselves. Which is why before you run a Shader Program, you set constants.

Side note: In graphics, vectors and colors are the same thing. All vectors are 4D and colors have four components: red, green, blue, and alpha (transparency).