倒影(reflections)效果的实现

1、简介

当站在湖畔岸边或者镜子面前的时候,都可以看到倒着的自己,那种效果就叫倒影,或者叫镜面反射。在SPE中也支持这种效果,实现的基本思路是把物体根据反射平面镜像之后再绘制一遍,绘制镜像时有几个问题需要注意:1、把深度测试关掉;2、如果打开了背面剔除,背面要反转,即如果设置逆时针为正面,则绘制倒影时逆时针应为背面。3、记得打开混合,并设置好倒影的透明度;4、先绘制反射平面,接着绘制倒影,最后绘制正常物体。

2、reflection matrix的推导

给定一个顶点V(x,y,z,1)以及一个平面P(n,d),其中n为平面单位法向量,d为原点到该平面的有向距离;怎么求得顶点V相对于平面P的镜像顶点V‘呢?如图1所示:如果求得V到平面P的距离D,那V‘ = V - 2*Dn,把顶点V跟平面P的方程进行点乘即可求得D,即D = V dot P = nx*x+ny*y+nz*z+d,把D代入到前面的式子中,可以把式子变成V' = MV的形式,这个M是个4x4的矩阵,就叫反射矩阵(reflection matrix),它的各元素如下所示:

                                          图1:求顶点的镜像

3、绘制倒影

有了反射矩阵,在绘制物体时,只需要在物体世界变换之后再加入镜像变换,即乘以世界变换矩阵之后,再乘以反射矩阵,就可以绘制倒影了。主要的代码如下:

void cReflectDemo::OnFrameRender()
{cCamera *pCam = cScene::GetSingletonRef().GetActiveCamera();pCam->LoadAllMatrix();glClearColor(0.5f,0.6f,0.7f,1.0f);glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);// render planeplaneMat_.ApplyMaterial();Utils::DrawPlane(3.5f,Utils::PLANE_Y,VECTOR3D(0,-1.0f,0));// render mirrored cubeMATRIX4X4 reflectMat;MakeReflectMatrix(reflectMat,VECTOR3D(0,1,0),1.0f);glFrontFace(GL_CW); // attention!!glDisable(GL_DEPTH_TEST);glEnable(GL_BLEND);glBlendColor(0,0,0,0.4f);glBlendFunc(GL_CONSTANT_ALPHA,GL_ONE_MINUS_CONSTANT_ALPHA);glMatrixMode(GL_MODELVIEW);glPushMatrix();glMultMatrixf(reflectMat);cubeMat_.ApplyMaterial();cube.Render();glPopMatrix();glEnable(GL_DEPTH_TEST);glDisable(GL_BLEND);glFrontFace(GL_CCW);// render cube noramllycubeMat_.ApplyMaterial();cube.Render();
}

该代码绘制了一个大小为2的正方体,以及其相对于平面<(0,1.0f,0),1.0f>的镜像,如下图所示:


                                             图2:倒影0

注意到倒影在非镜面所占的区域也有显示(右下角),在实际中是不可能的,解决这个问题的方法是:将镜面所占的屏幕区域进行标记,然后绘制倒影时,只在标记了的屏幕区域进行显示,这在OpenGL中可以用模板测试做到,更改后的代码如下,其中在//...和//...之间的代码为新加的,新的倒影效果如图3所示:

void cReflectDemo::OnFrameRender()
{cCamera *pCam = cScene::GetSingletonRef().GetActiveCamera();pCam->LoadAllMatrix();glClearColor(0.5f,0.6f,0.7f,1.0f);glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);// open stencil testglEnable(GL_STENCIL_TEST);// render plane// flag the plane area with 1'sglStencilFunc(GL_ALWAYS,0x1,0x1);glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);planeMat_.ApplyMaterial();Utils::DrawPlane(3.5f,Utils::PLANE_Y,VECTOR3D(0,-1.0f,0));// render mirror cube// only draw the mirror cube to the plane areaglStencilFunc(GL_EQUAL,0x1,0x1);glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);MATRIX4X4 reflectMat;MakeReflectMatrix(reflectMat,VECTOR3D(0,1,0),1.0f);glFrontFace(GL_CW); // attention!!glDisable(GL_DEPTH_TEST);glEnable(GL_BLEND);glBlendColor(0,0,0,0.4f);glBlendFunc(GL_CONSTANT_ALPHA,GL_ONE_MINUS_CONSTANT_ALPHA);glMatrixMode(GL_MODELVIEW);glPushMatrix();glMultMatrixf(reflectMat);cubeMat_.ApplyMaterial();cube.Render();glPopMatrix();glEnable(GL_DEPTH_TEST);glDisable(GL_BLEND);glFrontFace(GL_CCW);// close stencil test to draw other thingsglDisable(GL_STENCIL_TEST);// render cubecubeMat_.ApplyMaterial();cube.Render();
}

                                                  图3:倒影1
