HLSL的应用—反射环境映射
反射环境映射有两种,静态环境映射和动态环境映射,我们从简单的即静态的开始看
静态的环境映射其实很简单,原理是主程序中先把CUBE贴图生成好,然后在shader里面计算出相对视线的反射向量,然后用一个texCUBE采样函数就可以了.来看看shader代码:
//--------------------------------------------------------------
// Desc: 效果文件
//--------------------------------------------------------------
//--------------------------------------------------------------
// 全局变量
//--------------------------------------------------------------
float4x4 matWorldViewProj;
float4x4 matWorld;
float4x4 matView;
float4 vecEye;
//---------------------------------------------------------------
// 立方体纹理采样器
//---------------------------------------------------------------
texture CubeMap;
samplerCUBE CubeMapSampler = sampler_state
{
Texture = <CubeMap>;
MinFilter = Linear;
MagFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};
//--------------------------------------------------------------
//顶点渲染器输出结构
//--------------------------------------------------------------
struct VS_OUTPUT
{
float4 Pos : POSITION;
float3 Reflect: TEXCOORD4;
};
//-------------------------------------------------------------
// 顶点渲染器主函数
//-------------------------------------------------------------
VS_OUTPUT VS(float4 Pos : POSITION, float2 Tex : TEXCOORD, float3 Normal : NORMAL)
{
VS_OUTPUT Out = (VS_OUTPUT)0;
//坐标变换
Out.Pos = mul(Pos, matWorldViewProj);
//计算世界空间中的顶点法线并标准化
float3 Norm = normalize(mul(Normal, matWorld));
//计算从顶点指向观察点的方向向量并标准化
float3 PosWorld = normalize(mul(Pos, matWorld));
float3 Incident = normalize(PosWorld - vecEye);
//计算立方体映射的反射向量
Out.Reflect = normalize(reflect(Incident, Norm));
return Out;
}
//-------------------------------------------------------------
// 像素渲染器主函数
//-------------------------------------------------------------
float4 PS(VS_OUTPUT In) : COLOR
{
return texCUBE(CubeMapSampler, In.Reflect);
}
//-------------------------------------------------------------
// 技术
//-------------------------------------------------------------
technique TShader
{
pass P0
{
VertexShader = compile vs_2_0 VS();
PixelShader = compile ps_2_0 PS();
}
}
实现很简单,这里主要说明一下HLSL库提供的reflect函数.它是用来计算反射向量的,其第一个参数是视线向量,第二个参数是法向量,返回视线向量经法向量所在平面反射后的向量.
R = I-2*N*dot(I,N); 用矢量图画画就出来了.
算出这个反射向量后再把它传到texCUBE里面去采样,得出的即是正确的颜色值了.
然后再拓展一下,刚才我们实现了反射效果,我们再来看看怎么实现折射效果,这个也不难,只是结果不是那么精确,因为我们不知道观察物体的折射率.因此我们在反射计算时加个小小的步骤,把法向量缩放一下,得出近似的折射向量.
//折射向量
float3 ShortNorm = mul(Norm, 0.4);
Out.Reflect2 = normalize(reflect(Incident, ShortNorm));
其他的和上例一样.
好了静态的就先到此,下面我们来看动态的
动态的环境映射也就是要动态的更新环境贴图,怎么更新呢?只要在所观察的物体的六个方向分别拍下快照,然后作为无缝的拼成一张CUBE贴图就可以了.具体怎么拍这个快照呢,DirectX已经有一个接口可以做这件事了,就是ID3DXRenderToEnvMap,具体的用法SDK里说的很详细.动态建好cube贴图后其他的就和静态的一样了!不难吧~!发现自己越来越浮躁了,什么时候自己动手写写就知道艰难了…呃….
转帖