Chinaunix首页 | 论坛 | 博客
  • 博客访问: 178006
  • 博文数量: 43
  • 博客积分: 827
  • 博客等级: 准尉
  • 技术积分: 487
  • 用 户 组: 普通用户
  • 注册时间: 2012-01-26 19:19
文章分类

全部博文(43)

文章存档

2015年(1)

2014年(1)

2013年(5)

2012年(36)

我的朋友

分类: WINDOWS

2012-02-19 20:32:02

对于Spot Light,先根据投射的方向进行投影可以得到这个Spot Light的光晕。
比如:
光晕图:
那么对于他的光照可以基于光晕使用Per-Pixel Light技术。
对于空间中的物体,使用Spot Light的Project Matrix进行投影,投影过后就得到了这个物体在光晕中坐标。这样这个物体在该Spot Light中的光照就确定了(物体和光源在同一个View Plane上,物体的投影和光晕投影的交集确定了这个物体上的Spot Light光照)。
Project Matrix = Word(Obj)*View(Light)*Proj(Light)*MatToTexcoord
Word(Obj)   : 这个物体的World Matrix,将物体变到世界坐标系中
View(Light) : Spot Light的View Matrix,Spot Light类似于Eye Position,Spot Light的方向类似于View Direction
Proj(Light)  :  Spot Light的Perspective Matrix,将Spot Light的"观察视域"投影为一个平面
MatToTexcoord : 变换得到光晕Texture上的坐标。该矩阵为
 D3DMATRIX   matToTexCoord = 
            {
                0.5f, 0.0f, 0.0f, 0.0f,
                0.0f, -0.5f, 0.0f, 0.0f,
                0.0f, 0.0f, 1.0f, 0.0f,
                0.5f, 0.5f, 0.0f, 1.0f
            };
因为在Porj过后得到的Clip Space坐标(Xp, Yp, Zp, Wp):
Xp/Wp = (-1, 1)
Yp/Wp = (1, -1)
而Texture中的坐标为:u = (0, 1), v = (0,1)
所以
(Xp/Wp)*0.5+0.5    = (0, 1)
(Yp/Wp)*(-0.5)+0.5 = (0,1)
这样可得到对应的Texture上的坐标
效果如图所示:


问题:
1:对于Spot Light的背后因该是没有光照的,但是上面的过程仅仅使用了x和y,而x,y在Spot Light的两侧经过上面的变换时对称的,所以前后都有光照。
2:没有光照的衰减

解决问题1:
在DX中Projection Matrix为:

也就是经过投影变换过后,得到的Zp = Zf*(Zv-Zn)/(Zf-Zn), Wp = Zv

Zp/Wp = Zf*(Zv-Zn)/[(Zf-Zn)*Zv]

Zf: The z value of the far plane
Zn: The z value of the near plane
Zv: The z value of the pixel in the view space

Zn and Zf are specified while constructing the project matrix

对于Zp/Wp值的讨论:
Zn<=Zv<=Zf            ---->Zp/Wp = [0, 1]
Zv>Zf                      ---->Zp/Wp > 1           
0Zp/Wp < 0
Zv<0                        ---->Zp/Wp > 1

那么也就是说:在Spot Light 到 Far Plane的Zp/Wp <= 1,这个空间也是这个Spot Light会产生光照的地方。
而对于Zv<0 (表示在Light之后的区域)和Zv>Zf(表示在Light不能照射的区域)Zp/Wp都是>1的,因此在Pixel Shader中添加这个判断,如果>1,则光照值为0,可去除太远和背后不应该产生的光源。

解决问题2:
使用Clamp(1-Zp/Wp)作为光照衰减值。这里Clamp会将>1的值设定为1,<0的值设定为0;而对于在Zn之后的Zp/Wp为负值,那么Clamp值将一直为1,这可以作为在近端的无衰减区域.另外因为Zp/Wp的值会变化的很快,可以使用Clamp(Weigth*(1-Zp/Wp))为光照的衰减值,这里Weight为一个权值,

效果:
PS:
1:可以在构造View和Project 矩阵时使用参数来控制Spot Light的光源性质,比如张角,方向,光源有效距离。
2:光晕图的周围必须为0,对于采样的时候使用Clamp状态采样,用来将光照周围的值都设定为0.

Code:
Vertex Shader
  1. vs_3_0
  2. ; Input
  3. dcl_position v0
  4. dcl_color0 v1
  5. ; Output
  6. dcl_position o0
  7. dcl_color0 o1
  8. dcl_texcoord0 o2
  9. ; c0~c3 geometry matrix
  10. ; c4~c7 light project matrix
  11. m4x4 o0, v0, c0
  12. mov o1, v1
  13. m4x4 o2, v0, c4

Pixel Shader
  1. ps_3_0
  2. ; input
  3. dcl_color0 v0
  4. dcl_texcoord0 v1
  5. dcl_2d s0
  6. def c0, 0.2, 1.0, 30.0, 0.0
  7. ; Compute the texcoord
  8. rcp r0, v1.w
  9. mul r0, r0, v1
  10. ; if Zp/Wp >= 1, p0 will be true
  11. setp_ge p0, r0.z, c0.y
  12. ; Sample the project light texture
  13. texld r1, r0, s0
  14. ; if the Zp/Wp >=1, set r1 0
  15. (p0.x)mov r1, c0.z
  16. ; Compute the attenuation
  17. sub_sat r0, c0.y, r0.z
  18. mul_sat r0, r0, c0.z
  19. mul r1, r1, r0
  20. ; Add the ambient
  21. add r0, r1, c0.x
  22. mul oC0, r0, v0


阅读(868) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~