Jump to content
  • Advertisement
Sign in to follow this  
Mr Kickass

D3DXComputeTangentFrame() woes

This topic is 4845 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I find D3DXComputeTangentFrame() hardley ever works on any .X files - in fact the only one that it does work with that comes with the DirectX sdk is the "cell.x" one and I think it is mangleing the calculations because I am sure the effect is right (normal mapping), but it just looks jacked up (i.e. a light will appear to move across one wall and wall immediatly adjacent to it will look totally dark when the light should be moving across it). I always get errors like "bowtie found" and "can't compute tangent frame on mesh without splitting verticies" in the debug window. I can get rid of the bowtie errors with a D3DX function but it still won't compute the tangents. How do I get it to work? Is there a site somewhere that has .X files that will just work with d3dxcomputetagentframe()? I just need one that works to make the shaders with.

Share this post


Link to post
Share on other sites
Advertisement
Hi there Mr. Kickass,
How are you doing?

[The theory]
For D3DXComputeTangentFrame to work you will need to actually clone with mesh with the correct vertex format, in a loose sense, make space for the tangent and binormal vectors.

[The solution]
So how do I do that you ask?
You first need to create a new vertex declaration that will define:
a Position
a Normal
a Texture Coordinate
a Tangent
a BiNormal (BiTangent)

Then clone the texture with the new vertex format, this will make space for each vertex in the mesh for the needed components. If it sounds a bit messy.

Well let me give you the code in C# and C++

c++
[source lang = c++]
D3DVERTEXELEMENT9 elements[] =
{
{ 0, sizeof( float ) * 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, sizeof( float ) * 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
{ 0, sizeof( float ) * 6, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{ 0, sizeof( float ) * 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0 },
{ 0, sizeof( float ) * 15, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0 },
D3DDECL_END()
};

LPD3DXMESH temp;
if ( FAILED( pMesh->CloneMesh( D3DXMESH_MANAGED, elements, pDevice, &temp ) ) )
{
pMesh = NULL;
return;
}

pMesh->Release();
pMesh = temp;

D3DXComputeTangentFrame(pMesh, 0);






C#
[source lang = c#]
//load the mesh
mesh = Mesh.FromFile(meshFilename, MeshFlags.Managed, device);

//Vertex elements that describe the new format of the mesh
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.TextureCoordinate, 0),
new VertexElement(0, 36, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Tangent, 0),
new VertexElement(0, 48, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.BiNormal, 0),
VertexElement.VertexDeclarationEnd,
};
VertexDeclaration decl = new VertexDeclaration(device, elements);
Mesh tempMesh = mesh.Clone(MeshFlags.Managed, elements, device);
mesh.Dispose();
mesh = tempMesh;





The Shader
[source lang = c++]
float4x4 ModelViewProj : WORLDVIEWPROJ; //our world view projection matrix
float4x4 ModelViewIT : WORLDVIEWIT; //our inverse transpose matrix
float4x4 ModelWorld : WORLD; //our world matrix
float4 lightPos; //our light position
float4 eyePos;

texture texture0;
texture texture1;

sampler2D texSampler0 : TEXUNIT0 = sampler_state
{
Texture = (texture0);
MIPFILTER = LINEAR;
MAGFILTER = LINEAR;
MINFILTER = LINEAR;
};
sampler2D texSampler1 : TEXUNIT1 = sampler_state
{
Texture = (texture1);
MIPFILTER = LINEAR;
MAGFILTER = LINEAR;
MINFILTER = LINEAR;
};

//application to vertex structure
struct a2v
{
float4 position : POSITION0;
float3 normal : NORMAL;
float2 tex0 : TEXCOORD0;
float3 tangent : TANGENT;
float3 binormal : BINORMAL;
};

//vertex to pixel shader structure
struct v2p
{
float4 position : POSITION0;
float2 tex0 : TEXCOORD0;
float2 tex1 : TEXCOORD1;
float3 lightVec : TEXCOORD2;
float att : TEXCOORD3;
float3 vHalf : TEXCOORD4;
};

//pixel shader to screen
struct p2f
{
float4 color : COLOR0;
};

//VERTEX SHADER
void vs( in a2v IN, out v2p OUT )
{
//getting to position to object space
OUT.position = mul(IN.position, ModelViewProj);

//getting the position of the vertex in the world
float4 posWorld = mul(IN.position, ModelWorld); //IN.position;

//getting vertex -> light vector
float3 light = normalize(lightPos - posWorld);

//getting the eye -> eye Vector
float3 eye = normalize(eyePos - light);

//placing the half vector in the object space
float3 vHalf = normalize(eye - lightPos);

//calculating the binormal and setting the Tangent Binormal and Normal matrix
float3x3 TBNMatrix = float3x3(IN.tangent, IN.binormal , IN.normal);

//setting the lightVector
OUT.lightVec = mul(TBNMatrix, light);

//setting the half vector and passing it to the pixel shader
OUT.vHalf = mul(TBNMatrix, vHalf);

//calculate the attenuation
OUT.att = 1/( 1 + ( 0.005 * distance(lightPos.xyz, posWorld) ) );

OUT.tex0 = IN.tex0;
OUT.tex1 = IN.tex0;
}

//PIXEL SHADER
void ps( in v2p IN, out p2f OUT )
{
//calculate the color and the normal
float4 color = tex2D(texSampler0, IN.tex0);

/*this is apparently how you uncompress a normal map*/
float3 normal = 2.0f * tex2D(texSampler1, IN.tex1).rgb - 1.0f;

//normalize the light
float3 light = normalize(IN.lightVec);

//normalize the half vector
float3 vHalf = normalize(IN.vHalf);

//set the output color
float diffuse = saturate(dot(normal, light));

//calculating the specular component
float specular = pow(dot( normal, IN.vHalf) , 16);

//setting ds(diffuse * specular)Color
float dsColor = 2.0 * (diffuse * specular) + 1.0; //last part is ambient

//multiply the attenuation with the color
OUT.color = IN.att * color * dsColor;
}

technique bump
{
pass p0
{
vertexshader = compile vs_1_1 vs();
pixelshader = compile ps_2_0 ps();
}
}




If you have any further problems with your shader etc...
Check out my tutorial on Normal mapping

I hope this helps a bit,
keep cool.

Share this post


Link to post
Share on other sites
Used D3DXComputeTangent() instead and it works... Hmmm... Should have tried that a couple days ago.

I was already cloning the mesh with needed information, but your tutorial has been most useful - I was already using that resource - thanks :D

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!