Short introduction to Semantics and Annotations
You saw earlier how semantics are added to variable to identify and link inputs and outputs of the graphics pipeline. Thus, semantics are relevant in the context of the language and are necessary for some variables.
You can use semantics to have a unified way of setting values to different variables in different shader. For example, you could use the WORLD semantic to access the corresponding variable, even if a shader uses WorldMatrix as the variable name, or wrld, or world_mat, as long as they are declared using the WORLD semantic.
In addition to semantics, HLSL also offers the concept of annotations. Annotations are used-defined data that can be attached to techniques, passes or parameters. Annotations are not relevant for the HLSL compiler. So having an annotation does not affect the final shader code. However, they are a flexible way to add information to parameters. An application can read and use this information in whatever way it chooses. Annotation declarations are delimited by angle brackets.
In the following example, we add an annotation to a texture, to specify the file that should be loaded in that texture.
texture Texture <string filename = "myTexture.bmp">
The annotation is just a decoration. The file myTexture.bmp is not loaded automatically in the Texture variable. However, we used the annotation, so we can use this information in the application. You can read annotations by using the Annotations member of the EffectParameter class. The following code illustrates how to use the annotation added to the Texture variable.
Effect effect; Texture2D texture; //read the annotation String filename = effect.Parameters["Texture"].Annotations["filename"].GetValueString(); [...]//load the texture specified in the filename in the texture variable //set the texture to the effect parameter effect.Parameters["Texture"].SetValue(texture);
Because annotations are so flexible, you can use them to interact with different effect files in the same way, both in a game and in some other tool.
Techniques and Passes
An effect file can contain one or more techniques. A technique encapsulates all information needed to determine a style of rendering, and contains one or more passes. Declaring a technique is done using the technique keyword.
technique Technique_0
{
//list of passes
}
technique Technique_1
{
//list of passes
}
From XNA code, the techniques are accessible through the Techniques member, and the currently active technique is accessible through CurrentTechnique. Techniques are often use for providing different versions of the same shader for different shader models. This way, when initializing an effect, based on the hardware configuration, you can use a technique to us from that point onwards.
As mentioned before, a technique is composed of one or more passes. A pass contains the state assignments required to render. These include the vertex and pixel shaders and the render states. Passes are usually used when the final rendering of a model/object requires more types of processing to be done, and then combined. For example, you could have a pass that evaluates directional lighting, and a pass that evaluates spotlights, and in the end combine their results. However, simply declaring more passes in a technique does not cause them to be automatically executed. The application code has to iterate through the list of passes of a technique, and issue a draw call for each pass.
The code below shows an example of a technique containing more passes.
technique example_technique
{
pass Pass0
{
...
}
pass Pass1
{
...
}
}
An XNA application would iterate and execute more passes in the following way.
effect.Begin();
foreach (EffectPass pass in effect.CurrentTechnique.Passes
{
pass.Begin();
//issue draw calls
pass.End();
}
effect.End();
Vertex Declarations
You saw earlier how semantics determine how data is linked from one pipeline stage to the next. One thing that was not so clear was how the graphics pipeline links bytes from vertex streams into the corresponding variables. We know that, for example, VertexShaderInput.Position should contain the position of the vertex, but when the graphics card receives N bytes of data representing a vertex, it needs a way to decide which of these bytes represent the position, and which represent other things, like normals, or texture coordinates.
This is where vertex declarations come in. A vertex declaration is a structure initialized through application code, which is set on the graphics device to indicate how streams of bytes are organized.
A vertex declaration is represented by an array of vertex elements. A vertex element is the base structure that defines one element of a vertex. For example, a vertex which contains information on position, normal and texture coordinates, would have three vertex elements, one for position, one for the normal and one for the texture coordinates. Below you can see the attributes of a vertex element.
- stream – stream index to use
- offset – offset to the beginning of the data
- element format – defines the vertex data type and size
- element method – defines the tessellation method
- element usage – defines how this data should be used
- usage index – allows specification of multiple data with the same usage. Usage index is used to differentiate between them
The first three attributes determine how and where the data corresponding to this element data is positioned in the byte stream. The usage and usage index together specify the logical meaning of the data, which maps directly to a semantic. Consider the following declaration.
VertexElement texCoords2 = new VertexElement(0,
12,
VertexElementFormat.Vector2,
VertexElementMethod.Default,
VertexElementUsage.TextureCoordinate,
2);
This creates a new vertex element that indicates that starting from the 12th byte in the stream, there are two floats that represent texture coordinates, with usage index 2. This translates into the semantic TEXCOORD2. So when a vertex declaration containing this vertex element in on the device, the graphics hardware will read 8 bytes (two floats) starting from position 12 in the stream and assign them to a shader variable which has the semantic TEXCOORD2, is such a variable exists.
XNA contains several vertex types predefined in the language, which have an array of vertex elements attached to them, through the VertexElements member. So to create a vertex declaration that specifies vertices of type VertexPositionColorTexture, you would need to use the next line.
VertexDeclaration vdecl = new VertexDeclaration(
GraphicsDevice,
VertexPositionColorTexture.VertexElements);
Sometime you will need to learn how to define your own vertex structures, together with their arrays of vertex elements, but this will only become necessary in advanced situations.


by Dennis Brandis, on 11.19.09 @ 12:22 am
On page 4:
float4 PixelShaderFunction(float2 TexCoords : TEXCOORD0) : COLOR0
{
return tex2D(TextureSampler, input.TexCoord);
}
may be it should be:
return tex2D(TextureSampler, TexCoord);
by Catalin Zima, on 11.19.09 @ 2:16 pm
I fixed it now. Thanks!
by Crash Course in HLSL « optic rust, on 01.02.10 @ 4:43 pm
[...] What does HLSL stand for? Why was it created? How does an HLSL effect file look like? What can you do with HLSL? Catalin Zima answers these questions and more in a brilliant article introducing HLSL over at her site. Check it out here [...]
by Hassan Aly Selim, on 01.31.10 @ 8:42 pm
Thanks alot for this HLSL Crash Course =)
Now I can start writing my own Custom Shaders in XNA !
by Catalin’s XNA Experiments » Re-awarded XNA/DirectX MVP for 2010, on 04.03.10 @ 6:10 pm
[...] Crash Course in HLSL (also published [...]
by Enio, on 05.01.10 @ 3:12 pm
Thanks for your helpful explanations. Which book would be more suitable for a beginner who needs to learn everything from scratch (shaders, algebra, algorithms, and physical)? Thanks!
by Enio, on 05.02.10 @ 12:41 am
Why not develop the second part of the course with several practical examples (Blur, DOF, Sepia, etc.)?
by Crash Course in HLSL, on 06.17.10 @ 8:54 am
[...] Can be found at: http://www.catalinzima.com/?page_id=575 [...]
by Devrunner, on 07.27.10 @ 11:50 am
You’re the best.