3d Game Walkman

3d图形渲染,网络引擎 — tonykee's Blog
随笔 - 45, 文章 - 0, 评论 - 309, 引用 - 0
数据加载中……

能穿透alphatest纹理的shadowmap

这几天加入了shadowmap影子,着实费了点脑子看起来很简单的,可这东西牵扯到很多东西,场景要成像的对象都要统一纳入深度图里面渲染一遍,加了很多渲染方面的组织代码,静态模型,骨骼模型,等等,都要影子,渲染的方法还略有区别,真是很繁琐,眼看就要成功了,可烦心事又来了,灯光没办法穿透alpha纹理,那些树叶都是一大片一大片的,根本不透光,场景中为了节约三角形,要做alphatest的纹理比比皆是,如果光线穿不透alpha纹理,那可太糟糕了,在gameres上问了一把,clayman和六水两位大侠给了我不小的帮助,主要的思路是深度图是需要做alphatest的,这样才能被穿透,直接用R32F我试过了,alphatest根本无效,也不知道是不是显卡太差了,看了一篇文章,
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纹理的穿透,还真是不容易,发图出来鉴赏一下这两天的成果:

posted on 2008-05-27 15:57 李侃 阅读(3059) 评论(8)  编辑 收藏 引用 所属分类: 前台客户端

评论

# re: 能穿透alphatest纹理的shadowmap  回复  更多评论   

高,实在是高!!

请问你学3d多久了
2008-05-27 16:05 | xiao7cn

# re: 能穿透alphatest纹理的shadowmap  回复  更多评论   

原来gameres上的问题是你问的啊。
2008-05-27 16:13 | 空明流转

# re: 能穿透alphatest纹理的shadowmap  回复  更多评论   

时间不算长,没记错的话,应该是22个月吧
2008-05-27 16:17 | 李侃

# re: 能穿透alphatest纹理的shadowmap  回复  更多评论   

渲染方面学的不好,见笑了。
2008-05-27 16:20 | 李侃

# re: 能穿透alphatest纹理的shadowmap  回复  更多评论   

才知道你的昵称就是tonykee。
2008-05-27 17:50 | 空明流转

# re: 能穿透alphatest纹理的shadowmap  回复  更多评论   

厉害是个牛人
2008-05-28 16:06 | 盛大推广员

# re: 能穿透alphatest纹理的shadowmap  回复  更多评论   

在PS里用纹理的Alpha来clip就可以了,连Alpha通道都不用占用。
2008-12-16 21:36 | 蓝色比特

# re: 能穿透alphatest纹理的shadowmap  回复  更多评论   

弱弱问下
这样应该是spot light吧,如果是平行光怎么办...
2009-02-05 21:02 | dongch007

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理