Sign in to follow this  

Do Bowties in my mesh matter when computing tangents?

This topic is 4302 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

hi I am trying to apply reflections to my meshes with HLSL. To do so I need to add TANGENT information to the mesh, right? I am getting this output, and wondered if it mattered: D3DX: D3DXValidMesh: A bowtie was found. Bowties can be fixed by call D3DXCleanMesh D3DX: D3DXValidMesh: A bowtie is the usage of a single vertex by two separate fans of triangles. D3DX: D3DXValidMesh: The fix is to duplicate the vertex so that each fan has its own vertex. D3DX: D3DXValidMesh: Bowtie found around vertex 122 shared by faces 49 and 24 D3DX: D3DXValidMesh: Bowtie found around vertex 124 shared by faces 52 and 25 D3DX: D3DXValidMesh: Bowtie found around vertex 9 shared by faces 55 and 82 D3DX: D3DXValidMesh: Bowtie found around vertex 149 shared by faces 122 and 97 D3DX: D3DXValidMesh: Bowtie found around vertex 151 shared by faces 125 and 98 D3DX: D3DXValidMesh: Bowtie found around vertex 136 shared by faces 138 and 65 D3DX: D3DXValidMesh: Bowtie found around vertex 138 shared by faces 141 and 67 D3DX: D3DXComputeTangentFrame: Mesh is not valid D3DX: ID3DXMesh::GetFVF: The declaration cannot be converted to an FVF D3DX: ID3DXMesh::GetFVF: The declaration cannot be converted to an FVF Here's my code, its a bit rough, patched together from various examples :) Assume I;ve just loaded the mesh and materials in the usual way
	// TANGENT BUILDER--------------------------------------------------------------------------
	HRESULT hr;

	//CLEAN THE MESH
	DWORD* pAdjacency = new DWORD[m_pMesh->GetNumFaces() * 3];
	m_pMesh->GenerateAdjacency(0.0, pAdjacency);
	ID3DXMesh* cleanedMesh;
	hr = D3DXCleanMesh( D3DXCLEAN_BOWTIES, m_pMesh, pAdjacency, &cleanedMesh, pAdjacency, NULL ); 
	m_pMesh->Release();
	m_pMesh = cleanedMesh;


	// Useful for reading the mesh declaration
	//D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
	//m_pMesh->GetDeclaration(declaration);

	if ( !(m_pMesh->GetFVF() & D3DFVF_NORMAL) )
    {
        hr = m_pMesh->CloneMeshFVF( dw32BitFlag | D3DXMESH_MANAGED, 
			m_pMesh->GetFVF() | D3DFVF_NORMAL, 
			g_device, &l_pTempMesh );
        if (FAILED(hr))
		{
			StringCchPrintf( temp, 100, L"cSimpleMesh::CloneMeshFVF() - FAILED - '%s'\n", m_name );
			OutputDebugString( temp );
			SAFE_RELEASE( l_pTempMesh );
		}

        D3DXComputeNormals( l_pTempMesh, NULL );

        m_pMesh->Release();
        m_pMesh = l_pTempMesh;
    }

	// Expand the mesh to hold tangent data
    D3DVERTEXELEMENT9 decl[] =
    {
        { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, 
        { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },  
        { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
        { 0, 32, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0 }, 
        D3DDECL_END()
    };

    hr = m_pMesh->CloneMesh( dw32BitFlag | D3DXMESH_MANAGED, decl, g_device, 
		&l_pTempMesh );
    if (FAILED(hr))
	{
		StringCchPrintf( temp, 100, L"cSimpleMesh::CloneMesh() - FAILED - '%s'\n", m_name );
		OutputDebugString( temp );
		SAFE_RELEASE(l_pTempMesh);	
		return;
	}

    hr = D3DXComputeTangent( l_pTempMesh, // input mesh 
		0, // TexStageIndex 
		0, // TangentIndex 
		0, // BinormIndex 
		0, // Wrap 
		NULL // Adjacency 
		);

    m_pMesh->Release();
    m_pMesh = l_pTempMesh;


	// END OF TANGENT BUILDER ----------------------------------------------------------------------

    // Done with the material buffer
    m_pD3DXMtrlBuffer->Release();
But I still get the same output, even with the D3DXCleanMesh bit added.... Should I worry? I think its works with the HLSL effect, but then I dont know what thats supposed to look like! Many thanks Si

Share this post


Link to post
Share on other sites
Thats interesting....

I have a seperate problem with my environment mapping. Its not reflecting the environment map ( a cube map), instead its reflecting a 2d texture (the one the vehicle uses without shaders )... Not sure how I've achieved that yet!

Share this post


Link to post
Share on other sites
Heres the effect:

// cubeMapFX.fx - reflects cubic texture


// Light direction (view space)
float3 LightDir < string UIDirectional = "Light Direction"; > =
normalize(float3(0.5, -0.5, 0));


// Light intensity
float4 I_a = { 0.0f, 0.0f, 0.0f, 1.0f }; // ambient
float4 I_d = { 1.0f, 1.0f, 1.0f, 1.0f }; // diffuse


// Material reflectivity
float4 k_a : MATERIALAMBIENT = { 1.0f, 1.0f, 1.0f, 1.0f }; // ambient
float4 k_d : MATERIALDIFFUSE = { 1.0f, 1.0f, 1.0f, 1.0f }; // diffuse

// Texture
texture Environment; // cubemap


// Transformations
float4x4 WorldView : WORLD;
float4x4 Projection : PROJECTION;

struct VS_OUTPUT
{
float4 Position : POSITION;
float4 Diffuse : COLOR0;

float3 Reflection : TEXCOORD0;
float3 Glossiness : TEXCOORD1;
float3 HalfVector : TEXCOORD2;
};

// Vertex shader
VS_OUTPUT VS(
float3 Position : POSITION,
float3 Normal : NORMAL,
float3 Tangent : TANGENT)
{
VS_OUTPUT Out = (VS_OUTPUT)0;

LightDir = -LightDir;

float3 P = mul(float4(Position, 1), (float4x3)WorldView); // position (view space)
float3 N = normalize(mul(Normal, (float3x3)WorldView)); // normal (view space)
float3 T = normalize(mul(Tangent, (float3x3)WorldView)); // tangent (view space)
float3 B = cross(N, T); // binormal (view space)
float3 R = normalize(2 * dot(N, LightDir) * N - LightDir); // reflection vector (view space)
float3 V = -normalize(P); // view direction (view space)
float3 G = normalize(2 * dot(N, V) * N - V); // glance vector (view space)
float3 H = normalize(LightDir + V); // half vector (view space)
float f = 0.5 - dot(V, N); f = 1 - 4 * f * f; // fresnel term

// Position
Out.Position = mul(float4(P, 1), Projection);

// Diffuse + ambient
//Out.Diffuse = I_a * k_a + I_d * k_d * max(0, dot(N, L));
Out.Diffuse = I_a * k_a + I_d * k_d * max(0, dot(N, LightDir));

// Glossiness
Out.Glossiness = f * float4( 0.7,0.7,0.7,0.0 );

// Transform half vector into vertex space
Out.HalfVector = float3(dot(H, N), dot(H, B), dot(H, T));
Out.HalfVector = (1 + Out.HalfVector) / 2; // bias

// Environment cube map coordinates
Out.Reflection = float3(-G.x, G.y, -G.z);

return Out;

}

sampler Sampler0 = sampler_state
{
texture = (Environment);
AddressU = CLAMP;
AddressV = CLAMP;
AddressW = CLAMP;
MIPFILTER = LINEAR;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
};


float4 PS(VS_OUTPUT In) : COLOR
{
float4 Color = (float4)0;
float3 Diffuse, Gloss;

Diffuse = In.Diffuse;// * Noise.a;
Gloss = texCUBE(Sampler0, In.Reflection) * saturate(In.Glossiness);
Color.rgb = Diffuse + Gloss;
Color.w = 1;

return Color;
}

technique tCubeMap
{
pass P0
{
CullMode = CCW;

// Shaders
VertexShader = compile vs_1_1 VS();
PixelShader = compile ps_1_1 PS();
}
}



Heres the render call:


if ( m_effect && g_useShaders )
{
D3DXVECTOR4 tempVec = D3DXVECTOR4( g_lightDirection, 1.0f );

m_effect->SetTexture("Environment", m_environment );
// m_effect->SetTexture("Tex1", m_backgroundTexture);
// m_effect->SetTexture("Tex2", m_detailTexture );

D3DXMATRIX worldView;
D3DXMatrixMultiply( &worldView, &m_worldMatrix, g_camera->GetViewMatrixPtr() );
m_effect->SetMatrix("WorldView", &worldView); // world matrix is Identity so no calc required.
m_effect->SetMatrix("Projection", g_simulation->GetProjMatrixPtr() );
m_effect->SetVector( "LightDir", &tempVec);
m_effect->SetFloatArray( "I_a", g_ambient, 4 );

m_effect->SetTechnique("tCubeMap");


UINT numPasses;//, iPass;
hr = m_effect->Begin( &numPasses, 0 );
// for( iPass = 0; iPass < numPasses; iPass ++ )
hr = m_effect->BeginPass( 0 );

// Render the object's mesh.
m_mesh->Render( selected );

m_effect->EndPass();
m_effect->End();


}

Share this post


Link to post
Share on other sites
That looks very complicated, here's mine:


float4x4 matWorld : M_W;
float4x4 matViewProj : M_VP;
float4x4 matWorldViewProj : M_WVP;

float3 cameraPosition : F_CP;

textureCUBE cubemap : T_0;

sampler CMSampler = sampler_state
{
texture = ( cubemap );
};

struct VS_INPUT
{
float4 Position : POSITION;
float3 Normal : NORMAL;
};

struct VS_OUTPUT
{
float4 Position : POSITION;
float3 Normal : TEXCOORD0;
float3 EyeToVert : TEXCOORD1;

};

VS_OUTPUT vs_main(VS_INPUT input)
{
VS_OUTPUT output = (VS_OUTPUT) 0;
output.Position = mul( input.Position, matWorldViewProj );
output.Normal = mul( input.Normal, matWorld );

output.EyeToVert = normalize( mul( input.Position, matWorld ) - cameraPosition );
output.EyeToVert = reflect( output.EyeToVert, output.Normal );
return output;
}

float4 ps_main( VS_OUTPUT input ) : COLOR
{
return texCUBE( CMSampler, input.EyeToVert );
}

technique cel
{
pass P0
{
VertexShader = compile vs_2_0 vs_main();
PixelShader = compile ps_2_0 ps_main();
}
}




I would try making sure that the look up does everything right, before you have glossiness factors and the like. Other than that the only difference i can see isthat i have used textureCUBE instead of just texture for passing it in.


Hope that helps,

Dave

Share this post


Link to post
Share on other sites
Thanks, I'll give it a try... Strangley, the wrong texture on the reflection was caused by a device->SetTexture call within the mesh rendering function.

Didnt think that device textures changed effect textures. There you go.

So, dave, just ignore the bowtie warnings?

Si

Share this post


Link to post
Share on other sites
Well i would fix them if validate mesh throws that warning, especially if there is a D3DX method to do it. Chances are that the shared vertex won't effect your environment map, but validate mesh doesn't know your implementation so it is prolly warning you because some effects would need indpendant vertices.

Dave

Share this post


Link to post
Share on other sites
Dave,

That shader is beautifully simple. Seems the reflect HLSL function is doing what I am doing in maths anyway.

Spotted a small problem tho - if you rotate the craft around the y axis, the reflection inverts. Heres one direction:



Heres 180degrees later:



Any idea why this is? maybe its coz I am passing a rotated translation matrix as the WVP?

Heres my effort working properly:



Ta

Simon

Share this post


Link to post
Share on other sites

This topic is 4302 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this