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 引言 ...
随机推荐
- 关于集合的size的操作
1.创建集合: 创建指定大小的集合:(大小为5) db.createCollection(}) 2.插入五条数据: > db.colle1.insert({name:}) WriteResult ...
- 转:布局【ViewGroup】
转: http://www.cnblogs.com/leehyuan/p/3389527.html 像素单位的变化:是用dip,而不是px,主要用于宽高的设置 在Android中支持的描述大小区域的类 ...
- [转载]Go的50度灰:Golang新开发者要注意的陷阱和常见错误
初级 开大括号不能放在单独的一行 未使用的变量 未使用的Imports 简式的变量声明仅可以在函数内部使用 使用简式声明重复声明变量 偶然的变量隐藏Accidental Variable Shadow ...
- 【反演复习计划】【bzoj3994】约数个数和
首先要用数学归纳证明一个结论,不过因为我实在是懒得打公式了... 先发代码吧. #include<bits/stdc++.h> #define N 50005 using namespac ...
- html怎样让表格里面的内容居中
html怎样让表格里面的内容居中 text-align:center; 在表格td中,有两个属性控制居中显示 align——表示左右居中——left,center,right valign——控制上下 ...
- EasyUI的tree展开所有的节点或者根据特殊的条件控制展示指定的节点
展示tree下的所有节点$(function(){ $('#t_funinfo_tree').tree({ checkbox: true, url:"<%=basePath %> ...
- 【 Zabbix 】 — 基础安装
一.基础环境 (1)centos6.7 x64 (2)JDK1.8 and zabbix-2.4.8(JDK是为了后期可以监控tomcat) (3)虚拟机测试环境 二.安装LAMP环境 这里为了快速搭 ...
- DRF的过滤与排序
过滤 对于列表数据可能需要根据字段进行过滤,我们可以通过添加 django-filter 扩展来增强支持. pip install django-filter 在配置文件中增加过滤后端的设置: INS ...
- python中的闭包与装饰器
#原创,转载请留言联系 装饰器的本质就是闭包,所以想知道装饰器是什么,首先要理解一下什么是闭包. 闭包 1. 外部函数返回内部函数的引用.2. 内部函数使用外部函数的变量或者参数. def outer ...
- selenium 常用浏览器操作API
package test; import org.openqa.selenium.By;import org.openqa.selenium.Dimension;import org.openqa.s ...