GraphicsLab Project之辉光(Glare,Glow)效果 【转】
作者:i_dovelemon
日期:2016 / 07 / 02
来源:CSDN
主题:Render to Texture, Post process, Glare, Glow, Multi-pass rendering
引言
辉光(Glare,Glow)
原理
下面给大家讲述下这种效果的实现方式。其实说白了它的实现原理很简单,我们只要对要添加辉光效果的物体进行一次模糊操作,然后将模糊过后的图片与原先的图片进行Alpha
Blend,就能够得到上面所示的效果。操作如图所展示的那样(这里为了简便,只在场景中绘制Glare物体,并且只添加了些许光照,没有添加其他效果):
OpenGL实现
渲染到纹理(Render to Texture, RTT)
在图形学处理中,我们经常需要对渲染好的场景进行一些处理。也就是说,我们需要一种方式,能够让我们通过图形API(OpenGL,
DirectX)绘制的场景保存到我们指定的内存(显存)中去,以便于我们后期对他进行一些处理。而在OpenGL中,我们能够很容易的实现这一点。这种技术在我的博客中也有讲到。大家可以根据博客中的描述和代码对此进行了解。
后处理(Post-processing)
后处理在图形学中经常被用到。我们在游戏中绘制的场景,往往是没有办法仅仅依靠光照模型计算就能够实现出来的。很多的特殊效果,都是通过对渲染好的场景进行图像空间的后期出理来得到。比如本篇文章中实现的辉光效果,就使用了这种技术。还有很多其他在图像空间进行后处理的特效,感兴趣的同学可以阅读Real-time
Rendering中关于此技术的章节。
图像模糊(Blur)
高斯模糊在图像处理的时候,是使用2维的高斯分布函数对一个像素的上下左右包围的像素进行采样来实现的。我们假设模糊的半径为20个像素,按照高斯模糊的原始计算方式,每一个像素都需要计算(2
* 20) ^ 2次采样。这在图像处理上面可以接受,但是对于实时性的游戏来说,计算量就有点大了。
从图中,我们可以看到,我们先对原场景图进行一次横向的模糊计算,此次计算我们只需要采用一维的高斯分布进行计算即可。然后对横向模糊之后的图像进行纵向模糊,与横向模糊一样,使用一维的高斯分布函数进行。这样就能够得到一张高斯模糊之后的图像,它的模糊效果不比二维高斯模糊效果来的差。
OpenGL绘制流程
- void glb_display() {
- glb_draw_normal_scene();
- glb_draw_render_target_gauss_blur_h();
- glb_draw_render_target_gauss_blur_v();
- glb_draw_blend();
- glutSwapBuffers();
- }
上面的代码给出了我绘制的流程:
Shader计算
- light_pixel.vs
- //--------------------------------------------------------------------
- // Declaration: Copyright (c), by i_dovelemon, 2016. All right reserved.
- // Author: i_dovelemon[1322600812@qq.com]
- // Date: 2016 / 06 / 29
- // Brief: Phong lights's vertex shader
- //--------------------------------------------------------------------
- #version 330
- in vec3 vertex;
- in vec3 normal;
- uniform mat4 proj;
- uniform mat4 view;
- uniform mat4 world;
- uniform mat4 trans_inv_world;
- out vec3 vs_vertex;
- out vec3 vs_normal;
- void main() {
- gl_Position = proj * view * world * vec4(vertex, 1.0);
- vs_vertex = (world * vec4(vertex, 1.0)).xyz;
- vs_normal = (trans_inv_world * vec4(normal, 0.0)).xyz;
- }
- light_pixel.ps
- //--------------------------------------------------------------------
- // Declaration: Copyright (c), by i_dovelemon, 2016. All right reserved.
- // Author: i_dovelemon[1322600812@qq.com]
- // Date: 2016 / 06 / 29
- // Brief: Phong lights's pixel shader
- //-------------------------------------------------------------------
- #version 330
- in vec3 vs_vertex;
- in vec3 vs_normal;
- out vec4 color;
- uniform vec3 parallel_light_dir;
- uniform vec3 parallel_light_ambient;
- uniform vec3 parallel_light_diffuse;
- uniform vec3 parallel_light_specular;
- uniform vec3 material_ambient;
- uniform vec3 material_diffuse;
- uniform vec3 material_specular;
- uniform float material_specular_pow;
- uniform vec3 eye_pos;
- vec3 calc_diffuse(vec3 light_vec, vec3 normal, vec3 diffuse, vec3 light_color) {
- float ratio = dot(light_vec, normal);
- ratio = max(ratio, 0.0);
- return diffuse * light_color * ratio;
- }
- vec3 calc_specular(vec3 light_vec, vec3 normal, vec3 view_vec, vec3 specular, vec3 light_color, float pow_value) {
- vec3 ref_light_vec = reflect(light_vec, normal);
- float ratio = dot(ref_light_vec, view_vec);
- ratio = max(ratio, 0.0);
- ratio = pow(ratio, pow_value);
- return specular * light_color * ratio;
- }
- void main() {
- vec3 light_vec = -parallel_light_dir;
- vec3 normal = normalize(vs_normal);
- vec3 view_vec = normalize(eye_pos - vs_vertex);
- vec3 ambient = material_ambient * parallel_light_ambient;
- vec3 diffuse = calc_diffuse(light_vec, normal, material_diffuse, parallel_light_diffuse);
- vec3 specular = calc_specular(light_vec, normal, view_vec, material_specular, parallel_light_specular, material_specular_pow);
- color = vec4(ambient + diffuse + specular, 1.0);
- }
这两个Shader只是为了实现Phong式光照计算,给场景一点光亮,对于绘制辉光效果并不是必须的,但你总得有东西才能绘制辉光效果吧!
- gauss_blur.vs
- //--------------------------------------------------------------------
- // Declaration: Copyright (c), by i_dovelemon, 2016. All right reserved.
- // Author: i_dovelemon[1322600812@qq.com]
- // Date: 2016 / 06 / 29
- // Brief: Gauss blur pass through vertex shader
- //--------------------------------------------------------------------
- #version 330
- in vec3 vertex;
- in vec2 texcoord;
- out vec2 vs_texcoord;
- void main() {
- gl_Position = vec4(vertex, 1.0);
- vs_texcoord = texcoord;
- }
- gauss_blurh.ps
- //--------------------------------------------------------------------
- // Declaration: Copyright (c), by i_dovelemon, 2016. All right reserved.
- // Author: i_dovelemon[1322600812@qq.com]
- // Date: 2016 / 06 / 29
- // Brief: Gauss blur horizontal pass shader
- //--------------------------------------------------------------------
- #version 330
- in vec2 vs_texcoord;
- out vec4 color;
- uniform sampler2D tex;
- uniform float tex_width;
- uniform float gauss_num[21];
- void main() {
- color = texture2D(tex, vs_texcoord) * gauss_num[0];
- float step = 1.0 / tex_width;
- for (int i = 1; i < 21; i++) {
- if (vs_texcoord.x - i * step >= 0.0) {
- color += texture2D(tex, vec2(vs_texcoord.x - i * step, vs_texcoord.y)) * gauss_num[i];
- }
- if (vs_texcoord.x + i * step <= 1.0) {
- color += texture2D(tex, vec2(vs_texcoord.x + i * step, vs_texcoord.y)) * gauss_num[i];
- }
- }
- }
- gauss_blurv.ps
- //--------------------------------------------------------------------
- // Declaration: Copyright (c), by i_dovelemon, 2016. All right reserved.
- // Author: i_dovelemon[1322600812@qq.com]
- // Date: 2016 / 06 / 29
- // Brief: Gauss blur vertical pass shader
- //--------------------------------------------------------------------
- #version 330
- in vec2 vs_texcoord;
- out vec4 color;
- uniform sampler2D tex;
- uniform float tex_height;
- uniform float gauss_num[21];
- void main() {
- color = texture2D(tex, vs_texcoord) * gauss_num[0];
- float step = 1.0 / tex_height;
- for (int i = 0; i <21; i++) {
- if (vs_texcoord.y - i * step >= 0.0) {
- color += texture2D(tex, vec2(vs_texcoord.x, vs_texcoord.y - i * step)) * gauss_num[i];
- }
- if (vs_texcoord.y + i * step <= 1.0) {
- color += texture2D(tex, vec2(vs_texcoord.x, vs_texcoord.y + i * step)) * gauss_num[i];
- }
- }
- }
上面三个Shader组合完成了高斯模糊的计算。这里有几点需要注意。
(1)进行模糊计算的时候,逻辑上是以一个像素单位为步进值,但是由于纹理坐标是从[0,1],所以我们需要将一个像素的步进值计算为对应的纹理坐标步进。这个操作可以在Application阶段计算完成,然后传递到Shader中,这里博主偷懒了,直接在Shader里面计算了。
- float glb_gauss_num(int x) {
- float pi = 3.1415927f;
- float e = 2.71828f;
- float theta = 0.1f;
- float theta2 = theta * theta;
- float temp1 = 1.0f / (theta * sqrt(2 * pi));
- float temp2 = pow(e, -(x * x) / 2 * theta2);
- return temp1 * temp2;
- }
- void glb_calc_gauss_nums() {
- g_GaussNum[0] = 1.0f;
- for (int32_t i = 1; i < sizeof(g_GaussNum) / sizeof(g_GaussNum[0]); i++) {
- g_GaussNum[i] = glb_gauss_num(i);
- }
- float total = 0.0f;
- for (int32_t i = 0; i < sizeof(g_GaussNum) / sizeof(g_GaussNum[0]); i++) {
- total += g_GaussNum[i];
- }
- for (int32_t i = 0; i < sizeof(g_GaussNum) / sizeof(g_GaussNum[0]); i++) {
- g_GaussNum[i] = g_GaussNum[i] / total;
- }
- }
对于步骤(4),使用了如下的两个Shader:
- blend.vs
- //--------------------------------------------------------------------
- // Declaration: Copyright (c), by i_dovelemon, 2016. All right reserved.
- // Author: i_dovelemon[1322600812@qq.com]
- // Date: 2016 / 06 / 29
- // Brief: Blend pass through vertex shader
- //--------------------------------------------------------------------
- #version 330
- in vec3 vertex;
- in vec2 texcoord;
- out vec2 vs_texcoord;
- void main() {
- gl_Position = vec4(vertex, 1.0);
- vs_texcoord = texcoord;
- }
- blend.ps
- //--------------------------------------------------------------------
- // Declaration: Copyright (c), by i_dovelemon, 2016. All right reserved.
- // Author: i_dovelemon[1322600812@qq.com]
- // Date: 2016 / 06 / 29
- // Brief: Alpha blend shader
- //--------------------------------------------------------------------
- #version 330
- in vec2 vs_texcoord;
- out vec4 color;
- uniform sampler2D blur_tex;
- uniform sampler2D scene_tex;
- void main() {
- vec4 blur_color = texture2D(blur_tex, vs_texcoord);
- vec4 scene_color = texture2D(scene_tex, vs_texcoord);
- color = blur_color * 0.5 + scene_color * 0.5;
- }
最后的混合计算,我选取了模糊贴图的一半加上场景贴图的一半来进行混合操作。最终的效果如下图所示:
总结
上面文章为了简化操作,做了很多在实际项目中不可以的操作。比如在Shader中计算纹理步进值。而在实际的情况下,实现辉光效果远远要比这里展示的复杂的多,比如场景中有不发光的物体,和发光的物体,此时需要通过Alpha贴图来标识出场景图中哪些是需要进行模糊的,而哪些是不需要进行。又比如说,发光物体在某个不发光物体的后面,那么进行模糊计算的时候,必然会让发光物体渗透到不发光物体中,会产生比较粗糙的感觉。
参考文献
GraphicsLab Project之辉光(Glare,Glow)效果 【转】的更多相关文章
- GraphicsLab Project学习项目
作者:i_dovelemon 日期:2016 / 05 / 30 主题:3D,Graphics 引言 进公司以来,主要在学习的就是如何保证代码的质量,以前热爱的图形学也放置了.但是,作为游戏程序员,特 ...
- 支持辉光效果的Label
支持辉光效果的Label 效果 源码 https://github.com/YouXianMing/UI-Component-Collection 中的 FBGlowLabel // // FBGlo ...
- Shimmer辉光动画效果
Shimmer辉光动画效果 效果 源码 https://github.com/facebook/Shimmer https://github.com/YouXianMing/Animations // ...
- 使用CALayer制作View的辉光效果
使用CALayer制作View的辉光效果 实现以下的辉光效果: 思路是这样子的: 1. 创建好需要实现辉光效果的View 2. 对这个View进行截图 3. 将这个截图重新添加进View中 4. 对这 ...
- GLSL实现Glow效果 [转]
http://blog.csdn.net/a3070173/archive/2008/11/04/3220940.aspx Glow即辉光效果现在已成为3D图形中一个引人注目的特效.本文主要介绍如何使 ...
- 辉光UIView的category
辉光UIView的category 本人视频教程系类 iOS中CALayer的使用 效果如下: 源码: UIView+GlowView.h 与 UIView+GlowView.m // // UI ...
- 辉光的UIView
辉光的UIView 辉光UIView使用了一个UIView的一个category,名为UIView+Glow,请自行到github上查找. 源码如下: // // RootViewController ...
- GLSL实现Glow效果 【转】
http://blog.csdn.net/a3070173/article/details/3220940 Glow即辉光效果现在已成为3D图形中一个引人注目的特效.本文主要介绍如何使用GLSL实现一 ...
- GraphicsLab Project之Diffuse Irradiance Environment Map
作者:i_dovelemon 日期:2020-01-04 主题:Rendering Equation,Irradiance Environment Map,Spherical Harmonic 引言 ...
随机推荐
- IPsec传输模式下ESP报文的装包和拆包过程
原创文章,拒绝转载 装包过程 总体流程图 过程描述 在原IP报文中找到TCP报文部分,在其后添加相应的ESP trailer信息. ESP trailer 包含三部分:Padding,Pad leng ...
- HashMap/Hashtable/ConcurrentHashMap区别
HashMap:每个隔间都没锁门,有人想上厕所,管理员指给他一个隔间,里面没人的话正常用,里面有人的话把这个人赶出来然后用. 优点,每个人进来不耽误都能用:缺点,每一个上厕所的人都有被中途赶出来的危险 ...
- python的加密算法(1):反转加密
说白了,就是把字符串倒序. 在js里,有一个reverse.但是python中没有. 不过,有一个更简单的方法,就是: ‘abcd’ [::-1] 这里,具体解释一下: (参看:https://doc ...
- 记录一次统计首页MYSQL非常慢的解决过程
select resource_size_int from t_resource_info where release_status in (1,3) and res_type in (1,2,4,5 ...
- Python3中的新特性(2)——常见陷阱
1.文本与字节 Python3对文本字符串(字符)和二进制数据(字节)进行了严格区分,'hello'表示一个以Unicode编码保存的文本字符串,而b'hello'表示一个字节字符串. 在Python ...
- 【互动问答分享】第11期决胜云计算大数据时代Spark亚太研究院公益大讲堂
Q1:docker成熟度如何? Docker是2013年和2014年最火爆的云计算开源项目: Baidu公司是中国使用Docker最为深入和最大规模的公司,线上稳定运行数十万个Docker容器,目前已 ...
- selenium 难定位元素,时间插件,下拉框定位,string包含,定位列表中的一个,技巧
关于frame: 如果网页存在iframe的话,传统的定位有时候找不到元素,需要切换frame: # 切换到leftFrame定位“测井设计” driver.switch_to_frame(" ...
- centos6.5 phpmyadmin 您应升级到 MySQL 5.5.0 或更高版本
看到自己当初写的,并没有直接的解决问题,而是退而求其次,安装低版本的mysql5.1,然后安装对应版本的phpmyadmin 4.0.10.5 UnicodeDecodeError: 'ascii' ...
- HDU 6326.Problem H. Monster Hunter-贪心(优先队列)+流水线排序+路径压缩、节点合并(并查集) (2018 Multi-University Training Contest 3 1008)
6326.Problem H. Monster Hunter 题意就是打怪兽,给定一棵 n 个点的树,除 1 外每个点有一只怪兽,打败它需要先消耗 ai点 HP,再恢复 bi点 HP.求从 1 号点出 ...
- openssl生成证书链多级证书
操作系统CentOS6.6 注:windows版本的Openssl无法做这个实验,由于所有编译的window版本openssl没有对openssl目录重新定向,导致在windows下找不到pki目录 ...