永发信息网

如何从height map生成normal map

答案:2  悬赏:60  手机版
解决时间 2021-01-24 06:43
如何从height map生成normal map
最佳答案
其实并不难,在《3D游戏与计算机图形学方法》中,提供了一种由高度图生成法向图的方法。其思想是根据高度图中的象素与其周围象素的高度差,在切空间构造S向量和T向量,由SXT得到法线向量。
设H(i,j)表示在height map上(i,j)象素点的高度值,则在切线空间S和T方向的切向量可以表示成:
S(i,j) = (1,0,H(i+1,j) - H(i-1,j) )
T(i,j) = (0,1,H(i,j+1) - H(i,j-1) )
Normal(i,j) = S(i,j) X T(i,j)
H(i+1,j) – H(i-1,j)为沿S方向的高度差,也就是S方向的坡度,H(i,j+1) - H(i,j-1)为沿T方向的高度差,也就是T方向的坡度。当相邻象素高度差为0时,则算出的Normal(i,j) = (0,0,1),表示法线垂直于平面,当有高度差时,法线就会分别朝S方向或T方向偏移。

用shader来实现也很简单,VS和PS代码如下,上边左图为HeightMap,右图为由下面shader生成的NormalMap,这个方法生成的NormalMap并不够好,在RenderMonkey中有一个叫NormalmapFilter的Sample,会生成更高质理的NormalMap,有兴趣的朋友可以参考。
VS_OUTPUT main(float4 Pos: POSITION){
VS_OUTPUT Out;
// Clean up inaccuracies
Pos.xy = sign(Pos.xy);
Out.Pos = float4(Pos.xy, 0, 1);
// Image-space
Out.texCoord.x = 0.5 * (1 + Pos.x);
Out.texCoord.y = 0.5 * (1 - Pos.y);
return Out;
}

float4 main(float2 texCoord: TEXCOORD) : COLOR {
float2 off = 1.0 / HeightMapSize;
float Scale = 1;
// Sample teh neighbor
float s0 = tex2D(Heightmap, texCoord + float2(-off.x,0)).r;
float s1 = tex2D(Heightmap, texCoord + float2( off.x,0)).r;
float s2 = tex2D(Heightmap, texCoord + float2( 0,-off.y)).r;
float s3 = tex2D(Heightmap, texCoord + float2(0,off.y)).r;
float3 U = float3(1,0,s1 - s0);
float3 V = float3(0,1,s3 - s2);
float3 normal = normalize(Scale * cross(U,V));
// Pack [-1, 1] into [0, 1]
return float4(normal * 0.5 + 0.5,1);
}
全部回答
那么heightmap是怎么转化成normalmap的呢? 其实并不难,在《3d游戏与计算机图形学方法》中,提供了一种由高度图生成法向图的方法。其思想是根据高度图中的象素与其周围象素的高度差,在切空间构造s向量和t向量,由sxt得到法线向量。设h(i,j)表示在height map上(i,j)象素点的高度值,则在切线空间s和t方向的切向量可以表示成:s(i,j) = (1,0,h(i+1,j) - h(i-1,j) ) t(i,j) = (0,1,h(i,j+1) - h(i,j-1) ) normal(i,j) = s(i,j) x t(i,j) h(i+1,j) – h(i-1,j)为沿s方向的高度差,也就是s方向的坡度,h(i,j+1) - h(i,j-1)为沿t方向的高度差,也就是t方向的坡度。vs_output main(float4 pos: position){ vs_output out; // clean up inaccuracies pos.xy = sign(pos.xy); out.pos = float4(pos.xy, 0, 1); // image-space out.texcoord.x = 0.5 * (1 + pos.x); out.texcoord.y = 0.5 * (1 - pos.y); return out;} float4 main(float2 texcoord: texcoord) : color { float2 off = 1.0 / heightmapsize; float scale = 1; // sample teh neighbor float s0 = tex2d(heightmap, texcoord + float2(-off.x,0)).r; float s1 = tex2d(heightmap, texcoord + float2( off.x,0)).r; float s2 = tex2d(heightmap, texcoord + float2( 0,-off.y)).r; float s3 = tex2d(heightmap, texcoord + float2(0,off.y)).r; float3 u = float3(1,0,s1 - s0); float3 v = float3(0,1,s3 - s2); float3 normal = normalize(scale * cross(u,v)); // pack [-1, 1] into [0, 1] return float4(normal * 0.5 + 0.5,1);}
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
永辉鑫时代快运怎么去啊,我要去那办事
育婴(宝母婴店)地址在什么地方,我要处理点事
沈阳179公交最晚到几点
如图,分别以Rt△ABC的斜边AB,直角边AC为边
中铁快运(肥城总部)地址在什么地方,想过去办
华婴母婴用品店地址有知道的么?有点事想过去
请问:平面图形①②③④⑤分别可由平面截几何
马埠综合快运肥城代发收点怎么去啊,我要去那
一How dangerous it was!—Yes,but for the
嘟嘟baby地址在什么地方,我要处理点事
东方瑞鑫交通物流地址在什么地方,想过去办事
张一白在一生一世里唱的什么歌
下列离子方程式正确的是A.碳酸钙与稀HNO3:CO
宝宝身上长痱子了,怎么办才好?
8厘习1万一天多少钱
推荐资讯
浪漫满屋地址有知道的么?有点事想过去
命令方块怎么获得 命令方块获取指令及用法介
夷陵区宜昌胜达电器这个地址在什么地方,我要
单选题2006年10月27日,中国工商银行A+H股在
关于物理匀强电场与匀强磁场的题
在-5,0.6,3.8,0,-0.5,5六个数中正数有__
愿你余生的爱情如你爱我一样少?什么意思?
PICVideo4注册码
【氯化钾溶解度】氯化钾溶解度
新宏晟贸易有限公司(金宝国际汽车城内)地址有
蜀相诗中的三顾频烦天下计,描述的是三国演义
我有一部五菱荣光标准型的车,双空调,电动门
正方形一边上任一点到这个正方形两条对角线的
阴历怎么看 ?