一. 概述
折射是自然界中常见的现象,当光从一种介质到另一种介质时会发生折射,在图形学中利用折射可以实现很多效果使得效果更为逼真如热浪 狙击镜 水面等。


二. 实现思路
折射的实现方式有很多种有些方法是通过计算环境映射然后在运行时使用,但这种方式在场景中有很多折射表面时需要不同的环境映射因为会损失效率。还有一种模拟水折射的方式是通过水面上的集合信息生成折射图,再由折射图绘制水的折射,这种方案对水的绘制是分两次绘制,对复杂场景仍然存在性能问题。本示例用一个简单的方式近似模拟折射效果,用较小的代价实现近似折射效果。其基本思路即是: 利用RTT(render to texture)把现有的后台缓存作为一张帖图,通过对该帖图局部或者整体的纹理坐标进行位移来模拟折射效果。


三. 实现方式
折射效果的实现主要分为两个步骤:第一步则是将场景绘制到一张纹理Texture(当然绘制的对象不包括折射对象)
第二步则是绘制折射对象,绘制折射对象时通过扰动过的纹理坐标从Texture纹理中查找值来模拟折射效果。这个扰动可以通过法向量的XY(RG)通道乘以一个很小的值如0.005来作为纹理坐标的扰动值来实现。以下示例用折射原理实现火焰热浪的热扰动效果。


三. 具体代码
Away3D关于RTT后处理可以利用滤镜效果实现因此可以通过自己实现热浪滤镜HeatHazeFilter3D实现:



关于对纹理坐标的扰动的Shader则是在Filter3DHeatHazeTask中实现



Shader实现先从扰动纹路中获取数据归一化到uv(0~1)范围,再用uv乘以0.05作为扰动值加上原来的uv坐标作为扰动后坐标从主纹理中采样.


四. 实现效果:
增加热浪效果之前




增加热浪效果





五. 潜在问题及解决方法:
由于该折射实现方式是先将场景中对象绘制到纹路在绘制折射对象故而折射对象一定在最上层,但当相机与火焰(折射对象)之间存在其他对象(如一个盒子)时,盒子会作为背景绘制与实际现象相违背,如下图 图中灰色方块是在相机和火焰之间应该是木板遮挡部分火焰,但由于是先对场景中对象绘制再绘制火焰折射故绘制顺序会被颠倒。





解决方法则是要设法将遮挡区域标记出来不对其进行扰动,具体作法可以利用渲染到纹理Texture的alpha通道标识当前区域是否被遮挡,初始时设置所有aplha值为0绘制折射对象时将绘制区域alpha值设为1此时由于深度测试只有可以被扰动的区域alpha值为1此时只需修改shader,将最后一步的采样代码 tex oc, ft0, fs0 <2d, nearest>\n;修改为
tex ft2, ft0, fs0 <2d, nearest>\n tex ft3, v0, fs0 <2d, nearest>\n mul ft2, ft2, ft2.w mul ft3 ft3,(1-ft3.w)(伪代码)
即扰动后数据* alpha + 扰动钱数据*(1-alpha) 由于只有未被遮挡区域alpha为1也就实现了只对未被遮挡区域的折射效果处理。


锐亚教育

锐亚教育,游戏开发论坛|游戏制作人|游戏策划|游戏开发|独立游戏|游戏产业|游戏研发|游戏运营| unity|unity3d|unity3d官网|unity3d 教程|金融帝国3|8k8k8k|mcafee8.5i|游戏蛮牛|蛮牛 unity|蛮牛