三种凹凸材质算法总结

来源:互联网 发布:lol美服账号淘宝购买 编辑:程序博客网 时间:2024/06/02 07:27


一、Normal Mapping

图1

                     图1

在Pixel Shader中,光照方程中diffuse分量的计算是通过从像素点到光源的单位向量和该点的单位法向量进行点积得到的。如图1,diffuse=dot(L,N).

如果使用一张法线贴图(3个通道的纹理),纹理中每个像素的三个通道对应X、Y、Z三个空间向量,组成一个法线,对现有的每个像素的法线进行替换,得到表面凹凸的效果。

法线以RGB编码。因为法线各分量的范围为[-1,1],而RGB各分量的范围为[0,1],所以需要对法线进行转换,以便保存在纹理中。转换公式为RGB=(XYZ+1)/2,相应的,XYZ=RGB*2-1。

在切空间中,指向屏幕外的法线为(0,0,1),转换为RGB为(0.5,0.5,1),这是蓝色。法线纹理中的B分量不可能小于0.5,因为当B<0.5,Z<0,而这样的法线是指向表面下的,所以不需要保存在纹理中,这也是为什么法线图的主色都是蓝色的原因。

 

 

二、Parallax Mapping

之前的Normal Mapping是对法线进行扰动,而现在介绍的Parallax Mapping则是对每个像素的纹理坐标进行修改。

                                                 图2

在图2中,从视线向量观察平面时,看到的是A点,而当观察实际表面时,看到的却是B点。通过纹理坐标偏移,可以取得B点的纹理值,得到正确的颜色。

对于每个像素,这个过程需要:一个初始纹理坐标,一个表面高度值和一个从像素点指向观察点的坐标(切空间)。

一个标准的高度图用来表示表面高度的变化,范围是[0,1]。

                                                      图3

在图3中,为了计算在P点得纹理坐标偏移,首先将eye向量单位化得到向量V。T0处的高度h从高度图中读出,为了将h的范围从[0,1]转换到一个更好表示物理高度的范围,要经过变换:hsb=h*scale+bias。然后,通过从A点到eye向量的平行于平面的向量计算偏移。新的纹理坐标Tn=T0+(hsb*V{x,y}/V{z})。这个新的纹理坐标用来对颜色纹理和法线纹理进行取样。

上述的公式有个问题,当从很窄的角度观察时,偏移将会非常大,得到的将会是非常混乱的景象。所以,要限制偏移的上限,使得其不超过hsb,新的公式为Tn=T0+(hsb*V{x,y})。

一般的,会将法线图和高度图放在一张纹理中,RGB通道保存法线信息,A通道保存高度信息。

 

 

三、Relief Mapping

Parallax Mapping是对纹理坐标近似的偏移,而Relief Mapping是对纹理坐标更加精确的偏移。

                                图4

在图4中,对于每一个像素:

1、计算从观察点到像素点的向量VD

2、将VD转换到切空间,编程VD’

3、A点是高度为0的地方,B点是高度为1的地方,A点的纹理坐标是当前像素的纹理坐标,通过他和VD’计算B点得纹理坐标

4、首先进行一定次数的线性查找,到达位于向量上得一个点

4、然后使用二分查找,精确计算VD’和表面相交点

5、通过相交点得纹理坐标去颜色纹理和法线纹理中取样

供参考的hlsl代码:

复制代码
  1 float4x4 worldviewproj_matrix;