4、物体与镜面相交时的倒影

                                                              图4:倒影artifacts

如图4所示,此时镜面跟立方体相交,如果按照上面的代码绘制倒影,就会出现不正常现象:镜面下方的物体部分被反射到上面来了;解决的办法是:绘制倒影时使用设置镜面为裁剪面,把镜面上方的倒影部分裁掉,不予以显示;OpenGL中设置裁剪面的函数是glClipPlane,它的原型是void glClipPlane( GLenum plane, const GLdouble *equation),关于该函数,官方文档中有一句话是这么说的:

When glClipPlane is called, equation is transformed by the inverse of the modelview matrix and stored in the resulting eye coordinates. Subsequent changes to the modelview matrix have no effect on the stored plane-equation components.

意思是说当函数被调用时,裁剪平面会被当前模型视图矩阵的逆矩阵变换到视图空间,然后被保存起来,之后模型视图矩阵的改变不会再影响它。这说明平面在物体的模型空间给定,然后被变换到视图空间,但是变换到视图空间应该乘以模型视图矩阵的逆的转置才对,我已经试验过,OpenGL确实是乘以模视矩阵的逆的转置,但文档写错了,误导了不少人。

下面贴上加了裁剪面的实现代码:

void cReflectDemo::OnFrameRender()
{cCamera *pCam = cScene::GetSingletonRef().GetActiveCamera();pCam->LoadAllMatrix();glClearColor(0.5f,0.6f,0.7f,1.0f);glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);// open stencil testglEnable(GL_STENCIL_TEST);// render plane// flag the plane area with 1'sglStencilFunc(GL_ALWAYS,0x1,0x1);glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);planeMat_.ApplyMaterial();Utils::DrawPlane(3.5f,Utils::PLANE_Y,VECTOR3D(0,0.3f,0));// render mirror cube// only draw the mirror cube to the plane areaglStencilFunc(GL_EQUAL,0x1,0x1);glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);MATRIX4X4 reflectMat;MakeReflectMatrix(reflectMat,VECTOR3D(0,1,0),-0.3f);glFrontFace(GL_CW); // attention!!glDisable(GL_DEPTH_TEST);glEnable(GL_BLEND);glBlendColor(0,0,0,0.4f);glBlendFunc(GL_CONSTANT_ALPHA,GL_ONE_MINUS_CONSTANT_ALPHA);glMatrixMode(GL_MODELVIEW);glPushMatrix();glMultMatrixf(reflectMat);// setup clipping planeGLdouble planeEqu[] = {0,1.0,0,-0.3};glEnable(GL_CLIP_PLANE0);glClipPlane(GL_CLIP_PLANE0,planeEqu);cubeMat_.ApplyMaterial();cube.Render();// disable clipping plane0glDisable(GL_CLIP_PLANE0);glPopMatrix();glEnable(GL_DEPTH_TEST);glDisable(GL_BLEND);glFrontFace(GL_CCW);// close stencil test to draw other thingsglDisable(GL_STENCIL_TEST);// render cubecubeMat_.ApplyMaterial();cube.Render();
}

纠正后的倒影效果如下图所示:


                                                     图5:纠正后的倒影

5、倒影绘制shader

为了更方便,也可以使用专门设计的shader来绘制倒影,顶点shader和像素shader看起来像下面这样:

// reflection.vs
// for phong shading
varying vec3 viewPos;
varying vec3 viewNorm;uniform mat4 reflectionMatrix;
uniform mat4 worldMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;void main()
{viewPos = viewMatrix*reflectionMatrix*worldMatrix * gl_Vertex;viewNorm = normalize(gl_NormalMatrix * gl_Normal);gl_Position = projectionMatrix*viewMatrix*reflectionMatrix*worldMatrix*gl_Vertex;gl_ClipVertex = gl_ModelViewMatrix * pos;
}
// reflection.fs
varying vec3 viewPos;
varying vec3 viewNorm;uniform float alpha;void main()
{gl_FragColor = Lighting(viewPos,viewNorm);gl_FragColor.a = alpha;
}



 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/252344.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

