Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Shaderx5 2.6normalmappingwithoutprecomputedtangents 130318 (1)

1,676 views

Published on

Published in: Technology, Business
  • Be the first to comment

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

×