Parallax Mapping

1649 篇文章 12 订阅
1623 篇文章 23 订阅
Parallax Mapping

Bump Map通过对一个平面上的像素点上增加法向量信息,因此通过像素级的光照后,平面上就具有凹凸的表现,但他仍然是一个平面,呈现不出几何上的高低。而Parallax Map可以一定程度的弥补这种情况,同样Parallax Map仍然是一个平面。

如下图所示:

如果一个Plane上添加了高度信息(这个信息可以放在Normal Map的Alpha中),在Bump Map中,看到的将是V0点,而实际上应该看到的是V1点

最初的Parallax Map方法
如图所示(该图只表示了在u方向)

因为通过u点并不知道到实际的点有多远的off,所以就根据在u点的height和eye的角度,根据off = h*tan(a)来计算得到u',然后以新的uv值从新采样得到normal和detail。这只是一个近似。
存在的问题:
1:表现出的视差效果并不是很好,而且会出现浮动(Swimming Effect)
2:当Eye与Plane的角度很低的时候,off会出现的很大,这会出现很严重的错误

解决方法:
1:对于Swimming Effect,在Irrlicth中使用的方法是,对Height上面再乘上一个Normal.z。

From Irrlicth CD3D8ParallaxMapRenderer.cpp

点击(此处)折叠或打开

  1. ; original parallax mapping: \n"\
  2. ";mul r3, r1_bx2.wwww, c6; ; r3 = (height, height, height) * scale \n"\
  3. ";mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\
  4. " \n"\
  5. "; modified parallax mapping to reduce swimming effect: \n"\
  6. "mul r3, r1_bx2.wwww, r1_bx2.zzzz ; (nh,nh,nh,nh) = (h,h,h,h) * (n.z,n.z,n.z,n.z,) \n"\
  7. "mul r3, r3, c6; ; r3 = (nh, nh, nh) * scale \n"\
  8. "mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\
实际上他的off = h*h_scale*n.z

2:对于角度很低时候的问题,可以像Irrlicht中一样,根本就不乘上tan(a),因此就避开了角度的问题;另外一种方法是给定一个角度的极限,当角度超过了允许的极限,则使用极限值来替代这个角度。也就是说tan(a)存在一个最大值。


改进的Parallax Map

改进的方法是通过一定的Trace,找到实际的交点
如图所示
这个方法,首先根据u点,以最大的高度(就是1*height_scale)按照Eye的角度得到一个初始值u_s,然后以u_step为步调从u_s点开始依次往前找,每次将对应点的实际h值和当前的Eye视线的h值做比较,如果h_e>h_u,则h_e递减,u递增,直到找到h_e<=h_u的点或者到达u点。使用这种方法明显要比前面的方法要精确。并且该方法支持了Occlusion。

存在的问题:
1:迭代的消耗更大;当然,如果迭代越多,精度越大,但性能消耗越严重,反之则反之。
2:同样存在角度很小的时候,得到的u_s偏离u很大,而出现错误,这可以规定一个极限角度来解决。

Shader Code :
Vertex Shader

点击(此处)折叠或打开

  1. // Vertex Shader
  2. vs_3_0
  3. ; Input
  4. dcl_position v0
  5. dcl_tangent0 v1
  6. dcl_binormal0 v2
  7. dcl_normal v3
  8. dcl_texcoord0 v4.xy
  9. ; Output
  10. dcl_position o0
  11. dcl_color0 o1 ; light vector
  12. dcl_color1 o2 ; eye vector
  13. dcl_texcoord0 o3.xy ; tex uv
  14. ; c0~c3 Geometry matrix
  15. ; c4 Eye position in object space
  16. ; c5 Lit position in object space
  17. m4x4 o0, v0, c0
  18. ; Calculate the light vector
  19. sub r0, c5, v0
  20. m3x3 r1.xyz, r0, v1
  21. nrm r2, r1
  22. mov o1, r2
  23. ; Calculate the eye vector
  24. sub r0, c4, v0
  25. m3x3 r1.xyz, r0, v1
  26. nrm r2, r1
  27. mov o2, r2
  28. mov o3.xy, v4.xy
Original Pixel Shader with assembly shader

