能穿透alphatest纹理的shadowmap
GPU GEM1
http://http.developer.nvidia.com/GPUGems/gpugems_ch12.html
有提到这个算法,可以把R32F转换为A8R8G8B8即可节约内存又可以提高兼容性,很多显卡还不支持R32F呢,
这就涉及到一个压缩和解压的算法,那篇NV的文章说的太抽象,很不具体,试了很久也不成功。
网上找了一个晚上加一上午的时间,终于找到了答案
http://www.gamedev.net/community/forums/topic.asp?topic_id=442138
这个主题就是讨论这个算法的。
其中:
float4 pack(float fDist)
{
const float4 bitSh = float4( 256*256*256, 256*256, 256, 1);
const float4 bitMsk = float4( 0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
float4 comp;
comp = fDist * bitSh;
comp = frac(comp);
comp -= comp.xxyz * bitMsk;
//我这里稍微该了改,把最后低的精度移到了末尾
return float4(comp.y, comp.z, comp.w, comp.x);
}
float unpack(sampler ShadowMapS, float2 texcood)
{
float4 vec = tex2D(ShadowMapS, texcood);
//我这里稍微该了改,把最后一个精度移到了末尾
const float4 bitShifts = float4(1.0/(256.0*256.0), 1.0/256.0, 1, 1.0/(256.0*256.0*256.0));
//return vec.x*1.0/(256.0*256.0*256.0) + vec.y* 1.0/(256.0*256.0) + vec.z*1.0/256.0 + vec.w;
return dot(vec.xyzw , bitShifts);
}
//以下是shadowmap的拍摄过程
void BuildShadowMapVS(float3 posL : POSITION0,
float3 normalL : NORMAL0,
float2 tex0 : TEXCOORD0,
out float4 posH : POSITION0,
out float2 depth : TEXCOORD0,
out float2 tex1 : TEXCOORD1
)
{
// Render from light's perspective.
posH = mul(float4(posL, 1.0f), gLightWVP);
// Propagate z- and w-coordinates.
depth = posH.zw;
tex1 = tex0;
}
float4 BuildShadowMapPS(float2 depth : TEXCOORD0, float2 tex1 : TEXCOORD1) : COLOR
{
// Each pixel in the shadow map stores the pixel depth from the
// light source in normalized device coordinates.
float a = tex2D(TexS, tex1).a;
float f = clamp(depth.x / depth.y , 0, 1);
float4 val=pack(f);
if(a < 0.5)
val.a = 0.0f;
else
val.a = 1.0f;
return val;
}
就是关键的float与A8R8G8B8之间的压缩和解压的算法,其中
comp -= comp.xxyz * bitMsk;很难理解,但仔细想一想你就能想明白其中的道理
这个是可以转换了,但里面还有更为关键的东西,还要把A8的alpha信息加进去,不然还是不能做影子的alpha测试,根据六水兄的提议,我也忽略了256*256*256末尾的精度,加入了成像纹理的alpha信息,这样最终实现了光线对alpha纹理的穿透,还真是不容易,发图出来鉴赏一下这两天的成果: