3D游戏引擎系列(八):环境映射

发表于2017-04-03
评论0 3.3k浏览

        环境映射在材质的渲染上同样应用广泛,现实生活中我们也经常遇到环境映射,比如一个光滑的铁球上可以映射出周围环境。环境映射的实现方式就是把周围的环境通过反射,折射映射到3D物体表面的材质上,给人非常炫酷的感觉。环境映射实现方式有两种:一种是通过美工做一张环境映射贴图实现环境映射;第二种方式是美工做六张贴图实现环境映射。Unity实现环境映射的方式是采用的后者,本节实现的是第一种方式,第二种方式可以借鉴Unity的立方体纹理,Unity实现环境映射效果如下图:


        通过六张贴图就可以把环境映射的效果展现出来,这种方式同样适用于天空盒的实现。本节是通过一张贴图实现环境映射效果,接下来还是新建一个文本文件,将其扩展名改成.fx。完整代码如下所示:

  1. float4x4 matWorldViewPrj;  
  2. float4x4 matWorld;  
  3. float4x4 matView;  
  4. float3 eyePos;  
  5.   
  6. texture cubeMapTexture;  
  7. texture sphereMapTexture;  
  8.   
  9. //--  
  10. struct VS_INPUT  
  11. {  
  12.     float3 pos      : POSITION;  
  13.     float3 normal : NORMAL;  
  14. };  
  15.   
  16. struct VS_OUTPUT  
  17. {  
  18.     float4 pos : POSITION;  
  19.     float3 cubeTex  : TEXCOORD0;  
  20. };  
  21.   
  22. VS_OUTPUT my_vs(VS_INPUT vert)  
  23. {  
  24.     VS_OUTPUT vsout;  
  25.     vsout.pos = mul(float4(vert.pos,1),matWorldViewPrj);  
  26.       
  27.     float3 worldPos = mul(float4(vert.pos,1),matWorld);  
  28.     float3 worldNormal = normalize(mul(vert.normal,matWorld));  
  29.           
  30.     float3 viewDir = normalize(worldPos - eyePos);  
  31.       
  32.     vsout.cubeTex = reflect(viewDir, worldNormal);  
  33.       
  34.     return vsout;  
  35. }  
  36.   
  37. //--  
  38. samplerCUBE cubeMap = sampler_state  
  39. {  
  40.     Texture = ;  
  41.     MipFilter = LINEAR;  
  42.     MinFilter = LINEAR;  
  43.     MagFilter = LINEAR;  
  44. };  
  45.   
  46. float4 my_ps(float3 cubeTex : TEXCOORD0) : COLOR  
  47. {  
  48.     return texCUBE(cubeMap,cubeTex);  
  49. }  
  50.   
  51. //--  
  52. technique myCubeEnvMap  
  53. {  
  54.     pass p0  
  55.     {  
  56.         VertexShader = compile vs_1_1 my_vs();  
  57.         PixelShader = compile ps_2_0 my_ps();  
  58.     }  
  59. }  
  60.   
  61. //--  
  62. struct VS_OUTPUT_Sphere  
  63. {  
  64.     float4 pos : POSITION;  
  65.     float2 sphereTex    : TEXCOORD0;  
  66. };  
  67.   
  68. VS_OUTPUT_Sphere my_sphere_vs(VS_INPUT vert)  
  69. {  
  70.     VS_OUTPUT_Sphere vsout;  
  71.       
  72.     vsout.pos = mul(float4(vert.pos,1),matWorldViewPrj);  
  73.       
  74.     float3 viewNormal = mul(vert.normal,matWorld);  
  75.     viewNormal = mul(viewNormal,matView);  
  76.     viewNormal = normalize(viewNormal);  
  77.           
  78.     vsout.sphereTex = float2(viewNormal.x/2+0.5,viewNormal.y/2+0.5);  
  79.       
  80.     return vsout;  
  81. }  
  82.   
  83. sampler sphereMap = sampler_state  
  84. {  
  85.     Texture = ;  
  86.     MipFilter = LINEAR;  
  87.     MinFilter = LINEAR;  
  88.     MagFilter = LINEAR;  
  89. };  
  90.   
  91. float4 my_sphere_ps(float2 sphereTex    : TEXCOORD0  
  92.             ) : COLOR  
  93. {  
  94.     return tex2D(sphereMap,sphereTex);  
  95. }  
  96.   
  97. technique mySphereEnvMap  
  98. {  
  99.     pass p0  
  100.     {  
  101.         VertexShader = compile vs_1_1 my_sphere_vs();  
  102.         PixelShader = compile ps_2_0 my_sphere_ps();  
  103.     }  
  104. }  

相比上一个CelShading卡通渲染Shader,在函数:

VS_OUTPUT my_vs(VS_INPUT vert)

增加了反射函数reflect语句如下:

  1. float3 viewDir = normalize(worldPos - eyePos);vsout.cubeTex = reflect(viewDir, worldNormal)  

        计算中的反射和折射不需要程序手工计算,直接调用Shader的库函数就可以实现,但是原理还是要搞清楚。在该Shader中实现了两种效果:分别是立方体和球体,Shader实现方面也分了两个Technique,每个Technique有一个pass通道分别是关于立方体映射和球体映射。这里面涉及到两张贴图的渲染,一个是环境平面材质的渲染,另一个是球体的环境材质渲染。C++要实现此效果,需要两张贴图,第一张贴图是环境贴图,第二张是球贴图如下所示:




         立方体环境映射渲染效果如图:


        其在引擎内部的调用与前面CelShading的编写代码类似,这里就不介绍了。C++主要是调用不同的Technique以达到不同的渲染处理方式,代码语句如下:

  1. m_pEffect->SetTechnique("myCubeEnvMap");  

        这条语句是默认的通道,可以通过if else条件语句去切换立方体和球体映射,换句话说就是调用不同的Technique技术,因为GPU一次只能执行一个Technique。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引