I am having absolutely no luck with constructing my own vertex format and use it to store two normals for use in my shader.
There are a number of flags which I can set to indicate various items such as position, normal, texture etc, but there is only one normal. How do I define that I want to use both normal and normal1 and for that matter normal5
I need to have a vertex which has a position and two normals. I tried storing one normal in a color for a PositionNormalColored vertex type, but for some reason it fails. I store my normal as color by setting solor to ColorFormat(normal.x / 0.5 + 0.5, ....
in order to keep the normals values in the interval [0..1]. in the shader I convert them back again by deducting 0.5 and multiplying by two, but it fails in a way that my various debugging methods cant seem to catch. it fails with the wrong effect, not an exception, but right now I am on vs2005 which does not have the shader debugger (wonder why).
So in short.. can someone please tell me how to define a vertex format which contains a position and two normals, or perhaps why my clever normal-in-color doesn't work as expected. The normal aparently becomes scaled so the dot product with the light vector always becomes negative.

Passing two normals for a vertex to the vertex shader
doug gorman
Raiden_S
That was a great help. Thanks!
Naturally I now have new problems.
I can define the vertex format, create a vertexbuffer, fill it with data and then render it. That is without errors.
When I enable my effect, I loose visible output. It doesnt complain about errors, but the model is no longer visible.
That is even though the vertex shader as such should be ok. Now that I am testing this problem, I have shaved it down to
VS_OUTPUT RenderSceneVS(float3 position : POSITION0, float3 normal1:NORMAL2, float3 normal2:NORMAL3)
{
VS_OUTPUT Output;
Output.Position = mul(position, worldViewProjectionMatrix);
return Output;
}
The vertex has been defined as
VertexElement
[] vertexElements = new VertexElement[]{
new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0), new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 2), new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 3), VertexElement.VertexDeclarationEnd};
Apart from getting a vs2003 and debugging the shader, what can I do next I have tried with other position and normal indexes, but only POSITION0 works without an "invalid call" exception, and for normals I have to go to NORMAL2 and 3 to avoid the exception.
I assume that I can use anything I like as long as I refer to it by the same number in the shader
QEIINatTrust
normal.x / 0.5 + 0.5,
to keep in 0 to 1 range
What are the normal.x range value
-1 to 1
If you divide by 0.5 you in fact multiply by 2...
1/0.5 = 2
not what you want :-)
to fit a -1 to 1 range into a 0 to 1 range :
(normal.x+1)/2
Move up 1, scale to 0..1 range
To the the oposite
Unscale *2
And Move down by 1 (so -1)
Your way is good too, simply divide by 2 not by 0.5
Or if you want multiply by 0.5
You know all that :-)
It's just a little mistake
Chris Cardinal
The problem here could be caused by a wrong vertex declaration. The second parameter in the contructor of VertexElement is labeled offset and determines the offset from the beginning of this vertex's data to this data in bytes. Because you use DeclarationType.Float3 for Position 0 and float itself takes 4 bytes, then the position data makes the first 12 bytes of a vertex's data. When you then declare Normal i data as the next data field, you must set it's offset to 12. The same goes for Normal i + 1, which should have the offset of 24 (2 "trios" of 4-byte floats precede this data in the format).
Your vertex declaration should then look like this :
VertexElement[] vertexElements = new VertexElement[]
{
new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
new VertexElement(0, 12, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 2),
new VertexElement(0, 24, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 3),
VertexElement.VertexDeclarationEnd
};
For more info on the VertexDeclaration, VertexElement and all those associated enumerations, use the SDK Documentation. You can find a bit more in the C++ one than in the Managed one.
Docs on the offset parameter:
C++
Offset from the beginning of the vertex data to the data associated with the particular data type.
Managed
Offset (if any) from the beginning of the stream to the beginning of the vertex data.
Well, the C++ version sounds much more right to me than the Managed one.
Cheers
Jurassic
Peter Zabback
I am sorry about that error. It was only in the post though - not in the code.
to store it in color i do
ColorValue((float)(nx/2.0+0.5),....
to extract it i do
nx = (red-0.5)*2
QldRobbo
l.walt
That was not the problem it seems.
I tried your change with the same result.
I also tried changing the format to only contain a single position and the same happened.
Besides... then my effect was not running, that same vertexbuffer with the same format rendered ok. It is only when the effect is turned on that it fails.
Thanks for your advice though. Sooner or later I would probably be crying my eyes out due t some odd error because I forgot that offset :-)
JasonMcF
As far as I could see the texture coordinates had to be 2d Perhaps I am mistaken. Even if I am not, you can do with just two and the knowledge that they are components of a vector with length 1.
I will try if I can get to that point. As it is now, I can not even get this effect to work with a vertex format containing only a position, so for now the problem is not the two normals.
DougWatt
I can't tell what's causing the strange behaviour with the data hidden in color. Probably it's somehow modified by the fixed-function pipeline.
For passing two normals in a single vertex, I would use the VertexDeclaration thingy, that is beginning to replace the more fixed-function-pipeline-like FVF codes. With that, you should be able to define a format with 3 floats for position 0, 3 floats for normal 0 and 3 floats for normal 1. This can be acheived using the DeclarationType and DeclarationUsage enumerations along with setting the apprioprite usageIndex.
Here is a tweaked version of the code from the SDK that would fit your needs.
VertexElement[] elements = new VertexElement[]
{
new VertexElement(0, 0, DeclarationType.Float3,
DeclarationMethod.Default,
DeclarationUsage.Position, 0),
new VertexElement(0, 12, DeclarationType.Float3,
DeclarationMethod.Default,
DeclarationUsage.Normal, 0),
new VertexElement(0, 24, DeclarationType.Float3,
DeclarationMethod.Default,
DeclarationUsage.Normal, 1),
VertexElement.VertexDeclarationEnd
};
VertexDeclaration decl = new VertexDeclaration(device, elements);
To set the declaration in place, use the device.VertexDeclaration property instead of setting the VertexFormat to a FVF code.
UPDATE - Just found out usage index 1 with the DeclarationUsage.Normal is used in fixed-function pipeline skinning, so you might consider using a different one. Then again, I've never tried skipping a usage index, but it should be OK.
Maclosky
I am using the effect, yes. I will try your suggestions.
If they dont do the trick, then I guess I will have to debug the shader with vs2003 and see what it is getting and what it it outputting, for this is getting silly.
That leads me to ask "why on earth is shader debugging not supported on vs2005 ". Vs2500 had been out for some time, and the betas for even longer, and still the support is missing.