|
|
The input registers are how data gets passed to the vertex shader. Direct3D provides input vertex registers, which will contain input data to the vertex shader. What this data is depends upon the format of the vertex stream(s) that are currently active.
The other set of input registers is the constant registers, which are set up prior to running the vertex shader. It's up to you to correctly set up these registers. For example, you probably want to pass in the current modelview matrix, light positions, etc., prior to calling the shader.
Aside from the actual instructions that you enter into your shader, you will most probably need to get values into those instructions, and you do it through the constant floating-point registers. They are called the float constant registers simply because they are floating point values that are read only once they are passed to the shader and the shader is running. However, you'll frequently find that you'll be setting values of the constant registers prior to the beginning of each frame of rendering (e.g., setting the world/model/projection matrix values), or even prior to each render primitive call (to set a primitive or shader-specific value).
One optimization made in the assembly of vertex shaders is that there can be only one constant register referenced from any single instruction. However, you may use that constant more than once, and each reference to the constant can independently swizzle or negate the constant's vector elements.
add r5, v0 v0 // fine add r5, c1 c2 // Error! 3 different registers add r5, c5 c5 // fine - doubles r5 add r5, c5 -c5 // fine - zero in r5 add r5 c5.xxxx, c5.yyyy // OK fills r5 with x+y
The syntax that allowed for constant registers is also a little more complex. You can reference them like any other, or you can place the numeric part inside square brackets. DirectX 8.1 introduced the address register, a0.x, which allows you to have a programmable index into the constant registers. Some examples are shown next.
mov oD1, c5 // fine - regular way mov oD1, c[5] // using brackets mov oD1, c[5+a0.x] // fine for DX8.1+
There are two ways to get the constant registers loaded. One way is to use the def statement and then (in DirectX 8) postprocess this to add the generated shader code fragment to the shader. The preferred (and easier) way is to just set the values using SetVertexShaderConstant() to take a vector of four floats and store them in the specified register. You can set an array of constants using this call.
There are at least 96 float constant registers in DirectX 8 shaders, while there are at least 256 float constants in DirectX 9 vertex shaders. You could check the number specified in the MaxVertexShaderConst member of the D3DCAPS structure.
DirectX 9 also introduced 16 integer constants and 16 bool constants as well as modifying the way that constants can be set. In addition to the SetVertexShaderConstantx() calls, the def instruction in vertex shaders 2.0 now actually does something. When the def instruction is encountered in a shader, the current value of the temporary register specified is pushed then set immediately to that value for the life of the shader. These are called immediate constants. When the shader exits the constant register is popped back to its original value. Any call to get a constant's value will necessarily be done after the shader. The post processing step required in DirectX 8 shaders is no longer supported. |
The input vertex registers contain the vertex information that the shader is going to work on. There are a total of sixteen input registers designated as v0 through v15. Each vertex register is read only and consists of a four-element floating point vector. A vertex shader instruction may access only one input register at a time, but may use that register more than once in that instruction.
The vertex information is taken from the current vertex stream(s) and loaded into the vertex registers, and then the shader is run. What is stored in them and their order are completely up to you, and will consist of things like the vertex position, normal, color values (diffuse, specular), texture coordinates, and blending values. You specify what's in each input vertex register when you declare a shader register and use it in SetStreamSource(). This is where the mapping between your input vertex stream and the input vertex shader registers occurs. See Chapter 5 for more details on setting up a mapping between a stream and the input registers.
If you are using the FVF formats in DirectX 8, then the input vertex registers are given to the shader in the following order:
VECTOR COMPONENT | FVF TAG | SHADER DECLARATION NAME | REGISTER |
---|---|---|---|
Position | D3DFVF_XYZ | D3DVSDE_POSITION | v0 |
Blend weight | D3DFVF_XYZRHW | D3DVSDE_BLENDWEIGHT | v1 |
Blend indices 1 through 5 | D3DFVF_XYZB1 through D3DFVF_XYZB5 | D3DVSDE_BLENDINDICES | v2 |
Normal | D3DFVF_NORMA | D3DVSDE_NORMAL | v3 |
Point size | D3DFVF_PSIZE | D3DVSDE_PSIZE | v4 |
Diffuse | D3DFVF_DIFFUSE | D3DVSDE_DIFFUSE | v5 |
Specular | D3DFVF_SPECULAR | D3DVSDE_SPECULAR | v6 |
Texture | D3DFVF_TEXO | D3DVSDE_TEXCOORDO | v |
Position 2 | D3DVSDE_POSITION2 | v15 | |
Normal2 | D3DVSDE_NORMAL2 | v16 |
|
|