I_dovelemon
Date: 2014/9/13
Source: CSDN
Topics: Bump Mapping, Tangent Space, Normal map, Height map
Introduction
In the previous article, I described how to create a normal map from a height diagram. And promises to tell you about the important tools in 3D geometry, tangent space, in the background. Today, we are here to tell you about the next part of the work.
Tangent Space
As we know, in the previous article, the normals in the described normal map are in the space of the texture diagram, which is also in tangent spaces. When we are doing light calculations, we need to place the light vector and the normal of the pixel in a space for light calculation. In general, the illumination vectors of light sources are in world space, and the normals are in tangent space. If we were to convert the normals of each pixel from tangent space to the world coordinate space when we were doing light calculations, we would have to do this for all the pixels, but if we did this with the light vector, we just had to vertex You can do it once in a shader. Therefore, it is natural for us to try to convert the light source vector into the same tangent space as the normal pixel.
Coordinate space transformation is the basic knowledge of 3D graphics. If the reader doesn't understand it, see the 3D coordinate transformation in my blog. In order to be able to coordinate the transformation, we need the coordinate space of the normal of the pixel to tangent space's base coordinates in the model coordinate spaces, so that we can easily transform the vector in the model coordinate space into tangent space.
So, how do you create three base vectors for tangent space?
The x-axis in Tangent space is aligned with the U-axis direction of the bump map, while the y-axis aligns with the V-axis direction of the bump map. That is, if the Q point represents a point in the triangle, then we can use the following equation to represent:
Q-p0 = (u-u0) T + (V-v0) B, (equation 1)
The T and B here are vectors aligned with the bump map. P0 is a vertex of a triangle, and (u0,v0) represents the texture coordinates of a P0 vertex. And the following B is Bitangent, some books also called Binormal.
Suppose we have a triangle whose three vertices are P0, P1, P2, and their corresponding texture coordinates are (u0,v0), (U1,V1), (U2,V2), respectively. For the sake of convenience, we will P0 as a reference point here. So, let's assume:
Q1 = P1-p0
Q2 = P2-p0
And
(S1, T1) = (u1-u0, v1-v0)
(s2, t2) = (u2-u0, v2-v0)
Since equation 1 above represents a bit of a relationship in a triangle, the same function can be satisfied for Point P1 and P2, which is to say:
Q1 = s1t + t1b
Q2 = s2t + t2b
We use matrices to solve the equation above and get the following matrix equation:
Both sides are multiplied by the inverse matrix of the (s,t) matrix, resulting in the following matrix equation:
(Equation 2)
Well, from the matrix equation above, we can get two vectors t and b.
With the t,b,n vector, we can use the following matrix to transform the coordinates of tangent space into the coordinate space of the model:
The matrix above is the transformation of the coordinates in tangent space into the model coordinate space, but what we need here is to transform the coordinates in the model coordinate space into the tangent space coordinates. So we need the inverse matrix of the matrix above. (This is actually imprecise because the n vector we used above is the normal vector direction of the vertex, which is slightly different from the n vectors in the actual tangent space, but negligible.) Since these three vectors are perpendicular to each other, then this matrix is the orthogonal matrix, and the inverse matrix of the orthogonal matrix equals its transpose matrix, so the following is the final matrix that transforms the coordinates in the model coordinate space into the tangent space:
Calculate Tangent Space
The following two functions are used to calculate the tangent vector in the vertex's tangent space coordinate vector.
<span style= "Font-family:microsoft Yahei;" >void calctangent (zfxtvertex* v) { for (int i = 0; i < 8; i + +) { &N bsp; calctangent (&v[i*3],&v[i*3+1],&v[i*3+2]); }}//end for calctangentvoid calctangent (Zfxtvertex *t1, Zfxtvertex *t2, Zfxtvertex *t3) { ZFXVector VC, VcA, VcB; float fu21 = t2->tu-t1->tu, fv21 = T2->TV-T1-&G T;tv, fu31 = t3->tu-t1->tu, fv31 = t3- >TV-T1->TV; //x-component of Tangent vector vca.set (t2->x-t1->x, FU2 1, fv21); vcb.set (t3->x-t1->x, fu31, fv31); vc.cross (VcA, VcB); if (Fabs (vc.x) > 0.0001f) { t1->vcu[0] =- vc.y/vc.x; } //y-component of Tangent vector vca.set (t2->y-t1->y, Fu21, fv21); vcb.set (T3->y-t1->y, fu31, fv31); vc.cross (VcA, VcB); & nbsp if (Fabs (vc.x) > 0.0001f) { t1->vcu[1] =-vc.y/vc.x ; } //z-component of Tangent vector vca.set (t2->z-t1->z, Fu21, fv21); vcb.set (T3->z-t1->z, fu31, fv31); vc.cross (VcA, VcB); & nbsp if (Fabs (vc.x) > 0.0001f) { t1->vcu[2] =-vc.y/vc.x ; } zfxvector Normalv (t1->vcu[0],t1->vcu[1],t1->vcu[2]); normalv.normalize (); t2->vcu[0] = t3->vcu[0] = t1->vcu[0] = normalV.x; & NBSP;T2->VCU[1] = t3->vcu[1] = T1->vCU[1] = normalv.y; t2->vcu[2] = t3->vcu[2] = t1->vcu[2] = normalv.z;} End for Calctangent</span>
The formula is fully used in the above conclusion formula and the other calculation, as long as the cross expansion, you can understand. In the function, I only calculated the T vector, not the T and B vectors as in the theory above. Because, I'm going to use the normal direction of the vertex as the n vector of tangent space, so after having T and N, we can get the B vector with the cross product operation. This decision is also reflected in the vertex structure I define, as follows:
<span style= "Font-family:microsoft Yahei;" >/*** Define the Tangent Vertex format*/typedef struct zfxtvertex_type{float x, y, z; float vcn[3]; float tu, TV; float VCU[3]; Tangent vector}zfxtvertex;</span>
function is very simple, as long as the formula, copied copy can be, there is no need to say more.
Program Examples
Now that we know how to calculate tangent space, let's use this method to build a model of the same type, which is the creation code for the model:
<span style= "Font-family:microsoft Yahei;" >hresult Createroom (zfxtvertex* V, word* index) {//create a wallzfxvector normal;//triangle 1v[0].x = -100; v[0].y = 1 00; V[0].z = +; V[0].vcn[0] = 0; V[0].VCN[1] = 0; V[0].VCN[2] = 1; v[0].tu = 0.0f; v[0].tv = 0.0f; v[1].x = 100; V[1].Y = 100; V[1].z = +; V[1].vcn[0] = 0; V[1].VCN[1] = 0; V[1].VCN[2] = 1; v[1].tu = 1.0f; v[1].tv = 0.0f; v[2].x = 100; V[2].Y =-100; V[2].z = +; V[2].vcn[0] = 0; V[2].VCN[1] = 0; V[2].VCN[2] = 1; v[2].tu = 1.0f; v[2].tv = 1.0f;//triangle 2v[3].x =-100; V[3].Y = 100; V[3].z = +; V[3].vcn[0] = 0; V[3].VCN[1] = 0; V[3].VCN[2] = 1; v[3].tu = 0.0f; v[3].tv = 0.0f; v[4].x = 100; V[4].Y =-100; V[4].z = +; V[4].vcn[0] = 0; V[4].VCN[1] = 0; V[4].VCN[2] = 1; v[4].tu = 1.0f; v[4].tv = 1.0f; v[5].x =-100; V[5].Y =-100; V[5].z = +; V[5].vcn[0] = 0; V[5].VCN[1] = 0; V[5].VCN[2] = 0; v[5].tu = 0.0f; v[5].tv = 1.0f;//triangle 3v[6].x =-100; V[6].Y =-100; V[6].z = v[6].vcn[0] = 0; V[6].VCN[1] = 1; V[6].VCN[2] = 0; v[6].tu = 0.0f; v[6].tv = 0.0f; v[7].x = 100; V[7].Y =-100; V[7].z = +; V[7].vcn[0] = 0; V[7].VCN[1] = 1; V[7].VCN[2] = 0; v[7].tu = 1.0f; v[7].tv = 0.0f; v[8].x = 100; V[8].Y =-100; V[8].z = -100; v[8].vcn[0] = 0; V[8].VCN[1] = 1; V[8].VCN[2] = 0; v[8].tu = 1.0f; v[8].tv = 1.0f;//triangle 4v[9].x =-100; V[9].Y =-100; V[9].z = +; V[9].vcn[0] = 0; V[9].VCN[1] = 1; V[9].VCN[2] = 0; v[9].tu = 0.0f; v[9].tv = 0.0f; v[10].x = 100; V[10].Y =-100; V[10].z = -100; v[10].vcn[0] = 0; V[10].VCN[1] = 1; V[10].VCN[2] = 0; v[10].tu = 1.0f; v[10].tv = 1.0f; v[11].x =-100; V[11].Y =-100; V[11].z = -100; v[11].vcn[0] = 0; V[11].VCN[1] = 1; V[11].VCN[2] = 0; v[11].tu = 0.0f; v[11].tv = 1.0f;//triangle 5v[12].x =-100; V[12].Y = 100; V[12].z = -100; v[12].vcn[0] = 1; V[12].VCN[1] = 0; V[12].VCN[2] = 0;v[12].tu = 0.0f; v[12].tv = 0.0f; v[13].x =-100; V[13].Y = 100; V[13].z = +; v[13].vcn[0] = 1; V[13].VCN[1]= 0; V[13].VCN[2] = 0; v[13].tu = 1.0f; v[13].tv = 0.0f; v[14].x =-100; V[14].Y =-100; V[14].z = +; v[14].vcn[0] = 1; V[14].VCN[1] = 0; V[14].VCN[2] = 0; v[14].tu = 1.0f; v[14].tv = 1.0f;//triangle 6v[15].x =-100; V[15].Y = 100; V[15].z = -100; v[15].vcn[0] = 1; V[15].VCN[1] = 0; V[15].VCN[2] = 0;v[15].tu = 0.0f; v[15].tv = 0.0f; v[16].x =-100; V[16].Y =-100; V[16].z = +; v[16].vcn[0] = 1; V[16].VCN[1] = 0; V[16].VCN[2] = 0; v[16].tu = 1.0f; v[16].tv = 1.0f; v[17].x =-100; V[17].Y =-100; V[17].z = -100; v[17].vcn[0] = 1; V[17].VCN[1] = 0; V[17].VCN[2] = 0; v[17].tu = 0.0f; v[17].tv = 1.0f;//triangle 7v[18].x = 100; V[18].Y = 100; V[18].z = +; V[18].vcn[0] =-1; V[18].VCN[1] = 0; V[18].VCN[2] = 0; v[18].tu = 0.0f; v[18].tv = 0.0f; v[19].x = 100; V[19].Y = 100; V[19].z = -100; v[19].vcn[0] = 1; V[19].VCN[1] = 0; V[19].VCN[2] = 0;v[19].tu = 1.0f; v[19].tv = 0.0f; v[20].x = 100; V[20].Y =-100; V[20].z = -100; v[20].vcn[0] = 1; V[20].VCN[1] = 0; V[20].VCN[2] = 0; v[20].tu = 1.0f; v[20].tv = 1.0f;//triangle 8v[21].x = 100; V[21].Y = 100; V[21].z = +; V[21].vcn[0] =-1; V[21].VCN[1] = 0; V[21].VCN[2] = 0; v[21].tu = 0.0f; v[21].tv = 0.0f; v[22].x = 100; V[22].Y =-100; V[22].z = -100; v[22].vcn[0] = 1; V[22].VCN[1] = 0; V[22].VCN[2] = 0; v[22].tu = 1.0f; v[22].tv = 1.0f;v[23].x = 100; V[23].Y =-100; V[23].z = +; V[23].vcn[0] =-1; V[23].VCN[1] = 0; V[23].VCN[2] = 0; v[23].tu = 0.0f; v[23].tv = 1.0f;//calculate the Tangent vectorcalctangent (v); for (int i = 0; i <; i + +) index[i] = i; return 0;} End for Createroom</span>
After constructing the 24 vertex data, we calculate the T-vector in tangent space and save the array.
Well, after the calculations are done, we'll render them through the following functions:
<span style= "Font-family:microsoft Yahei;" >void Renderomnipass (UINT BID, uint vsID, uint PsID, uint nLight) {Zfxmatrix mattenu;static float n = 0.0f; Zfxvector pos_1 (100.0f, -100.0f, 0.0f); Zfxvector pos_2 ( -100.0f, 100.0f, 0.0f); Zfxvector pos; if (nLight = = 1) pos = pos_1; elsepos = pos_2; Zfxmatrix mrotate;mrotate.identity (); Mrotate.rotatey (n); n + = 0.01f;pos = pos * mrotate;//set the help vector to C30zfxvec Tor Vhelp (0.5f, 0.5f, 0.5f); if (FAILED (G_pdevice->setshaderconstant (sht_vertex,dt_float, 1, &vhelp))) return;//set the light color to c0zfxcolor Lightcolor = {1.0f, 1.0f, 1.0f, 1.0f};if (FAILED (G_pdevice->setshaderconstan T (sht_pixel,dt_float, 0, 1, &lightcolor)) return, if (FAILED (G_pdevice->activatevshader (VsID, Vid_ut))) return ; if (FAILED (G_pdevice->activatepshader (PsID))) return; Zfxmatrix mw;mw.identity (); G_pdevice->setworldtransform (&MW);//set the light position to C25zfxmatrix InvM; Invm.inverseof (mW);p OS = pos * INVM; if (FAILED (g_pdevice->setsHaderconstant (Sht_vertex, Dt_float, 1, &pos))) return;//set the world_transform to C31zfxmatrix Transm; transM.tr Ansposeof (MW), if (FAILED (G_pdevice->setshaderconstant (Sht_vertex,dt_float, 4, &TRANSM))) return; g_ Pdevice->useadditiveblending (True); if (FAILED (G_pdevice->getvertexcachemanager ()->render (BID)) return; G_pdevice->useadditiveblending (false);} End for Renderomnipass</span>
There is nothing too troublesome in the above function. The only thing to note is that we need to transform the light source into the coordinate space of the model, because we want to light the light in the model's coordinate space. Here is the vertex Shader and pixel Shader for this instance program:
<span style= "Font-family:microsoft Yahei;" >vs.1.1 dcl_position v0dcl_normal v3dcl_texcoord v7dcl_tangent v8m4x4 oPos, V0, C0 ; Transform Positionmov R5, V8mov R7, v3; Calculate Binormal V as; Crossproduct of U and Nmul R0,r5.zxyw,-r7.yzxw;mad R6,r5.yzxw,-r7.zxyw,-r0;; Build vector to_lightsub R2, C25, V0; Transform To_light vectordp3 r8.x, r5.xyz, R2dp3 r8.y, r6.xyz, R2dp3 r8.z, R7.XYZ, R2; Normalize transformed To_light vectordp3 r8.w, R8, R8rsq R8.W, R8.wmul R8, R8, R8.W; *.5 +. 5mad od0.xyz, r8.xyz, c30.x, c30.x mov ot0.xy, V7.xymov ot1.xy, v7.xy</span>
<span style= "Font-family:microsoft Yahei;" >ps.1.1 Tex t0 Tex T1 dp3 R1, t1_bx2, v0_bx2 mul r0, C0, T0mul r0, R1, r0</span>
I use assembly Shader here, if you do not understand the words also have no relationship, with the above on the tangent space calculation, the reader should be able to completely use HLSL for lighting calculation.
The final program is as follows:
All right, today's notes are over!
Zfxengine Development Note Bump Mapping (2)