Advertisement Jump to content
Sign in to follow this  
hupsilardee

Tangents for heightmap from limited information

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

(solved)

 

Hi all, I'm working on normal mapping for my terrain. My terrain system calculates a normal map on the fly when a heightmap is loaded (or generated), which means I can use per-pixel normals. This makes distant terrain look a lot nicer. However, I am wondering if there is a clever way to calculate the tangent space for normal mapping, given some extra information

 

1. You are given the normal for a pixel, and this is already normalized

2. The first tangent is guaranteed to have X component = 0, because it's just a straightforward texture-splattedgrid geometry

3. Similarly, the second tangent has Z component = 0

4. Tangent space should be orthonormal

 

How can I fill in the unknowns in the most performance-friendly way possible?

 

Normal: (nx, ny, nz)

Tangent: (0, ?, ?)

Bitangent (?, ?, 0)

 

EDIT: Solved it.

// tangent known to be perpendicular to normal
dot(n, t) = 0
nx*tx + ny*ty + nz*tz = 0
 
// x component is 0
ny*ty + nz*tz = 0
 
// length of tangent is 1
ty*ty + tz*tz = 1
 

Now I have 2 equations for 2 unknowns which gives the z component as solution to a quadratic, where I'll take the positive answer! and I can work out the bitangent similarly, or use a cross product

Edited by hupsilardee

Share this post


Link to post
Share on other sites
Advertisement

Since the tangent has the X component = 0 you can assume that the tangent might be (0,0,1) so you can calculate the tangent basis with two cross products:

temp_tangent = ( 0, 0, 1 )

bitangent = cross( temp_tangent, normal )

tangent = cross( normal, bitangent )

float3x3 TBN = float3x3( tangent, bitangent, normal )
Edited by TiagoCosta

Share this post


Link to post
Share on other sites

Thanks for the alternative! Your method actually looks faster.

(While we're here, would anyone mind reassuring me that this HLSL code to calculate the normal from the heightfield is actually correct?)

 

float hxm = Heightmap.Load(int3(iPos.x-1, iPos.y, 0)).r;
float hxp = Heightmap.Load(int3(iPos.x+1, iPos.y, 0)).r;
float hzm = Heightmap.Load(int3(iPos.x, iPos.y-1, 0)).r;
float hzp = Heightmap.Load(int3(iPos.x, iPos.y+1, 0)).r;
float h = Heightmap.Load(int3(iPos.x, iPos.y, 0)).r;

float3 t1 = float3(2, hxp - hxm, 0);
float3 t2 = float3(0, hzp - hzm, 2);
    
float3 n = cross(t2, t1);

Share this post


Link to post
Share on other sites

 

Thanks for the alternative! Your method actually looks faster.

(While we're here, would anyone mind reassuring me that this HLSL code to calculate the normal from the heightfield is actually correct?)

float hxm = Heightmap.Load(int3(iPos.x-1, iPos.y, 0)).r;
float hxp = Heightmap.Load(int3(iPos.x+1, iPos.y, 0)).r;
float hzm = Heightmap.Load(int3(iPos.x, iPos.y-1, 0)).r;
float hzp = Heightmap.Load(int3(iPos.x, iPos.y+1, 0)).r;
float h = Heightmap.Load(int3(iPos.x, iPos.y, 0)).r;

float3 t1 = float3(2, hxp - hxm, 0);
float3 t2 = float3(0, hzp - hzm, 2);
    
float3 n = cross(t2, t1);
float hxm = Heightmap.Load(int3(iPos.x-1, iPos.y, 0)).r;
float hxp = Heightmap.Load(int3(iPos.x+1, iPos.y, 0)).r;
float hzm = Heightmap.Load(int3(iPos.x, iPos.y-1, 0)).r;
float hzp = Heightmap.Load(int3(iPos.x, iPos.y+1, 0)).r;
float h = Heightmap.Load(int3(iPos.x, iPos.y, 0)).r;

float3 n = 2.0 * float3(hxp - hxm, 2, hzp - hzm); //2.0 * can be optimized off if normalized

Optimized version.

Edited by kalle_h

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!