[GLSL]着色器周记02——火焰特效 【转】

时间:2022-09-30 11:19:06

http://www.cnblogs.com/tkgamegroup/p/4214081.html

这周学了好多。包括伪随机数。柏林噪声。
先说伪随机数。伪随机数我们用的是周期函数而不是那种由前一项乘一个超大的数取余数的方法。使用周期函数的好处就是可以让其随时间均匀变化。不过使用周期函数一定要保证周期非常长,不然就会出现重复的图样。
这是我在网上找到的一个伪随机函数:
cos(x * (12.9898) + y * (4.1414)) * 43758.5453
它使用x, y作为参数,刚好对应像素的坐标。(PS:发现好多GLSL的例子都用类似的随机函数,应该里面蕴含了什么数学吧。) 
这个函数的周期应该挺长的, 会发现在cos的后面还乘上了一个超大的数,这样可以达到不错的伪随机效果,不过还需要很重要的一步。
最终的随机函数是这样的:
fract(cos(x * (12.9898) + y * (4.1414)) * 43758.5453)
fract这个glsl预定义的函数的作用是返回小数部分,会达到非常不错的效果。
 
↑这是没有加上fract的结果,因为所有大于1的值都变成1了。(GL中像素的颜色值范围是0.0-1.0) 
 
↑这是加上fract的效果,看起来还不错是吧。
PS:
在想随机数的时候,我想人工智能是不是其实是可以实现的呢。因为智能可能就是对一个个小事件的反应,当这些对各种事情的反应多起来的时候,数量趋近于无穷,或者达到一个阀值,就会表现出智能。因为人类的大脑说不定也是这样,是不是也是对一个个小事件的反应呢,我想是的,大脑里面这种反应非常多,多到了一个阀值,所以才会变现出“智能”,而*意志应该就是量子随机性造成的,而至于为什么不觉得这种随机不想是“随机”的呢,而想是可控的呢?因为这些随机性的东西都会经过一个个在大脑中设定好的程序,被这样处理过的信息之后,看起来就变得“有序”了。(稍后你会看到上面这些这样随机的图样,最终会变成一幅不错的图画)所以,人工智能终有一天是会实现的,只要不断地设定对各种事件的反应,让它看起来“好像是智能的样子呢”,当这种“好像是智能的样子呢”多起来的时候,达到了一个阀值,那么这个东西就是真正的智能了,这里可没有双引号。这里也稍微的用一下数学里面的极限思想了呢,0.999...这样无穷下去,数学上的结果就是1。不过目前想要达到这个阀值,需要的是非常高性能的计算机还有聪明的程序员,至少前者还不能实现,在未来20年之后,估计就能实现看起来非常智能的人工智能了。
哎呀,扯多了。

接下来是一个火焰特效,看起來像20年前的技術,哈哈。由浅入深嘛。慢慢地就会学到现代的技术了。

看起来还阔以吧。

不知道gif能不能播放,不过gif画质太渣了,还是不用gif了。你就想想这个火焰是会动的就行啦。

接下来是柏林噪声(Perlin噪声)了,Ken Perlin在1981年为电影创造了这种噪声,它可以模拟自然的云、火焰、水面等,为电影特效做出了功不可没的贡献,为此,他获得了“奥斯卡技术成就奖”。

Perlin噪声就是n个函数的叠加,这n个函数满足,下一个的频率是前一个的两倍,幅度是二分之一。而函数嘛,当然是选择我们上面的伪随机函数啦。

不过首先,我们要对屏幕的像素分组。我的分组是250*250个一组。 也就是这250*250个像素共享同一个随机的值。然后,对于每个小组,每个小组里面的像素,进行一次插值,(可以是线性插值(假如在A,,B两点间插值,t(0<=t<=1)是距离A的距离比例,那么t位置的值是(1
- t) * A + t * B,(1 - t)是插值函数),不过效果差,Perlin本人推荐 3 * t * t - 2 * t * t *
t,后来推荐..哎呦
这个好长,就不写出来了)二维的插值是这样的,首先取本小组的值和右边小组的值在x方向插值得到a,然后是下面小组的值和右下小组的值在x方向插值得到b,最后就是a和b在y方向插值得到最终结果。
glsl里面有预定义插值函数,线性的mix和平滑的smoothstep。

所以,代码看起来是这样的:

