笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。
CSDN课程视频网址:http://edu.csdn.net/lecturer/144
环境映射在材质的渲染上同样应用广泛,现实生活中我们也经常遇到环境映射,比如一个光滑的铁球上可以映射出周围环境。它的实现方式就是把周围的环境通过反射,折射映射到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 = <cubeMapTexture>;
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 = <sphereMapTexture>;
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。

本文详细介绍了环境映射技术在3D渲染中的应用,包括通过一张环境贴图和六张贴图实现的不同效果,并提供了具体的Shader代码示例。
5155

被折叠的 条评论
为什么被折叠?



