环境映射在材质的渲染上同样应用广泛,现实生活中我们也经常遇到环境映射,比如一个光滑的铁球上可以映射出周围环境。环境映射的实现方式就是把周围的环境通过反射,折射映射到3D物体表面的材质上,给人非常炫酷的感觉。环境映射实现方式有两种:一种是通过美工做一张环境映射贴图实现环境映射;第二种方式是美工做六张贴图实现环境映射。Unity实现环境映射的方式是采用的后者,本节实现的是第一种方式,第二种方式可以借鉴Unity的立方体纹理,Unity实现环境映射效果如下图:
通过六张贴图就可以把环境映射的效果展现出来,这种方式同样适用于天空盒的实现。本节是通过一张贴图实现环境映射效果,接下来还是新建一个文本文件,将其扩展名改成.fx。完整代码如下所示:
- float4x4 matWorldViewPrj;
- float4x4 matWorld;
- float4x4 matView;
- float3 eyePos;
-
- texture cubeMapTexture;
- texture sphereMapTexture;
-
-
- struct VS_INPUT
- {
- float3 pos : POSITION;
- float3 normal : NORMAL;
- };
-
- struct VS_OUTPUT
- {
- float4 pos : POSITION;
- float3 cubeTex : TEXCOORD0;
- };
-
- VS_OUTPUT my_vs(VS_INPUT vert)
- {
- VS_OUTPUT vsout;
- vsout.pos = mul(float4(vert.pos,1),matWorldViewPrj);
-
- float3 worldPos = mul(float4(vert.pos,1),matWorld);
- float3 worldNormal = normalize(mul(vert.normal,matWorld));
-
- float3 viewDir = normalize(worldPos - eyePos);
-
- vsout.cubeTex = reflect(viewDir, worldNormal);
-
- return vsout;
- }
-
-
- samplerCUBE cubeMap = sampler_state
- {
- Texture = ;
- MipFilter = LINEAR;
- MinFilter = LINEAR;
- MagFilter = LINEAR;
- };
-
- float4 my_ps(float3 cubeTex : TEXCOORD0) : COLOR
- {
- return texCUBE(cubeMap,cubeTex);
- }
-
-
- technique myCubeEnvMap
- {
- pass p0
- {
- VertexShader = compile vs_1_1 my_vs();
- PixelShader = compile ps_2_0 my_ps();
- }
- }
-
-
- struct VS_OUTPUT_Sphere
- {
- float4 pos : POSITION;
- float2 sphereTex : TEXCOORD0;
- };
-
- VS_OUTPUT_Sphere my_sphere_vs(VS_INPUT vert)
- {
- VS_OUTPUT_Sphere vsout;
-
- vsout.pos = mul(float4(vert.pos,1),matWorldViewPrj);
-
- float3 viewNormal = mul(vert.normal,matWorld);
- viewNormal = mul(viewNormal,matView);
- viewNormal = normalize(viewNormal);
-
- vsout.sphereTex = float2(viewNormal.x/2+0.5,viewNormal.y/2+0.5);
-
- return vsout;
- }
-
- sampler sphereMap = sampler_state
- {
- Texture = ;
- MipFilter = LINEAR;
- MinFilter = LINEAR;
- MagFilter = LINEAR;
- };
-
- float4 my_sphere_ps(float2 sphereTex : TEXCOORD0
- ) : COLOR
- {
- return tex2D(sphereMap,sphereTex);
- }
-
- technique mySphereEnvMap
- {
- pass p0
- {
- VertexShader = compile vs_1_1 my_sphere_vs();
- PixelShader = compile ps_2_0 my_sphere_ps();
- }
- }
相比上一个CelShading卡通渲染Shader,在函数:
VS_OUTPUT my_vs(VS_INPUT vert)
增加了反射函数reflect语句如下:
- float3 viewDir = normalize(worldPos - eyePos);vsout.cubeTex = reflect(viewDir, worldNormal)
计算中的反射和折射不需要程序手工计算,直接调用Shader的库函数就可以实现,但是原理还是要搞清楚。在该Shader中实现了两种效果:分别是立方体和球体,Shader实现方面也分了两个Technique,每个Technique有一个pass通道分别是关于立方体映射和球体映射。这里面涉及到两张贴图的渲染,一个是环境平面材质的渲染,另一个是球体的环境材质渲染。C++要实现此效果,需要两张贴图,第一张贴图是环境贴图,第二张是球贴图如下所示:
立方体环境映射渲染效果如图:
其在引擎内部的调用与前面CelShading的编写代码类似,这里就不介绍了。C++主要是调用不同的Technique以达到不同的渲染处理方式,代码语句如下:
- m_pEffect->SetTechnique("myCubeEnvMap");
这条语句是默认的通道,可以通过if else条件语句去切换立方体和球体映射,换句话说就是调用不同的Technique技术,因为GPU一次只能执行一个Technique。