点击(此处)折叠或打开

  1. // Original with Assembly Shader
  2. ps_3_0
  3. ; Input
  4. dcl_color0 v0 ; Light vector
  5. dcl_color1 v1 ; Eye vector
  6. dcl_texcoord0 v2.xy
  7. dcl_2d s0 ; detail
  8. dcl_2d s1 ; normal
  9. ; Constant
  10. def c0, 2.0, 1.0, 0.03, 0.0
  11. def c1, 2.0, 0.0, 0.0, 0.0
  12. ; Texld the normal map, and the height is in the alpha channel
  13. texld r0, v2.xy, s1
  14. mad r0.xyz, r0.xyz, c0.x, -c0.y ; *2-1, transform to (-1, 1)
  15. ; Parallax mapping
  16. nrm r2, v1
  17. rcp r3.x, r2.z ; 1/Eye.z
  18. min r3.x, r3.x, c1.x ; Eye angle limitation
  19. mul r3.x, r3.x, r0.w ; h*scale/eye.z
  20. mul r3.x, r3.x, c0.z
  21. mad r3.xy, r2.xy, r3.x, v2.xy ; Get the true uv
  22. ; Texld the normal map
  23. texld r0, r3.xy, s1
  24. mad r0.xyz, r0.xyz, c0.x, -c0.y ; *2-1, transform to (-1, 1)
  25. nrm r1, r0
  26. ; Diffuse
  27. nrm r2, v0
  28. dp3_sat r0.w, r1, r2
  29. ; Load the detail texture
  30. texld r0.xyz, r3.xy, s0
  31. ; diffuse*detail
  32. mul oC0, r0.xyz, r0.w
Improved Pixel Shader with HLSL

点击(此处)折叠或打开

  1. //
  2. // Improved with HLSL shader
  3. sampler NrmSampler : register(ps, s1);
  4. sampler DtlSampler : register(ps, s0);
  5. struct PS_INPUT
  6. {
  7. float3 litVec : COLOR0;
  8. float3 eyeVec : COLOR1;
  9. float2 tex0 : TEXCOORD0;
  10. };
  11. static const float scale = 0.04; // Height map scaling
  12. static const float n = 10; // Trace count
  13. static const float fHStep = 1.0/n;
  14. static const float fMaxUVStep = 2.0*scale; // Camera angle limitation
  15. float4 main(PS_INPUT input) : COLOR0
  16. {
  17. // Get the normal and height
  18. float3 eyeVec = normalize(input.eyeVec);
  19. float2 uvStep = eyeVec.xy*min(scale/eyeVec.z, fMaxUVStep); // Init as the most offet
  20. float4 uv = {input.tex0+uvStep, 0.0, 0.0}; // The start uv
  21. float4 nrm = tex2D(NrmSampler, uv.xy);
  22. float curHDiff = 0.0;
  23. float preHDiff = 1.0;
  24. if(nrm.a < 1.0) // if nrm.a == 1.0, it's the highest point
  25. {
  26. float curH = 1.0;
  27. float preH = 1.0-nrm.a;
  28. uvStep *= fHStep;
  29. [loop] for(int i=0; i<n; ++i)<="" li="" style="word-wrap: break-word;">
  30. {
  31. if(nrm.a >= curH)
  32. {
  33. curHDiff = nrm.a-curH;
  34. break;
  35. }
  36. preHDiff = curH-nrm.a;
  37. curH -= fHStep;
  38. uv.xy -= uvStep;
  39. nrm = tex2Dlod(NrmSampler, uv);
  40. }
  41. }
  42. uv.xy += curHDiff/(preHDiff+curHDiff)*uvStep; // Interpolate
  43. nrm = tex2D(NrmSampler, uv.xy);
  44. // Do the parallax mapping
  45. nrm.xyz = normalize(float3(nrm.xyz*2-1));
  46. float3 litVec = normalize(input.litVec);
  47. float4 output = saturate(dot(litVec.xyz, nrm.xyz))*tex2D(DtlSampler, uv.xy);
  48. return output;
  49. };

Samples :
Bump Mapping

Original Parallax Mapping

Improved Parallax Mapping

Reference 
Kaneko, T., et al. " Detailed Shape Representation with Parallax Mapping"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值