Skip to main content
GameDev.net gamedev.net
🔒 Locked

Calculating tangents in a different way

Started by Ruggostein Sep 10, 2010 at 4:08 AM 4 replies 3.6k views
Original Post
Ruggostein
Ruggostein
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?
taby
taby
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.
taby
taby
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. :)
mind in a box
mind in a box
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.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.