#define r 250
float noise(float x, float y)
{
int base_x = int(floor(x / r)); // 小组的x编号
int base_y = int(floor(y / r)); // 小组的y编号
x = fract(x / r); // 像素在小组内x方向的权值
y = fract(y / r); // 像素在小组内y方向的权值
float f_x = smoothstep(0, 1, x); // 平滑后的值
float f_y = smoothstep(0, 1, y); // 平滑后的值
return
mix(
mix(rand(float(base_x), float(base_y)), rand(float(base_x + 1), float(base_y)), f_x) // 第一次的x方向插值
,
mix(rand(float(base_x), float(base_y + 1)), rand(float(base_x + 1), float(base_y + 1)), f_x) // 第二次的x方向插值
,
f_y) // 最后的y方向插值
;

}

看起来是这样的:

哇..看起来好爽。

接下来就是Perlin噪声了, 请看代码:

float fbm(float x, float y)
 {
float total = 0.0, amplitude = 1.0;
for (int i = 0; i < 4; i++) // 4个函数叠加
{
total += noise(x, y) * amplitude; 
x += x;  // 频率乘以2
y += y;  // 频率乘以2
amplitude *= 0.5; // 幅度乘以二分之一
}
return total;

}

效果是这样的:

我已经看到了一点云的样子了呢。

接下来,加点颜色,你可以*发挥,这里只是一个例子:

t = float(_t);
float z = fbm(gl_FragCoord.x - t * 100, gl_FragCoord.y - t * 100);
float x = fbm(gl_FragCoord.x + t * 60, gl_FragCoord.y - t * 40);
float c = fbm(gl_FragCoord.x - t * 70, gl_FragCoord.y - t * 80);
vec3 color1 = vec3(1.0, 0.9, 0.0);
vec3 color2 = vec3(1.0, 0.0, 0.0);
vec3 color3 = vec3(0.0, 0.0, 0.0);
vec3 color4 = vec3(0.2, 0.2, 0.2);
vec3 color5 = vec3(0.0, 0.0, 0.6);
vec3 color6 = vec3(0.0, 0.6, 0.0);

gl_FragColor = vec4(mix(color2, color1, z) + mix(color3, color4, x) - mix(color5, color6, c), 1.0); 
就可以达到火焰特效了,要更加逼真的效果就需要不断的尝试颜色的组合,或者加入数学知识。

对了,漏了最重要的一点,就是怎么向着色器里面传一个值。

用到的是uniform技术。

在glsl代码中,你只要这样:

uniform int _t;
 
就可以声明一个_t的uniform变量。uniform在一次渲染中值不会改变,所有着色器都可以访问这个值。程序也可以在每一帧时任意修改uniform的值。用这样的语句:

 
GLint location;
location = glGetUniformLocation(program, "_t");

glUniform1i(location, _t);

**以上参考:http://www.tuicool.com/articles/VFnAFbB。火焰特效是借鉴http://glslsandbox.com/里面的一个特效,不过原文的地址我忘了T T。

好了。周记完毕,在最后送一个小特效:

void main() 
{
vec3 color = vec3(0.0, 0.0, 0.0);
float angle = t * t * 0.1;
vec2 q;
q.x = p.x + cos(angle * 3.14 / 180) * 10;
q.y = p.y + sin(angle * 3.14 / 180) * 10;
float A = q.y - p.y;
float B = p.x - q.x;
float C = q.x * p.y - p.x * q.y;
float rate;
rate = A * gl_FragCoord.x + B * gl_FragCoord.y + C;
rate = rate * rate;
rate = rate / (A * A + B * B);
rate = 100 / rate;
color.x = rate * 0.0;
color.y += rate * 0.0;
color.z += rate * 0.8;
float x, y;
x = gl_FragCoord.x - 1366.0 / 2;
y = gl_FragCoord.y - 768.0 / 2;
rate = x * x + y * y;
rate = sqrt(rate);
int temp = _t % 20;
rate -= (temp * temp);
if(rate < 0)
rate = -rate;
rate *= rate;
rate = 100 / rate;
color.x = rate * 0.8;
color.y += rate * 0.0;
color.z += rate * 0.0;
gl_FragColor = vec4(color, 1.0);

}

