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 引言 ...
随机推荐
- linux下面which whereis find locate的使用
我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索.这些是从网上找到的资料,因为有时很长时间不会用到,当要用的时候经常弄混了,所以放到这里方便使用. which ...
- python自带的线程池和进程池
#python自带的线程池 from multiprocessing.pool import ThreadPool #注意ThreadPool不在threading模块下 from multiproc ...
- 解决小米/红米手机无法进行jdwp调试的问题
问题描述:在逆向一个app,研究环境是一台红米2,需要使用jdwp接口,也就是ddms下面这个界面: 但神奇的是,同一台主机上,模拟器的进程可以显示在ddms界面上,红米2确一个进程都没有显示出来.c ...
- linux内核同步之信号量、顺序锁、RCU、完成量、关闭中断【转】
转自:http://blog.csdn.net/goodluckwhh/article/details/9006065 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 一信 ...
- 创建第一个maven项目的那些坑
1.记事本方式: class所在的目录结构: class的代码书写: package com.imooc.maven01.mode1; public class HelloWorld { public ...
- TCP三次握手四次分手
TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标 ...
- Oracle基础 09 概要文件 profile
--创建 profile 概要文件create profile profile123 limit failed_login_attempts 2; --修改用户的 profile 文件alter u ...
- [ 总结 ] nginx 负载均衡 及 缓存
操作系统:centos6.4 x64 前端使用nginx做反向代理,后端服务器为:apache + php + mysql 1. nginx负载均衡. nginx编译安装(编译安装前面的文章已经写过) ...
- *****git pull总结
当git clone之后,直接git pull它会自动匹配一个正确的remote url 是因为在config文件中配置了以下内容: 1 [branch "master"] 2 r ...
- UTC时间
世界的每个地区都有自己的本地时间,在Internet及无线电通信时,时间的统一非常重要! 整个地球分为二十四时区,每个时区都有自己的本地时间.在国际无线电通信中,为统一而普遍使用一个标准时间,称为通用 ...