The Semantics such as POSITION0 are sort of a mixed bag of purely "hint" semantics and some with relevant purposes and repercussions. For example, the Vertex Shader must output a POSITION0 semantic. Failure to do so and the code simply won't compile. Also, as an input the Position variable is a float4, but in XNA you send position as a Vector3. There's one less float going in than what's going out! Because the semantic is POSITION, the 4th component is automatically set to 1 if it isn't provided. If the semantic were TEXCOORD instead, the value of the W component would default to 0 and the shader would likely not draw correctly. The reason this happens is because most of the time that value is going to be 1 anyway, so just assuming it to be 1 unless told otherwise means you can send more vertices in the same amount of space.
Pixel Shader semantics are slightly more confusing, for instance your vertex shader MUST output a variable with the POSITION0 semantic. If there is no semantic like that, the code won't compile. That stated, trying to manipulate or read the value attached to the POSITION0 semantic in the pixel shader will usually cause a compile error. This is because the POSITION0 semantic doesn't really get passed to the Pixel Shader. This leads to some code that tends to confuse people when they first see it, if you do need to use the pixel position in the pixel shader, for example to calculate shadows, it might look like this:
| struct VertexShaderOutput |
| { |
| float4 Position : POSITION0; |
| float2 TextureCoordinate : TEXCOORD0; |
| float4 CurrentPosition : TEXCOORD1; |
| } |
Notice the CurrentPosition is a TEXCOORD. Pixel Shaders don't really have very many valid semantics. You tend to stick with a POSITION0 and then lots of TEXCOORDS for everything else. In the vertex shader the coder fills CurrentPosition simply as:
output.CurrentPosition = output.Position;
I tell you this, the first time I saw this code I "optimized" CurrentPosition away and sat for hours trying to figure out how to get the code to compile because the compile error for doing that is VERY unhelpful, but I think that might be fixed in the next release. Anyway, that's also why there's a number in the back of the semantic. If there wasn't, you'd only have two semantics you could use and POSITION0 has already been earmarked. So you'd only have one semantic to work with!
| struct VertexShaderOutput |
| { |
| float4 Position : POSITION; |
| float4x4 TexCoordLightPowerReflectionRefractionObjectPositionCameraPositionNormalOtherStuffEtc : TEXCOORD; |
| } |
Hooray for numbered semantics, huh?
Another cool thing you can do with Semantics is to draw to multiple render targets with one effect. You're probably familiar with GraphicsDevice.SetRenderTarget(0, someRenderTarget); But have you ever wondered why you always put a zero there too? Try setting a one and a two as well and you can write a pixel shader that outputs to multiple COLOR semantics. Pretty cool, huh? Some good candidates for COLOR1 and COLOR2 include the pixel's Normal and Depth from the camera. These allow you to write lighting shaders, post processing effects like Depth of Field, etc.
| struct PixelShaderOutput |
| { |
| float4 Color : COLOR0; |
| float4 Normal : COLOR1; |
| float4 Depth : COLOR2; |
| }; |
Regarding the naming, you're right that's a bad name. I've never seen anyone call their texture register Texture before. Encasing () around the name requests the compiler to take the name literally rather than attempt to compile it as an instruction. Its the same thing you have to do in stored procedures working with databases if you have a table named Transaction, a column named Date, etc, since the object names are the same as instructions in the language.
Much better to write that as:
| texture ColorMap; |
| sampler ColorMapSampler = sampler_state |
| { |
| Texture = ColorMap; |
| |
| .... |
| }; |
Now you can very clearly see which parts are variable names and not instructions. You write a new sampler for each texture registered. Samplers are used for the texture look-ups in the shaders like this:
float4 color = tex2d(ColorMapSampler, input.TexCoords);
And setting the ColorMap in XNA would look like this:
myEffect.Parameters["ColorMap"].SetValue(myTexture);
So pretty much the texture is the variable as XNA recognizes it and the sampler is the texture the way HLSL recognizes is.
The lower version you target, the more people who can run the program. If you're targetting 360 that isn't really a problem. I would start at 1_1, then switch to 2_0 if I got a too many instructions error. A more pure programming approach would be to start at 1_1 and upon the instructions error attempt to optimize the the HLSL code. I wouldn't recommend this to a first-timer though because there isn't exactly a one-to-one correlation between lines of code and instructions. Some lines are many instructions and sometimes you can write longer code that makes up fewer instructions.