[GLSL]着色器周记02

这周学了好多。包括伪随机数。柏林噪声。
先说伪随机数。伪随机数我们用的是周期函数而不是那种由前一项乘一个超大的数取余数的方法。使用周期函数的好处就是可以让其随时间均匀变化。不过使用周期函数一定要保证周期非常长,不然就会出现重复的图样。
这是我在网上找到的一个伪随机函数:
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年前的特效。虽然不知道是不是真的是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);

}

时间: 2024-10-15 14:38:42

[GLSL]着色器周记02的相关文章

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

http://www.cnblogs.com/tkgamegroup/p/4214081.html 这周学了好多.包括伪随机数.柏林噪声.先说伪随机数.伪随机数我们用的是周期函数而不是那种由前一项乘一个超大的数取余数的方法.使用周期函数的好处就是可以让其随时间均匀变化.不过使用周期函数一定要保证周期非常长,不然就会出现重复的图样.这是我在网上找到的一个伪随机函数:cos(x * (12.9898) + y * (4.1414)) * 43758.5453它使用x, y作为参数,刚好对应像素的坐标

[GLSL]着色器周记01!

我决定开个新坑了.以后每周五更新.这是GLSL的学习周记!GLSL就是OPENGL SHADER LANGUAGE的简称,就是着色器语言.着色器是一种交给显卡运行的小程序,这种小程序可以用GLSL来写,写好后交给OPENGL编译,就可以在显卡上运行了. 那么问题来了!为什么要给显卡运行呢?显卡是一种特殊的处理器,有核心,有寄存器,还有内存,不过对比CPU,最大的特点就是显卡的核心更多.多多少呢?一般CPU有4-8个核心,而显卡则是100个左右的核心!不过由于造价还有空间的限制,显卡的某些功能会被

[GLSL]着色器周记03

懒惰的一周~http://www.cnblogs.com/easymind223/archive/2012/07/05/2578231.htmlhttp://glslsandbox.com/e#21606.0↑根据它们的指导做出来的Mandelbrot集~ #version 440 #define r 300.0 uniform int _t; vec2 center = vec2(1366.0 / 2.0, 768.0 / 2.0); void main() { vec2 c = vec2((

第4章:缓冲区、着色器、GLSL

原文链接: http://www.rastertek.com/gl40tut04.html Tutorial 4: Buffers, Shaders, and GLSL This tutorial will be the introduction to writing vertex and pixel shaders in OpenGL 4.0. It will also be the introduction to using vertex and index buffers in OpenG

OpenGLES2.0着色器语言glsl

OpenGLES2.0中是强制使用可编程的渲染管线的,使用的是glsl着色器语言,因为着色器语言是使用的GPU,即图形处理单元,而不是CPU,这样可以使CPU从繁重的几何计算和像素的处理中解脱出来了.这就加大了处理的速度. 下面的这篇教程是转载的.原文地址如下,感谢作者manyou http://www.apkbus.com/blog-99192-39382.html 一.着色语言基础 数据类型概述 1. 标量 标量也被称为"无向量"其值只有大小,并不具有方向.标量之间的运算遵循简单的

OpenGL中使用着色器

OpenGL中使用GLSL着色器步骤 GLSL既适用于顶点着色器,也适用于片段着色器. 使用着色器对象的步骤: 1.创建着色器对象: GLuint glCreateShader(GLenum type); //创建一个着色器对象,type值必须是GL_VERTEX_SHADER或GL_FRAGMENT_SHADER.error返回0 2.把着色器的源码与着色器对象相关联: glShaderSource(GLuint shader, GLsizei count, const GLChar** st

OpenGL学习笔记5:着色器

初识着色器语言 变量和数据类型 可用的数据类型只有4种:有符号整数,无符号整数,浮点数,布尔值. OpenGL着色语言中没有指针和字符串或字符.返回值可以为void. 向量类型 所有4种基本数据类型都可以存储在二维.三维或者四维向量中: OpenGL着色语言向量数据类型 类型 描述 vec2,vec3,vec4 2分量.3分量和4分量浮点向量 ivec2,ivec3,ivec4 2分量.3分量和4分量整数向量 uvec2,uvec3,uvec4 2分量.3分量和4分量无符号整数向量 bvec2,

WebGL 着色器语言(GLSL ES)

1.类型转换内置函数 转换/函数/描述 转换为整形数/int(float)/将浮点数的小数部分删去,转换为整形数(比如,将3.14转换为3) 转换为整形数/intl(bool)/true被转换为1,false被转换为0 转换为浮点数/float(int)/将整形数转换为浮点数(比如,将8转换为8.0) 转换为浮点数/float(bool)/true被转换为1.0,false被转换为0.0 转换为布尔值/bool(int)/0被转换为false,其他非0倍转换为true 转换为布尔值/0.0被转换

OpenGL学习日记-2015.3.5——Hello glsl(着色器)

过年前忍不住买了本新版的OpenGL编程指南,主要的目的还是为了系统的学习着色器编程,另外就是接触新版的OpenGL技术和思想.看了几页,就过年了QAQ.回来后也是各种不在状态,不想上班,不想工作,不想写代码...昨天终于强迫自己继续看书,也找回了些状态. 书本基础知识的全面性和权威性就不用说了,不过这个源代码就....这第一个例子照着代码来抄结果...我想应该是原来的代码一个参数错了,折腾了半天,代码分析是详说.主要是分析代码,有什么说什么,并没有全面的说明着色器的基本内容,想着在着色器的基础