渐变加蒙版做倒影

平面设计是PHOTOSHOP应用最为广泛的领域&#xff0c;无论是我们正在阅读的图书封面&#xff0c;还是大街上看到的招帖、海报&#xff0c;这些具有丰富图像的平面印刷品&#xff0c;基本上都需要PHOTOSHOP软件对图像进行处理。用Photoshop 为图片添加倒影&#xff0c;这个效果不…

联想IBM ThinkPad X201i 笔记本显示屏上方中间的键盘灯不亮解决办法

这款小黑&#xff0c;不记得13年还是14年买的&#xff0c;当年就要7千大洋&#xff0c;那时候觉得很贵咬牙买了下来&#xff0c;今天回头看来贵有贵的道理。因为现在用起来还是很爽&#xff0c;去年安装Win10&#xff0c;然后在上面开发JavaEE项目&#xff0c;很快、畅顺。最近…

ibm 服务器 总显示f1,联想ThinkPad笔记本中F1/F4键盘指示灯一直常亮着如何解决

有不少使用联想ThinkPad笔记本的小伙伴们在使用电脑的时候&#xff0c;发现遇到这样一个情况&#xff0c;就是键盘上的F1/F4键盘状态指示灯常亮&#xff0c;按FNESC组合键也无法取消&#xff0c;按FN和对应的功能键也不行&#xff0c;这可该怎么解决呢&#xff0c;一般是由于热…

联想拯救者 Lenovo Legion 通电自启 插电自启 通电开机 插电开机 Wake on AC

联想拯救者 Lenovo Legion 通电自启 插电自启 通电开机 插电开机 Wake on AC 文章目录 联想拯救者 Lenovo Legion 通电自启 插电自启 通电开机 插电开机 Wake on AC说明一、我的电脑二、详细过程1.BIOS选项2.查阅改BIOS的资料3.修改BIOS失败4.换个思路&#xff1a;不修改BIOS?…

联想键盘sk8821的Fn功能键

1. 联想键盘sk8821的Fn功能键 1.1. 恢复 F1-F12实际功能 F1-F12系统下会默认为快捷键&#xff08;功能键&#xff09;&#xff0c;而非F1-F12实际功能。可能会导致您在使用习惯上的不适应。 键盘驱动安装目录&#xff1a;X:\LX_KEY\Yangtian\Low Profile Keyboard\setup.exe …

如何关闭联想台式机电脑USB键盘的FN功能

如何关闭联想台式机电脑USB键盘的FN功能 现在很多单位配备的联想台式机所配的USB键盘&#xff0c;F1-F12系统下会默认为快捷键&#xff08;功能键&#xff09;&#xff0c;而非F1-F12实际功能。可能会导致您在使用习惯上的不适应。 通过查询联想官网有如下解决方案&#xff0c;…

禁用联想笔记本电脑自带的键盘

最近电脑键盘出现故障&#xff0c;只要一开机&#xff0c;删除键就一直被按着&#xff0c;按其它键后&#xff0c;偶尔就恢复正常状态。被逼无奈&#xff0c;今天拿去电脑维修店&#xff0c;老板说是键盘的问题&#xff0c;需要换键盘。询问价格&#xff0c;说要&#xffe5;30…

杜蕾斯鞋套?又污又高级!

阳历四月雨纷纷&#xff0c;噼里啪啦湿鞋袜。 杜蕾斯专注“防水”九十多年。眼看大家进入了雨季&#xff0c;杜蕾斯上演一出《典中典》&#xff0c;上线经典鞋套。 我怀疑你在招风惹雨&#xff0c;只是我没证据。 穿这个鞋套出门会不会社死不知道&#xff0c;但谁用这玩意儿绝对…

压缩包.zip暴力破解方法

一: 前言 本方法基于虚拟机下的kali系统,软件为kali自带的fcrackzip,有兴趣的童鞋请自行研究下载. 二:方法说明 fcrackzip -help常用参数中文说明&#xff1a; -b 暴力破解模式 -D 使用字典破解模式 -v 就是可以看到更多的信息 -u 用zip去尝试 -l 密码长度 -c 指定掩码类型&…

