opengl 阴影_Shadow Volume 阴影锥技术之探Ⅰ

0b0a4a364920714e450e45a8bb1d3bed.png

2009-1-24 22:35:21 | 发布:zwqxin

尝试了一下Shadow Volume(阴影锥)技术.现在是最简单的一步:懂得Shadow Volume形成的算法基础.采用非模型的简单三角形为光源遮挡物,采用基于OPENGL固定渲染管线的Z-PASS算法.接下来将会继续探讨对复杂模型的阴影生成,Z-FAIL算法和shader实现版本等等,同时修正BUG。——ZwqXin.com

a96748906902c8be5c4a053443c09083.png


图中橙色边面包围的那部分就是Shadow Volume,知道什么地方该产生阴影了吗?

7cdeca34e8e87f4c4359973f4d5053b4.png


采用Z-PASS算法,最后渲染出三角形投影到地面的阴影

1b21eb1854d4247671b09fa004cf1dbe.png


某视觉下的效果图
本文来源于 ZwqXin (http://www.zwqxin.com/), 转载请注明
原文地址:http://www.zwqxin.com/archives/opengl/shadow-volume-1.html
在进行实现之前,有必要弄清楚Shadow Volume的算法原理。事实上为了看懂原理(表面上貌似简单),在上学期末两科考试之间那段时间真的在图书馆鏖战了很久(当然不只问本文这种简单的实现)。假期尝试由浅入深,在实现上真正弄明白。这里推荐当时看的一篇文章:阴影锥(shadow volume)原理与展望---真实的游戏效果的实现
虽然这次的实现,我觉得是好简单,结果却真的耗了我差不多一天,晕!在一些小而关键问题上翻了跟斗。这里必要提醒一下要注意的地方:
1. 一个平面的绘制方式(正时针逆时针绘制问题)是很重要的,知道重要还不够,画的时候要小心!这也是我对接下来针对复杂模型阴影的担心(虽然实在不行可以请教NEHE27课)。
2.一帧渲染完后重画,单单把蒙板(stencil)清0是不行的(0只是整数蒙板值的其中普通的一个而已),一定要重设蒙板glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 我的 NEHE框架中默认是glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 所以后面那里要自己添加,否则久把上一帧的结果带到下一帧了(另外框架中也要在设子设置像素格式那里开启蒙板缓存(见此),这个不用说的了是必要的一步)。
部分代码:

  1. void CMainFrame::ShadowCast()//生成阴影函数
  2. {
  3. glPushAttrib(GL_ALL_ATTRIB_BITS);//先保存目前设置
  4. glEnable(GL_CULL_FACE);//打开可见面判断特性,接下来会看到它的用途
  5. glDisable( GL_LIGHTING );// 关闭灯光,光照计算对阴影锥来说是多余的
  6. // 关闭颜色缓存可写性,因为shadow volume不需要画出来
  7. glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
  8. //关闭深度可写性,这样就保存了当前屏幕各个像素的深度了
  9. glDepthMask(GL_FALSE);
  10. //开启深度测试,这样就可以比较新像素和旧像素的远近了!
  11. glEnable(GL_DEPTH_TEST);
  12. //开启蒙板测试,每个像素都有一个独立的蒙板值,拿来干嘛随你,这里拿来判断屏幕中拿些像素处于阴影中
  13. glEnable(GL_STENCIL_TEST);
  14. //全窗口屏幕各像素的蒙板缓存清0,好,准备好了!
  15. glClearStencil(0);
  16. /准备工作结束,开始画shadow volume并设置蒙板/
  17. //首先,设置深度的比较函数。因为关闭DEPTH TEST了,所以无论现在在图上画什么都不会影响像素原来的深度值
  18. //只有小于等于原像素深度值的那部分才画出来.
  19. //(这个其实是本框架默认的,一般OPENGL渲染就该让前面的东西遮盖后面东西时,直接不画被遮盖的那部分,又叫画家算法)
  20. glDepthFunc(GL_LESS);
  21. //
  22. //上面是针对人眼的(人换个位置看东西状况就不同了)。下面是针对阴影的(只有光和景物相对位置变动才会改变)
  23. glStencilFunc(GL_ALWAYS,1, 0xFFFFFFF);
  24. glStencilOp(GL_KEEP,GL_KEEP,GL_INCR);
  25. //这两个函数堆在一起,表示接下来画出来的东西会让它所占用的那些像素(这里干脆叫"新占像素"啦)的蒙板值增加1,稍微解释一下啦:
  26. //1.glStencilFunc前两个参数用来作比较,譬如 GL_GREATER, 1的话就是"新占像素的蒙板值大于1才画出来",这里是GL_ALWAYS,1,前者就表示新像素总能通过测试而被画出了,所以后面那个参数其实没什么用途;
  27. //最后那个参数,明眼人一看就知道是个16进制表示的二进制数啦,其实跟IP掩码一样的,但它掩的是像素值。化为二进制数后位为1的那部分才比较,这里既然全F(111……)就是说全比较啦。所以也是没用途的(都GL_ALWAYS了)
  28. //2.glStencilOp表示处理结果,参数分别指明了:没通过深度测试和蒙板测试的时候怎样;通过了深度测试却没通过蒙板测试时怎样;都通过了时又怎样.
  29. //上面都让它们全通过了,前两个参数能奈何什么,呵呵!所以根据最后那个参数,"新占像素"蒙板值都加1了.
  30. //说了那么多,究竟让什么的蒙板加1啊?根据Z-PASS算法,这里是让ShadowVolume面朝我们的那些面加1;怎么判断哪些面朝我们呢?阴影体画出来后你看得见的那些面咯(只渲染你所见的所有逆时针画出来的面)
  31. glFrontFace(GL_CCW);//GL_CCW表示逆时针,只渲染看上去逆时针画的面
  32. ShadowVolume(false);//小函数卖面不卖线~
  33. //按照Z-PASS算法,接下来是:正面背对逆的面蒙板减1.这个类似的.
  34. //glStencilFunc(GL_ALWAYS,1, 0xFFFFFFF);//这句一样的就不要写了,OPENGL会直接继承上面的设置的
  35. glStencilOp(GL_KEEP,GL_KEEP,GL_DECR);//接下来画的"新占像素"全部无条件通过,蒙板减1
  36. glFrontFace(GL_CW);//变为:看上去顺时针的才画出来
  37. ShadowVolume(false);//再渲染一次shadow volume
  38. //然后就可以画阴影了,在全屏幕蒙板值不为0的地方画阴影(看到上面有点红有点黄的部分吗?蒙板测试结果,只有这里蒙板非0)
  39. glStencilFunc(GL_NOTEQUAL,0, 0xFFFFFFF);
  40. glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);//让蒙板非0的像素通过测试,接受接下来对它的XX
  41. //画阴影也许有更好方法,这里沿用传统那种粗暴方法:直接途黑掉它算了!
  42. //1.关掉裁减,当你不确定自己接下来是否一定会按逆时针为正的规则作图
  43. glDisable(GL_CULL_FACE);
  44. //2.打开颜色缓存,因为“阴影”要画出来
  45. glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
  46. //3.开混合,让阴影颜色和阴影所再物体的本来颜色混合一下
  47. glEnable(GL_BLEND);
  48. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  49. //4.转到正视图,这样画出来的矩形能覆盖全屏幕
  50. OthoView();//自定义,和接下来的PerpectiveView()配合
  51. glColor4f(0.0,0.0,0.0,0.9);
  52. glRectf(0.0, 0.0, VB_WIDTH, VB_HEIGHT);
  53. PerpectiveView();//转回透视视图
  54. //把刚才修改过的设置都设回原值
  55. glDisable(GL_BLEND);
  56. glDisable(GL_CULL_FACE);
  57. glEnable( GL_LIGHTING );
  58. glDepthFunc(GL_LEQUAL);
  59. glDepthMask(GL_TRUE);
  60. glDisable(GL_STENCIL_TEST);
  61. glPopAttrib();
  62. }


下一篇见:Shadow Volume 阴影锥技术之探Ⅱ(模型的影子)
放上本DEMO:shadowvolumeDemobyZwqxin.rar
按键:
→ ← ↑ ↓ PageUp 移动光源鼠标左键下按不放并移动鼠标:旋转视角;鼠标滚轮移动
空格:转变查看模式:辅助可视阴影锥/光源射线模式/正常模式
本文来源于 ZwqXin (http://www.zwqxin.com/), 转载请注明
原文地址:http://www.zwqxin.com/archives/opengl/shadow-volume-1.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值