2 float4x4 worldview_matrix;
3
4
5 float3 ambient;
6 float3 diffuse;
7 float3 specular;
8 float shine;
9 float3 lightpos;
10 float depth;
11
12 sampler2D colormap;
13 sampler2D bumpmap;
14
15
16 struct VS_INPUT
17 {
18 float4 Pos:POSITION;
19 float2 Tex:TEXCOORD0;
20 float3 Normal:NORMAL0;
21 float3 Tangent:TEXCOORD1;
22 float3 Binormal:TEXCOORD2;
23 };
24
25 struct VS_OUTPUT
26 {
27 float4 Pos:POSITION;
28 float2 Tex:TEXCOORD0;
29 float3 viewVecTS:TEXCOORD1;
30 float3 lightVecTS:TEXCOORD2;
31 };
32
33 VS_OUTPUT vs_main(VS_INPUT In)
34 {
35 VS_OUTPUT Out;
36 float4 pos=float4(In.Pos.x,In.Pos.y,In.Pos.z,1.0f);
37 Out.Pos=mul(pos,worldviewproj_matrix);
38 float3 vpos=mul(pos,worldview_matrix).xyz;
39 float3 vlight=mul(lightpos,(float3x3)worldview_matrix);
40 Out.Tex=In.Tex;
41 float3x3 worldviewrot;
42 worldviewrot[0]=worldview_matrix[0].xyz;
43 worldviewrot[1]=worldview_matrix[1].xyz;
44 worldviewrot[2]=worldview_matrix[2].xyz;
45 float3 tangent=mul(In.Tangent,worldviewrot);
46 float3 binormal=mul(In.Binormal,worldviewrot);
47 float3 normal=mul(In.Normal,worldviewrot);
48
49 float3x3 tangentspace=float3x3(tangent,binormal,normal);
50 Out.viewVecTS=mul(-vpos,tangentspace);
51 Out.lightVecTS=mul(vlight-vpos,tangentspace);
52 return Out;
53 }
54
55 void setup_ray(VS_OUTPUT In,out float3 p,out float3 v)
56 {
57 p=float3(In.Tex,0);
58 v=normalize(-In.viewVecTS);
59 v.z=abs(v.z);
60 v.xy*=depth;
61 }
62
63 float4 normal_mapping(sampler2D color_map,sampler2D normal_map,float2 tex,VS_OUTPUT In)
64 {
65 float4 color=tex2D(color_map,tex);
66 float4 normal=tex2D(normal_map,tex);
67 normal.xy=2*normal.xy-1;
68 normal.y=-normal.y;
69 normal.z=sqrt(1.0-dot(normal.xy,normal.xy));
70 float3 l=normalize(In.lightVecTS);
71 float3 v=normalize(In.viewVecTS);
72 float diff=saturate(dot(l,normal.xyz));
73 float spec=saturate(dot(normalize(l+v),normal.xyz));
74 float att=1.0-max(0,l.z);
75 att=1.0-att*att;
76
77
78 float4 finalcolor;
79 finalcolor.xyz=ambient*color.xyz+att*(color.xyz*diffuse*diff+specular*pow(spec,shine));
80 finalcolor.w=1.0;
81
82 return finalcolor;
83 }
84
85
86 void ray_intersect_relief(sampler2D relief_map,inout float3 p,inout float3 v)
87 {
88 const int num_steps_lin=15;
89 const int num_steps_bin=6;
90
91 v/=v.z*num_steps_lin;
92 int i;
93 for(i=0;i<num_steps_lin;++i)
94 {
95 float4 tex=tex2D(bumpmap,p.xy);
96 if(p.z<tex.w)
97 p+=v;
98 }
99 for(i=0;i<num_steps_bin;++i)
100 {
101 v*=0.5;
102 float4 tex=tex2D(bumpmap,p.xy);
103 if(p.z<tex.w)
104 p+=v;
105 else
106 p-=v;
107 }
108 }
109
110 float4 ps_main(VS_OUTPUT In):COLOR
111 {
112 float3 p,v;
113 setup_ray(In,p,v);
114 ray_intersect_relief(bumpmap,p.xyz,v);
115 return normal_mapping(colormap,bumpmap,p.xy,In);
116 }
复制代码

 

 

 Reference:

Parallax Mapping with Offset Limiting:A Per-Pixel Approximation of Uneven Surfaces

Real-Time Relief Mapping on Arbitrary Polygonal Surfaces

0 0
原创粉丝点击