python暴力破解zip加密文件

前言&#xff1a; 日常工作中&#xff0c;会遇到一些加密的zip文件&#xff0c;但是因为某些原因或者时间过长&#xff0c;密码不知道了。 但是zip文件中文件有很重要很必须。那么&#xff0c;我们试一试万能的Python&#xff0c;暴力破解密码。 一、破解zip加密文件的思路&a…

《在路上 …》 金山卫士开源 , 人生很多感慨

最近写日记少了很多, 主要是很多情绪化的东西, 都汇入了某条有去无回的地下河. 好吧, 不说这些, 来说说金山卫士开源. 相比360安全卫士那种作秀式的开源 (代码只对极少极少的人开放, 隐隐藏藏), 金山这次显得很真诚. 你可以直接看到代码 http://code.ijinshan.com/ http://code…

【Opencv实战】Python神器 | ps做印章太麻烦?无法拒绝的提取印章神技能,很多人都不知道~(附源码)

前言 哈喽&#xff0c;大家好&#xff0c;我是你们的栗子同学鸭~ 更新了很久的爬虫内容啦&#xff0c;已经吸收完了没&#xff1f; 印章作是我们工作中和生活中会经常接触到的东西&#xff0c;一般用来代表某个个体或者群体&#xff0c;有时候 我们需要复刻一些文件&#x…

PS制作印章

本文使用Photoshop制作古典印章。印章形式大体分阳文和阴文两种&#xff0c;也称朱文和白文。 1、新建一400X400像素&#xff0c;白色背景的文档&#xff0c;在图层面板双击解锁变成图层0。 2、设前景色为R230&#xff0c;G30,B30。这是模仿印泥的颜色&#xff0c;没有一定的…

ps 制作印章

工具 photoshop cs6 方法/步骤 首先我们新建一个600*400的画布&#xff0c;按Ctrlr调出标尺&#xff0c;然后拖动标尺平分画布宽和高&#xff0c;然后选择椭圆选区工具&#xff0c;以参考线中心为原点&#xff0c;按住ShiftAlt绘制一个正圆&#xff0c;填充前景色为#ff0000。…

华为android系统怎么关闭,华为手机怎么关闭情景智能?华为手机关闭情景智能教程...

华为手机关闭情景智能教程 华为手机有个情景智能&#xff0c;记录你的信息然后辅助你做一些事情&#xff0c;但是有时候就是觉得不太习惯&#xff0c;那么怎么来关闭它呢&#xff0c;首先打开手机&#xff0c;来到手机桌面&#xff0c;找到设置菜单&#xff0c;直接点击进入设置…

如何关闭华为手机智慧助手

手机会自动开启智能助手&#xff0c;当不需要这个功能的时候那就可以选择关闭。所以&#xff0c;今天聊聊华为手机智能助手怎么关闭。 在手机桌面空白处&#xff0c;两个手指往中间滑&#xff0c; 下面的内容转自&#xff1a; https://jingyan.baidu.com/article/0320e2c160…

华为浏览器关闭广告

前言 华为手机和平板在使用自带的华为浏览器时&#xff0c;启动页面或多任务切换时可能会出现广告&#xff0c;这个广告是可以通过设置关闭的&#xff0c;下文介绍关闭方法。 关闭方法 打开华为浏览器&#xff0c;打开设置&#xff0c;选择安全与隐私&#xff0c;点击个性化…

android系统怎么取消,安卓系统hd怎么关闭

大家好&#xff0c;我是时间财富网智能客服时间君&#xff0c;上述问题将由我为大家进行解答。 以vivox27为例&#xff0c;安卓系统hd关闭的方法如下&#xff1a; 1、首先打开手机设置应用&#xff0c;然后在设置页面点击“移动网络”一项进入。 2、接着在“移动网络”页面可以…

华为手机这几个默认设置,一定要关闭,再也不卡顿

华为手机现在是越来越多人使用了&#xff0c;手机用久了自然就会出现卡顿不流畅、占内存&#xff0c;加快耗电的情况。这是因为你手机里自带默认设置开关没有关&#xff0c;关了这几个默认设置&#xff0c;之后手机瞬间流畅。下面我们一起来看看怎么操作吧。 首先&#xff0c;第…