###### Normal Map的一些细节问题
Normal Map的一些细节问题

1.Noraml Map的用处

（经典例子是桔子皮或者砖墙）

2.Normal Map的生成
(1)对于Bump Map，通常是由Height Map生成的。公式的前提是：square patch assumption,“this assumption is acceptable for many important surfaces such as flat polygons, spheres, tori, and surfaces of revolution.”因此基本上够用了。
N’= N + D =[0,0,c]+ D =[a,b,c]
a = -dF/du * 1/k
b = -dF/dv  * 1/k
c = 1

-1 0 1        1  2  1

dx = -2 0 2  dy =  0  0  0

-1 0 1       -1 -2 -1

注意结果要单位化，并且由于法线的范围是[-1, 1]，所以还要转换到颜色的范围[0, 1] (又即0~255)

for(y = 0; y < gHeight; y++)
{
for(x = 0; x < gWidth; x++)
{
// Do Y Sobel filter
ReadPixel(srcImage, &pix, (x-1+gWidth) % gWidth, (y+1) % gHeight);
dY = ((float) pix.red) / 255.0f * -1.0f;

ReadPixel(srcImage, &pix,   x   % gWidth, (y+1) % gHeight);
dY += ((float) pix.red) / 255.0f * -2.0f;

ReadPixel(srcImage, &pix, (x+1) % gWidth, (y+1) % gHeight);
dY += ((float) pix.red) / 255.0f * -1.0f;

ReadPixel(srcImage, &pix, (x-1+gWidth) % gWidth, (y-1+gHeight) % gHeight);
dY += ((float) pix.red) / 255.0f * 1.0f;

ReadPixel(srcImage, &pix,   x   % gWidth, (y-1+gHeight) % gHeight);
dY += ((float) pix.red) / 255.0f * 2.0f;

ReadPixel(srcImage, &pix, (x+1) % gWidth, (y-1+gHeight) % gHeight);
dY += ((float) pix.red) / 255.0f * 1.0f;

// Do X Sobel filter
ReadPixel(srcImage, &pix, (x-1+gWidth) % gWidth, (y-1+gHeight) % gHeight);
dX = ((float) pix.red) / 255.0f * -1.0f;

ReadPixel(srcImage, &pix, (x-1+gWidth) % gWidth,   y   % gHeight);
dX += ((float) pix.red) / 255.0f * -2.0f;

ReadPixel(srcImage, &pix, (x-1+gWidth) % gWidth, (y+1) % gHeight);
dX += ((float) pix.red) / 255.0f * -1.0f;

ReadPixel(srcImage, &pix, (x+1) % gWidth, (y-1+gHeight) % gHeight);
dX += ((float) pix.red) / 255.0f * 1.0f;
ReadPixel(srcImage, &pix, (x+1) % gWidth,   y   % gHeight);
dX += ((float) pix.red) / 255.0f * 2.0f;

ReadPixel(srcImage, &pix, (x+1) % gWidth, (y+1) % gHeight);
dX += ((float) pix.red) / 255.0f * 1.0f;

// Cross Product of components of gradient reduces to
nX = -dX;
nY = -dY;
nZ = 1;
// Normalize
oolen = 1.0f/((float) sqrt(nX*nX + nY*nY + nZ*nZ));
nX *= oolen;
nY *= oolen;
nZ *= oolen;
pix.red   = (BYTE) PackFloatInByte(nX);
pix.green = (BYTE) PackFloatInByte(nY);
pix.blue = (BYTE) PackFloatInByte(nZ);

WritePixel(dstImage, &pix, x, y);
}
}

BYTE PackFloatInByte(float in)
{
return (BYTE) ((in+1.0f) / 2.0f * 255.0f);
}

(2)对于High Poly Detail for Low Poly，则相对要复杂一些。(例如Z-Brush)

An even cooler use for a normal map is to make a low res model look almost exactly like a high res model. This type of normal map is generated by the computer instead of painted like a bump map. Here is how it works: First you create two versions of the model: a high polygon version (which can contain as much detail as you want) and a low polygon version that will actually get used in the game. Then you align the two models so that they occupy the same space and overlap each other.
Next you run a special program for generating the normal map. The program puts an empty texture map on the surface of the low res model. For each pixel of this empty texture map, the program casts a ray (draws a line) along surface normal of the low res model toward the high res model. At the point where that ray intersects with the surface of the high res model, the program finds the high res model normal. The idea is to figure out which direction the high res model surface is facing at that point and put that direction information (normal) in the texture map.
Once the program finds the normal from the high res model for the point, it encodes that normal into an RGB color and puts that color into the current pixel in the afore mentioned texture map. It repeats this process for all of the pixels in the texture map. When its done, you end up with a texture map that contains all of the normals calculated from the high res model. Its ready to be applied to the low res model as a normal map. I抣l show you how to create this type of normal map in the second half of the tutorial.

3. TBN的计算

T = normalize(dx/du, dy/du, dz/du)
N = T × normalize(dx/dv, dy/dv, dz/dv)
B = N × T
(Tangent space is just such a local coordinate system. The orthonormal basis for the tangent space is the normalized unperturbed surface normal Nn, the tangent vector Tn defined by normalizing dP/du, and the binormal Bn defined as Nn×Tn. The orthonormal basis for a coordinate system is also sometimes
called the reference frame.)