[GLSL]着色器周记02——火焰特效 【转】的更多相关文章

  1. GLSL着色器,来玩

    对实现动画的前端同学们来说,canvas可以说是最*,最能全面控制的一个动画实现载体.不但能通过javascript控制点.线.面的绘制,使用图片资源填充:还能改变输入参数作出交互动画,完全控制动画 ...

  2. GLSL 着色器程序

    除了使用Cg/HSL 着色器程序以外, OpenGL 着色器语言(GLSL)着色器可以直接书写shader. 然而,使用原生的GLSL只推荐作为测试使用,或者你清晰的知道你的目标平台是 Mac OS ...

  3. OpenGLES2&period;0着色器语言glsl

    OpenGLES2.0中是强制使用可编程的渲染管线的,使用的是glsl着色器语言,因为着色器语言是使用的GPU,即图形处理单元,而不是CPU,这样可以使CPU从繁重的几何计算和像素的处理中解脱出来了. ...

  4. 【OPENGL】第三篇 着色器基础(二)

    在这一小节,主要学习GLSL的基本数据类型以及控制结构.GLSL具备了C++和Java的很多特性,我们会先了解所有着色阶段共有的特性,再了解各个着色器的专属特性. 1.着色器的基本结构 一个着色器程序 ...

  5. DirectX11 With Windows SDK--02 顶点&sol;像素着色器的创建、顶点缓冲区

    前言 由于在Direct3D 11中取消了固定管线,要想绘制图形必须要了解可编程渲染管线的流程,一个能绘制出图形的渲染管线最少需要有这两个可编程着色器:顶点着色器和像素着色器. 本章会直接跳过渲染管线 ...

  6. OpenGL学习脚印&colon; uniform blocks在着色器中的使用 转自https&colon;&sol;&sol;blog&period;csdn&period;net&sol;wangdingqiaoit&sol;article&sol;details&sol;52717963

    写在前面 目前,我们在着色器中要传递多个uniform变量时,总是使用多个uniform,然后在主程序中设置这些变量的值:同时如果要在多个shader之间共享变量,例如投影矩阵projection和视 ...

  7. OpenGL学习笔记(三)着色器

    目录 Shader是什么 GLSL 数据类型 输入与输出 顶点着色器向片段着色器发送数据 Uniform 制作三色渐变三角形 对着色器程序进行封装 参考资料:OpenGL中文翻译 Shader是什么 ...

  8. 对osg节点添加glsl特效(片断着色器FragmentShader)

    读取一个模型到节点node,然后想对node施加一些特效,这时可以只使用片段着色器 其中: gl_Color表示固定管线计算出来的颜色,包含光照效果 gl_TexCoord[]表示纹理坐标 unifo ...

  9. &lbrack;OpenGL ES 02&rsqb;OpenGL ES渲染管线与着色器

    [OpenGL ES 02]OpenGL ES渲染管线与着色器 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循"署名-非商业用途-保持一致"创 ...

随机推荐

  1. SQL 将2张不相关的表拼接成2列,批量更新至另一张表

    update SO_Master set LotteryNo=t2.LotteryNo,UpdateTime=GETDATE() --select sm.LotteryNo,sm.SysNo,t2.L ...

  2. &lpar;分享&rpar;Paxos在大型系统中常见的应用场景

    原帖http://timyang.net/distributed/paxos-scenarios/ 在分布式算法领域,有个非常重要的算法叫Paxos, 它的重要性有多高呢,Google的Chubby ...

  3. SQL Server 2008 存储过程,带事务的存储过程&lpar;创建存储过程,删除存储过程,修改存储过

    SQL Server 2008 存储过程,带事务的存储过程(创建存储过程,删除存储过程,修改存储过     存储过程 创建存储过程 use pubs --pubs为数据库 go create proc ...

  4. C&plus;&plus;11 之 scoped enum

      C++11 枚举类型是“域化的” (scoped enum),相比 C++98 枚举类型的“非域化” (unscoped enum),具有如下优点: 1  命名空间污染  一般来说,声明在花括号内 ...

  5. 示例说明Oracle RMAN两种库增量备份的差别

    1差异增量实验示例 1.1差异增量备份 为了演示增量备份的效果,我们在执行一次0级别的备份后,对数据库进行一些改变. 再执行一次1级别的差异增量备份: 执行完1级别的备份后再次对数据库进行更改: 再执 ...

  6. 监听器和普通类获取springContext和context,从而获取springbean和application范围的对象

    1.定义一个监听器[MyContextListener],此类里最主要获取springContext和context package my.request; import javax.servlet. ...

  7. js 获取选中的多选框

    前台html <span class="spbox"> <input type="checkbox" name="category& ...

  8. 转&Tab;git使用命令&comma; 特别&colon;git checkout -b a 与 git branch a区别

    创建分支: $ git branch mybranch 切换分支: $ git checkout mybranch 创建并切换分支: $ git checkout -b mybranch 更新mast ...

  9. Js弹出层,弹出框代码

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. WebKit框架 浅析

    摘要 WebKit是iOS8之后引入的专门负责处理网页视图的框架,其比UIWebView更加强大,性能也更优. iOS中WebKit框架应用与解析 一.引言 在iOS8之前,在应用中嵌入网页通常需要使 ...