# Calculating tangents in a different way

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

## Recommended Posts

For my voxel terrain editor, I need to calculate tangents for all generated vertices. By using the method of taking the UV coords, it produces bad results, because this terrain is using tri-planar texturing (3 sets of UV coords, interpolated using the normal).

If I understand correctly, the tangent and bitangent vectors are perpendicular to the normal, and follow the direction of the U and V.

My UVs are ourrently generated from the position of the vertices, something like
U = vertex.y * UVScale
V = vertex.y * UVScale
W = vertex.z * UVScale

I tried using the face normals to select the two coords of the the three (eg: when the face normal is pointing to the Y direction, pick X and Z for uvs).
This doesnt produce smooth tangent vectors.

Since the UVs are dependent from the position, we can assume they're always pointing in the positive direction, and somehow calculate a perpendicular vector to the normal, to get the tangent?

##### Share on other sites
Quote:
 Original post by Relfos...

If you only have one vector to start with, I think this might work... I think JYK showed me something like this once:

1) Find out which of the normal vector's components (N.x, N.y, or N.z) is the shortest/of the smallest value. For example, let's say that we've found the N.x component to be the shortest...

2) Make a second vector B, where the B.x component is of length 1, and the B.y and B.z components are of length 0. Again, I focus on N.x and B.x here only because I'm giving a specific example. It could have been N.y or N.z that was the shortest in the previous step.

3) Take the cross product of NxB = C to get a third vector.

4) The chances of C being of unit length by default is very very slim, so you must normalize C before continuing.

5) Take the cross product of CxN = B to get a final version of B.

You should now have a basis consisting of three orthogonal unit vectors N, B and C.

##### Share on other sites
If you can get access to a copy of ShaderX5 there is an article about building tangent frames in the pixel shader using the ddx and ddy instructions. I've never tried it but maybe it is useful to you: 2.6 Normal Mapping without Pre-Computed Tangents by Christian Schueler

##### Share on other sites
Congratulations on your degree. That's totally awesome that your terrain editor is like a mini-3D paint/clay modeling program, with texture brushes and all. :)

I see the chapter 5.5.2 Tangent Space.

Please correct me if I'm wrong: basically you use the two tangent fields to avoid coordinate singularities? If so, is this is to do with making the surfaces orientable? I know these sound like silly questions, but I'm still learning a lot, and I ask honestly. :)

##### Share on other sites
Relfos, I think I have done just the same thing like you in my engine (With the PolyVox library).

I would find it very cool when I could see yours [smile]
Here's a news-posting explaining my terrain editors layer system (And a video!):
http://www.moddb.com/engines/wtech/news/wtech-voxel-based-terrain-layers-via-deferred-rendering

As you see, I am using triplanar texturing with normal mapping as well.

To get the tangents, I got some code from Nvidias GPU Gems 3 and modified it to fit my needs:

float3 GetTriPlanarNrmMap(Texture2D yzTexture,Texture2D zxTexture,Texture2D xyTexture,float2 TexScale, float NrmMapDepth, PixelShaderInput Input, float3 VertexPos, float3 Normals){		// Determine the blend weights for the 3 planar projections.	// N_orig is the vertex-interpolated normal vector.	float3 blend_weights = abs( Normals );	// Tighten up the blending zone:	blend_weights = (blend_weights +WEIGHT_BIAS) * WEIGHT_MUL;	blend_weights = max(blend_weights, 0);	// Force weights to sum to 1.0 (very important!)	blend_weights /= (blend_weights.x + blend_weights.y +	blend_weights.z ).xxx;	// Now determine a color value and bump vector for each of the 3	// projections, blend them, and store blended results in these two	// vectors:	float4 blended_color;  // .w hold spec value	float3 blended_bump_vec;		// Compute the UV coords for each of the 3 planar projections.	// tex_scale (default ~ 1.0) determines how big the textures appear.	float2 coord1 = (VertexPos.yz * TexScale);	float2 coord2 = (VertexPos.zx * TexScale);	float2 coord3 = (VertexPos.xy * TexScale);	// This is where you would apply conditional displacement mapping.	//if (blend_weights.x > 0) coord1 = . . .	//if (blend_weights.y > 0) coord2 = . . .	//if (blend_weights.z > 0) coord3 = . . .		// Sample bump maps too, and generate bump vectors.	// (Note: this uses an oversimplified tangent basis.)	float2 bumpFetch1 = (TexUV(Tex2,coord1).xy -0.5)*NrmMapDepth;	float2 bumpFetch2 = (TexUV(Tex2,coord2).xy -0.5)*NrmMapDepth;	float2 bumpFetch3 = (TexUV(Tex2,coord3).xy -0.5)*NrmMapDepth;	float3 bump1 = float3(0, bumpFetch1.x, bumpFetch1.y);	float3 bump2 = float3(bumpFetch2.y, 0, bumpFetch2.x);	float3 bump3 = float3(bumpFetch3.x, bumpFetch3.y, 0);	blended_bump_vec = bump1.xyz * blend_weights.xxx +				     bump2.xyz * blend_weights.yyy +				     bump3.xyz * blend_weights.zzz;	return blended_bump_vec;}

To use what this generates, you simply need to add the result of the function to your mesh's normal-vector.

I hope this could be useful for you.

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 9
• 11
• 15
• 21
• 26