Shaderx5 2.6normalmappingwithoutprecomputedtangents 130318 (1)

1,471 views

Published on

Published in: Technology, Business
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,471
On SlideShare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
6
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Shaderx5 2.6normalmappingwithoutprecomputedtangents 130318 (1)

  1. 1. ShaderX5 2.6 Normal Mapping without Precomputed Tangents Christian Schuler, Phenomic ShaderStudy 2013.03.18 황규석 http://cafe.naver.com/shader
  2. 2. Introduction  TBN Matrix(Tangent Frames)를 Pixel Shader에서 실시간으로 계산하는 방법  장점 - Vertex attributes에 Tangent Frames를 넣어 줄 필요가 없다 • Band width, Memory, Complexity 감소 • 그래픽 디자이너가 툴에서 이것을 신경 쓸 필요가 없다  단점 - Pixel Shader에서의 부하, Optimization 필수  Cotangent Frames - More optimization
  3. 3. TBN matrix
  4. 4. Normal Texture Mapping ©http://marupeke296.com Normal 벡터를 Texture 좌표계(공간)에서 Local 좌표계(공간)로 변환 new = [dot(old, X), dot(old, Y), dot(old, Z)] (X, Y, Z는 new 좌표계에서 표현되는 old 좌표계 basis vectors, e.g. T, B, N)
  5. 5. Tangents to a surface Position 벡터(p1, p2)와 Texture 좌표 벡터(u1, u2, v1, v2)를 이용해 Tangent 벡터(T, B) 계산
  6. 6. // A code snippet to perform normal perturbation using a tangent-space normal map float3 perturb_normal(float3 T, float3 B, float3 N, float2 texcoord) { // Build a tangent frame as float3x3 for convenience float3x3 tangent_frame = float3x3(T, B, N); // Read the perturbed normal from the normal map float3 perturbed_normal = tex2D(normalmap, texcoord); // Sign-expand (for a normal map in unsigned RGB format) perturbed_normal = 2 * perturbed_normal – 1; // And transform the perturbed normal out of tangent space // (into whatever space T, B and N were originally expressed in, usually world). return normalize( mul( perturbed_normal, tangent_frame)); } Tangent space Normal mapping
  7. 7. // A function that takes an interpolated surface normal N, a position vector p, // and texture coordinates u and v and returns a complete tangent frame that is // ready to be used in lighting calculations (46 pixel shader instructions) float3x3 compute_tangent_frame(float3 N, float3 p, float2 uv) { // Get edge vectors of the pixel triangle float3 dp1 = ddx(p); // 가로 방향의 옆 픽셀과의 Position 변화량 float3 dp2 = ddy(p); // 세로 방향의 옆 픽셀과의 Position 변화량 float2 duv1 = ddx(uv); // 가로 방향의 옆 픽셀과의 UV값 변화량 float2 duv2 = ddy(uv); // 세로 방향의 옆 픽셀과의 UV값 변화량 // Solve the linear system float3x3 M = float3x3(dp1, dp2, cross(dp1, dp2)); float3x3 inverseM = invert_3x3(M); float3 T = mul(inverseM, float3(duv1.x, duv2.x, 0)); float3 B = mul(inverseM, float3(duv1.y, duv2.y, 0)); // Construct tangent frame // (* see discussion regarding the square patch assumption) float maxLength = max(length(T), length(B)); return float3x3 (T / maxLength, B / maxLength, N); } float3x3 invert_3x3(float3x3 M) { float det = dot( cross(M[0], M[1]), M[2] ); float3x3 T = transpose(M); return float3x3( cross(T[1], T[2]), cross(T[2], T[0]), cross(T[0], T[1]) ) / det; } Moving to the Pixel Sahder
  8. 8. // Optimization 1: // normalize T and B and spare the determinant. // (31 pixel shader instructions) float3x3 compute_tangent_frame_01(float3 N, float3 p, float2 uv) { // Get edge vectors of the pixel triangle float3 dp1 = ddx(p); float3 dp2 = ddy(p); float2 duv1 = ddx(uv); float2 duv2 = ddy(uv); // Solve the linear system float3x3 M = float3x3(dp1, dp2, cross(dp1, dp2)); float3x3 inverseM = invert_3x3_nodet(M); float3 T = mul(inverseM, float3(duv1.x, duv2.x, 0)); float3 B = mul(inverseM, float3(duv1.y, duv2.y, 0)); // Construct tangent frame return float3x3(normalize(T), normalize(B), N); } float3x3 invert_3x3_nodet(float3x3 M) { float3x3 T = transpose(M); return float3x3( cross(T[1], T[2]), cross(T[2], T[0]), cross(T[0], T[1]) ); } Optimization 1
  9. 9. // Optimization 2: // exploits the zero components found in the solution vectors and collapses // a hidden double transpose // (17 pixel shader instructions) float3x3 compute_tangent_frame_02(float3 N, float3 p, float2 uv) { // Get edge vectors of the pixel triangle float3 dp1 = ddx(p); float3 dp2 = ddy(p); float2 duv1 = ddx(uv); float2 duv2 = ddy(uv); // Solve the linear system float3x3 M = float3x3(dp1, dp2, cross(dp1, dp2)); float3x3 inversetransposeM = float2x3( cross(M[1], M[2]), cross(M[2], M[0]) ); //inversetranspose = original float3 T = mul(float2(duv1.x, duv2.x), inversetransposeM); float3 B = mul(float2(duv1.y, duv2.y), inversetransposeM); // Construct tangent frame return float3x3(normalize(T), normalize(B), N); } Optimization 2
  10. 10. // Optimization 3: // assume M is orthogonal and exploits the fact that we have made an inverse transpose explicit. // (14 pixel shader instructions) float3x3 compute_tangent_frame_03(float3 N, float3 p, float2 uv) { // Get edge vectors of the pixel triangle float3 dp1 = ddx(p); float3 dp2 = ddy(p); float2 duv1 = ddx(uv); float2 duv2 = ddy(uv); // Solve the linear system // (not much solving is left going here) float2x3 M = float2x3(dp1, dp2); float3 T = mul(float2(duv1.x, duv2.x), M); float3 B = mul(float2(duv1.y, duv2.y), M); // Construct tangent frame return float3x3(normalize(T), normalize(B), N); } Optimization 3
  11. 11. Conclusion  TBN matrix 계산을 Pixel shader에서 낮은 비용으로 하는 방법 제 공함  Vertex 속성에서 Tangent frames를 제거할 수 있지만 픽셀셰이더 에서 부하가 증가  텍스처 좌표 공간에서의 procedural 처리도 가능한 방법  추가적으로 Cotangent frames를 이용한 방법을 블로그에 소개하 고 있음 
  12. 12. A vector v (red) represented by tangent basis vectors (yellow, left: e1, e2, e3) to the coordinate curves (black), · dual basis, covector basis, or cobasis (blue, right: e1, e2, e3 ), normal vectors to coordinate surfaces (grey), in 3D general curvilinear coordinates (q1, q2, q3), a tuple of numbers to define point in a position space. Note: the basis and cobasis do not coincide unless the basis is orthogonal. Tangent and Contangent basis vectors ©wikipedia
  13. 13. // compute contangent frames mat3 contangent_frame(vec3 N, vec3 p, vec2 uv) { // Get edge vectors of the pixel triangle vec3 dp1 = dFdx(p); vec3 dp2 = dFdy(p); vec2 duv1 = dFdx(uv); vec2 duv2 = dFdy(uv); // Solve the linear system vec3 dp2perp = cross(dp2, N); vec3 dp1perp = cross(N, dp1); vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; // Construct a scale-invariant frame float invmax = inversesqrt(max(dot(T,T), dot(B,B)); return mat3(T * invmax, B * invmax, N); } vec3 pertub_normal(vec3 N, vec3 V, vec2 texcoord) { // assume N, the interpolated vertex normal and // V, the view vector(vertex to eye) vec3 map = texture2D(mapBump, texcoord).xyz; #ifdef WITH_NORMALMAP_UNSIGNED map = map * 255./127. – 128./127.; #endif #ifdef WITH_NORMALMAP_2CHANNEL map.z = sqrt(1. – dot(map.xy, map.xy)); #endif #ifdef WITH_NORMALMAP_GREEN_UP map.y = -map.y; #endif mat3 TBN = cotangent_frame(N, -V, texcoord); return normalize(TBN * map); } Contangent Frames
  14. 14. varying vec3 g_vertexnormal; varying vec3 g_viewvector; // camera pos – vertex pos varying vec2 g_texcoord; void main() { vec3 N = normalize(g_vertexnormal); vec3 V = normalize(g_viewvector); #ifdef WITH_NORMALMAP N = perturb_normal(N, V, g_texcoord); #endif // ... } Contangent Frames (cont.) Reference (Followup) Normal mapping without precomputed tangents http://www.thetenthplanet.de/archives/1180 Covariance and contravariance of vectors http://en.wikipedia.org/wiki/Covariance_and_contravariance_of_vectors Fast inverse square root http://en.wikipedia.org/wiki/Fast_inverse_square_root

×