(D3DX提供了两个帮助函数：D3DXComputeTangentFrame, D3DXComputeTangentFrameEx)

v2v1 =   △c2c1T T + △c2c1B B
v3v1 =   △c3c1T T + △c3c1B B

(注意：上图是右手系，其中STangentTBinormal)

fPartialEdgeThreshold
[in] Specifies the maximum cosine of the angle at which two partial derivatives are deemed to be incompatible with each other. If the dot product of the direction of the two partial derivatives in adjacent triangles is less than or equal to this threshold, then the vertices shared between these triangles will be split.

同时还处理了“奇异点”：
fSingularPointThreshold
[in] Specifies the maximum magnitude of a partial derivative at which a vertex will be deemed singular. As multiple triangles are incident on a point that have nearby tangent frames, but altogether cancel each other out (such as at the top of a sphere), the magnitude of the partial derivative will decrease. If the magnitude is less than or equal to this threshold, then the vertex will be split for every triangle that contains it.

fNormalEdgeThreshold
[in] Similar to fPartialEdgeThreshold, specifies the maximum cosine of the angle between two normals that is a threshold beyond which vertices shared between triangles will be split. If the dot product of the two normals is less than the threshold, the shared vertices will be split, forming a hard edge between neighboring triangles. If the dot product is more than the threshold, neighboring triangles will have their normals interpolated.

TBN的使用：

Tx   Bx   Nx

Lts = Los ×  Ty   By   Ny

Tz    Bz   Nz

Sself = min( 8*max(Lz,0), 1)。
I = Ia + Sself * ( Kd*max(0, L·N’) + Ks*max(0, N’·H)shininess )

5. 使用normalization cub map

6. 纹理过滤对法线的影响及diffuse与specular计算时的一些区别

Note that N’filtered is not generally normalized. Renormalizing N’filtered might seem reasonable and has been suggested in the literature [21], but not renormalizing when computing surface’s perceived diffuse intensity is actually more correct.
Note that if N’filtered is renormalized then bumpy diffuse surfaces incorrectly appear too bright. This result suggests that linear averaging of normalized perturbed normals is a reasonable filtering approach for the purpose of diffuse illumination. It also suggests that if bump maps are represented as perturbed normal maps then such normal maps can be reasonably filtered with conventional linear-mipmap-linear texturing hardware when used for diffuse lighting.

The single good thing about this approach is that there is an opportunity for sharing the same bump map encoding between the diffuse and specular illumination computations. The diffuse computation assumes an averaged perturbed normal that is not normalized while the specular computation requires the same normal normalized. Both needs are met by storing the normalized perturbed normal and a descaling factor. The specular computation uses the normalized normal directly while the diffuse computation uses the normalized normal but then fixes the diffuse illumination by multiplying by the descaling factor to get back to the unnormalized vector needed for computing the proper diffuse illumination.
A scaling factor for the normal. Mipmap level 0 has a constant magnitude of 1.0, but down-sampled mipmap levels keep track of  the unnormalized vector sum length. For diffuse per-pixel lighting, it is preferable to make N be the _unnormalized_ vector, but for specular lighting to work reasonably, the normal vector should be normalized. In the diffuse case, we can multiply by the "mag" to get the possibly shortened unnormalized length.

7. mipmap的使用

8. 什么情况下更新TBN？
显然只有当object空间中顶点的位置发生变化时才更新(旋转，非均匀缩放Uniform scaling)，通常为Mesh的动画。
但完全重新计算的代价太大，因此TBN的计算通常都和动画配合：
(1)如果是骨骼动画(Bone-Based Skinning)，则直接用顶点变换矩阵Matrix作用于T和B，只算出T和B即可，然后
T X B = N

(2)如果是基于Mesh的关键帧插值(Keyframe Interpolation)，同样对T和B进行插值。

[1] Mark J. Kilgard, A Practical and Robust Bump-mapping Technique for Todays GPUs, NVIDIA Corporation, July 2000

[2] Chris Wynn, Implementing Bump-Mapping using Register Combinerss, NVIDIA Corporation, August 2001

[3] Sim Dietrich, Texture Space Bump Mapping, NVIDIA Corporation, November 2000

[4] Jakob Gath, Derivation of the Tangent Space Matrix,

[5] BEN CLOWARD, Normal Mapping Tutorial,

#### 如何由Height Map生成Normal Map

2015-10-12 15:26:40

#### Height Map高度图

2015-10-12 14:00:58

2014-12-09 14:55:49

#### 凹凸贴图---------------- Bump Map vs Normal Map vs Parallax Map

2014-12-18 17:04:16

2017-03-15 01:19:40

#### Normal Mapping

2017-12-11 01:08:33

#### Normal Map

2015-10-27 17:31:22

#### 对于法线贴图（Normal Map） 的深入研究

2011-12-14 23:14:13

#### 凹凸贴图(Bump Map)实现原理以及与法线贴图(Normal Map)的区别

2013-02-23 14:40:02

#### NormalMapFilter

2011年08月28日 682KB 下载

## 不良信息举报

Normal Map的一些细节问题