在线咨询 400-826-1668
回到顶部
ARTICLE DETAIL

资讯详情

深耕国风建站与运营引流的一线实战洞察。

LearnOpenGL之Shader编程——生成设计

LearnOpenGL之Shader编程——生成设计 ———————————————————— 前序 ———————————————————AndroidLearnOpenGL是本博主自己实现的LearnOpenGL练习集合Github地址GitHub - wangyongyao1989/AndroidLearnOpenGL: OpenGL基础及运用系列文章1、LearnOpenGL之入门基础2、LearnOpenGL之3D显示3、LearnOpenGL之摄像机4、LearnOpenGL之光照5、LearnOpenGL之3D模型加载6、LearnOpenGL之文字渲染7、LearnOpenGL之高级OpenGL18、LearnOpenGL之高级OpenGL29、LearnOpenGL之骨骼动画10、LearnOpenGL之Shader编程用算法绘画11、LearnOpenGL之Shader编程——生成设计———————————————————————————————————————————————————————————— 效果展示 ————————————————————一、随机随机性是熵的最大表现。我们如何在看似可预测而且严苛的代码环境中生成随机性呢sin函数其波形的分数部分。值域为-1.0到1.0之间的sin() 函数被取了小数点后的部分(这里实际是指模1))返回0.0到1.0间的正值。我们可以用这种效果通过把正弦函数打散成小片段来得到一些伪随机数。如何实现呢通过在sin(x)的值上乘以大些的数。控制混沌使用随机会很难它不是太混沌难测就是有时又不够混乱。谨记我们用的rand()是确定性随机也被称作是伪随机。这就意味着 就rand(1.)为例总会返回相同的值。2D随机现在我们对随机有了深入的理解是时候将它应用到二维x轴和y轴。为此我们需要将一个二维向量转化为一维浮点数。这里有几种不同的方法来实现但 dot() 函数在这个例子中尤其有用。它根据两个向量的方向返回一个0.0到1.0之间的值。用 dot() 函数在这个例子中尤其有用。它根据两个向量的方向返回一个0.0到1.0之间的值。#version 320 es precision mediump float; out vec4 FragColor;//out代表输出至下一个着色器 uniform vec2 u_resolution;//视窗的分辨率 uniform float u_time;//传入的时间变量 float random (vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898, 78.233)))*43758.5453123); } void main() { vec2 st gl_FragCoord.xy / u_resolution; vec3 color vec3(0.0f); float rnd random(st); color vec3(rnd); FragColor vec4(color, 1.0f); }使用混沌第一步是在网格上的应用用 floor() 函数我们将会产生一个单元整数列表。#version 320 es precision mediump float; out vec4 FragColor;//out代表输出至下一个着色器 uniform vec2 u_resolution;//视窗的分辨率 uniform float u_time;//传入的时间变量 float random (vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898, 78.233)))*43758.5453123); } void main() { vec2 st gl_FragCoord.xy / u_resolution; st * 10.0;// Scale the coordinate system by 10 vec2 ipos floor(st);// get the integer coords vec2 fpos fract(st);// get the fractional coords // Assign a random value based on the integer coord vec3 color vec3(random(ipos)); FragColor vec4(color, 1.0f); }迷宫生成器的GLSL代码块#version 320 es precision mediump float; #define PI 3.14159265358979323846; out vec4 FragColor;//out代表输出至下一个着色器 uniform vec2 u_resolution;//视窗的分辨率 uniform float u_time;//传入的时间变量 float random (in vec2 _st) { return fract(sin(dot(_st.xy, vec2(12.9898, 78.233)))*43758.5453123); } vec2 truchetPattern(in vec2 _st, in float _index){ _index fract(((_index-0.5)*2.0)); if (_index 0.75) { _st vec2(1.0) - _st; } else if (_index 0.5) { _st vec2(1.0-_st.x, _st.y); } else if (_index 0.25) { _st 1.0-vec2(1.0-_st.x, _st.y); } return _st; } void main() { vec2 st gl_FragCoord.xy / u_resolution; st * 10.0; st (st-vec2(5.0))*(abs(sin(u_time*0.2))*5.); // st.x u_time*3.0; vec2 ipos floor(st); // integer vec2 fpos fract(st); // fraction vec2 tile truchetPattern(fpos, random( ipos )); float color 0.0; // Maze color smoothstep(tile.x-0.3,tile.x,tile.y)- smoothstep(tile.x,tile.x0.3,tile.y); // Circles color (step(length(tile),0.6) - step(length(tile),0.4) ) (step(length(tile-vec2(1.)),0.6) - step(length(tile-vec2(1.)),0.4) ); // Truchet (2 triangles) // color step(tile.x,tile.y); FragColor vec4(vec3(color), 1.0f); }二、噪音Noise:Perlin noise 算法理解如何生成 noise 的好的出发点。float i floor(x); // 整数i 代表 integer float f fract(x); // 小数f 代表 fraction y rand(i); y mix(rand(i), rand(i 1.0), f); y mix(rand(i), rand(i 1.0), smoothstep(0.,1.,f));2D Noise#version 320 es precision mediump float; out vec4 FragColor;//out代表输出至下一个着色器 uniform vec2 u_resolution;//视窗的分辨率 uniform float u_time;//传入的时间变量 // 2D Random float random (in vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123); } // 2D Noise based on Morgan McGuire morgan3d // https://www.shadertoy.com/view/4dS3Wd float noise (in vec2 st) { vec2 i floor(st); vec2 f fract(st); // Four corners in 2D of a tile float a random(i); float b random(i vec2(1.0, 0.0)); float c random(i vec2(0.0, 1.0)); float d random(i vec2(1.0, 1.0)); // Smooth Interpolation // Cubic Hermine Curve. Same as SmoothStep() vec2 u f*f*(3.0-2.0*f); // u smoothstep(0.,1.,f); // Mix 4 coorners percentages return mix(a, b, u.x) (c - a)* u.y * (1.0 - u.x) (d - b) * u.x * u.y; } void main() { vec2 st gl_FragCoord.xy / u_resolution; // Scale the coordinate system to see // some noise in action vec2 pos vec2(st*20.0); // Use the noise function float n noise(pos); FragColor vec4(vec3(n), 1.0f); }Noise 算法的设计初衷是将难以言说的自然质感转化成数字图像。在目前我们看到的一维和二维的实践中都是在randomvalues随机值之间插值所以它们才被叫做Value Noise但是还有很多很多获取 noise 的方法value noise 看起来非常“块状”。为了消除这种块状的效果在 1985 年 Ken Perlin 开发了另一种 noise 算法Gradient Noise。Ken 解决了如何插入随机的gradients梯度、渐变而不是一个固定值。这些梯度值来自于一个二维的随机函数返回一个方向vec2格式的向量而不仅是一个值float格式。#version 320 es precision mediump float; out vec4 FragColor;//out代表输出至下一个着色器 uniform vec2 u_resolution;//视窗的分辨率 uniform float u_time;//传入的时间变量 vec2 random2(vec2 st){ st vec2(dot(st, vec2(127.1, 311.7)), dot(st, vec2(269.5, 183.3))); return -1.0 2.0*fract(sin(st)*43758.5453123); } // Gradient Noise by Inigo Quilez - iq/2013 // https://www.shadertoy.com/view/XdXGW8 float noise(vec2 st) { vec2 i floor(st); vec2 f fract(st); vec2 u f*f*(3.0-2.0*f); return mix(mix(dot(random2(i vec2(0.0, 0.0)), f - vec2(0.0, 0.0)), dot(random2(i vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x), mix(dot(random2(i vec2(0.0, 1.0)), f - vec2(0.0, 1.0)), dot(random2(i vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x), u.y); } void main() { vec2 st gl_FragCoord.xy / u_resolution; st.x * u_resolution.x/u_resolution.y; vec3 color vec3(0.0); vec2 pos vec2(st*10.0); color vec3(noise(pos)*.5.5); FragColor vec4(color, 1.0f); }木头表皮Noise:#version 320 es precision mediump float; out vec4 FragColor;//out代表输出至下一个着色器 uniform vec2 u_resolution;//视窗的分辨率 uniform float u_time;//传入的时间变量 float random (in vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123); } // Value noise by Inigo Quilez - iq/2013 // https://www.shadertoy.com/view/lsf3WH float noise(vec2 st) { vec2 i floor(st); vec2 f fract(st); vec2 u f*f*(3.0-2.0*f); return mix(mix(random(i vec2(0.0, 0.0)), random(i vec2(1.0, 0.0)), u.x), mix(random(i vec2(0.0, 1.0)), random(i vec2(1.0, 1.0)), u.x), u.y); } mat2 rotate2d(float angle){ return mat2(cos(angle), -sin(angle), sin(angle), cos(angle)); } float lines(in vec2 pos, float b){ float scale 10.0; pos * scale; return smoothstep(0.0, .5b*.5, abs((sin(pos.x*3.1415)b*2.0))*.5); } void main() { vec2 st gl_FragCoord.xy / u_resolution; st.x * u_resolution.x/u_resolution.y; vec3 color vec3(0.0); vec2 pos st.yx*vec2(10., 3.); float pattern pos.x; // Add noise pos rotate2d(noise(pos)) * pos; // Draw lines pattern lines(pos, .5); color vec3(pattern); FragColor vec4(color, 1.0f); }距离场噪音#version 320 es precision mediump float; out vec4 FragColor;//out代表输出至下一个着色器 uniform vec2 u_resolution;//视窗的分辨率 uniform float u_time;//传入的时间变量 vec2 random2(vec2 st){ st vec2(dot(st, vec2(127.1, 311.7)), dot(st, vec2(269.5, 183.3))); return -1.0 2.0*fract(sin(st)*43758.5453123); } // Gradient Noise by Inigo Quilez - iq/2013 // https://www.shadertoy.com/view/XdXGW8 float noise(vec2 st) { vec2 i floor(st); vec2 f fract(st); vec2 u f*f*(3.0-2.0*f); return mix(mix(dot(random2(i vec2(0.0, 0.0)), f - vec2(0.0, 0.0)), dot(random2(i vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x), mix(dot(random2(i vec2(0.0, 1.0)), f - vec2(0.0, 1.0)), dot(random2(i vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x), u.y); } void main() { vec2 st gl_FragCoord.xy / u_resolution; st.x * u_resolution.x/u_resolution.y; vec3 color vec3(0.0); float t 1.0; // Uncomment to animate t abs(1.0-sin(u_time*.1))*5.; // Comment and uncomment the following lines: st noise(st*2.)*t;// Animate the coordinate space color vec3(1.) * smoothstep(.18, .2, noise(st));// Big black drops color smoothstep(.15, .2, noise(st*10.));// Black splatter color - smoothstep(.35, .4, noise(st*10.));// Holes on splatter FragColor vec4(1.0-color, 1.0f); }形状噪音#version 320 es precision mediump float; out vec4 FragColor;//out代表输出至下一个着色器 uniform vec2 u_resolution;//视窗的分辨率 uniform float u_time;//传入的时间变量 vec2 random2(vec2 st){ st vec2(dot(st, vec2(127.1, 311.7)), dot(st, vec2(269.5, 183.3))); return -1.0 2.0*fract(sin(st)*43758.5453123); } // Gradient Noise by Inigo Quilez - iq/2013 // https://www.shadertoy.com/view/XdXGW8 float noise(vec2 st) { vec2 i floor(st); vec2 f fract(st); vec2 u f*f*(3.0-2.0*f); return mix(mix(dot(random2(i vec2(0.0, 0.0)), f - vec2(0.0, 0.0)), dot(random2(i vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x), mix(dot(random2(i vec2(0.0, 1.0)), f - vec2(0.0, 1.0)), dot(random2(i vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x), u.y); } mat2 rotate2d(float _angle){ return mat2(cos(_angle), -sin(_angle), sin(_angle), cos(_angle)); } float shape(vec2 st, float radius) { st vec2(0.5)-st; float r length(st)*2.0; float a atan(st.y, st.x); float m abs(mod(au_time*2., 3.14*2.)-3.14)/3.6; float f radius; m noise(stu_time*0.1)*.5; a * 1.abs(atan(u_time*0.2))*.1; a * 1.noise(stu_time*0.1)*0.1; f sin(a*50.)*noise(stu_time*.2)*.1; f (sin(a*20.)*.1*pow(m, 2.)); return 1.-smoothstep(f, f0.007, r); } float shapeBorder(vec2 st, float radius, float width) { return shape(st, radius)-shape(st, radius-width); } void main() { vec2 st gl_FragCoord.xy / u_resolution; vec3 color vec3(1.0) * shapeBorder(st, 0.8, 0.02); FragColor vec4(1.0-color, 1.0f); }水榕灯#version 320 es precision mediump float; out vec4 FragColor;//out代表输出至下一个着色器 uniform vec2 u_resolution;//视窗的分辨率 uniform float u_time;//传入的时间变量 vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec3 permute(vec3 x) { return mod289(((x*34.0)1.0)*x); } float snoise(vec2 v) { const vec4 C vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) -0.577350269189626, // -1.0 2.0 * C.x 0.024390243902439);// 1.0 / 41.0 vec2 i floor(v dot(v, C.yy)); vec2 x0 v - i dot(i, C.xx); vec2 i1; i1 (x0.x x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); vec4 x12 x0.xyxy C.xxzz; x12.xy - i1; i mod289(i);// Avoid truncation effects in permutation vec3 p permute(permute(i.y vec3(0.0, i1.y, 1.0)) i.x vec3(0.0, i1.x, 1.0)); vec3 m max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0); m m*m; m m*m; vec3 x 2.0 * fract(p * C.www) - 1.0; vec3 h abs(x) - 0.5; vec3 ox floor(x 0.5); vec3 a0 x - ox; m * 1.79284291400159 - 0.85373472095314 * (a0*a0 h*h); vec3 g; g.x a0.x * x0.x h.x * x0.y; g.yz a0.yz * x12.xz h.yz * x12.yw; return 130.0 * dot(m, g); } void main() { vec2 st gl_FragCoord.xy / u_resolution; st.x * u_resolution.x/u_resolution.y; vec3 color vec3(0.0); vec2 pos vec2(st*3.); float DF 0.0; // Add a random position float a 0.0; vec2 vel vec2(u_time*.1); DF snoise(posvel)*.25.25; // Add a random position a snoise(pos*vec2(cos(u_time*0.15), sin(u_time*0.1))*0.1)*3.1415; vel vec2(cos(a), sin(a)); DF snoise(posvel)*.25.25; color vec3(smoothstep(.7, .75, fract(DF))); FragColor vec4(1.0-color, 1.0f); }材质噪音#version 320 es precision mediump float; out vec4 FragColor;//out代表输出至下一个着色器 uniform vec2 u_resolution;//视窗的分辨率 uniform float u_time;//传入的时间变量 #define PI 3.14159265359f; #define TWO_PI 6.28318530718f; const float F3 0.3333333; const float G3 0.1666667; // Copyright (c) Patricio Gonzalez Vivo, 2015 - http://patriciogonzalezvivo.com/ // I am the sole copyright owner of this Work. // // You cannot host, display, distribute or share this Work in any form, // including physical and digital. You cannot use this Work in any // commercial or non-commercial product, website or project. You cannot // sell this Work and you cannot mint an NFTs of it. // I share this Work for educational purposes, and you can link to it, // through an URL, proper attribution and unmodified screenshot, as part // of your educational material. If these conditions are too restrictive // please contact me and well definitely work it out. float shape(vec2 st, int N){ st st*2.-1.; float a atan(st.x, st.y)PI; float r (1.0 / float(N)) * TWO_PI; return cos(floor(0.5a/r)*r-a)*length(st); } float box(vec2 st, vec2 size){ return shape(st*size, 4); } float hex(vec2 st, bool a, bool b, bool c, bool d, bool e, bool f){ st st*vec2(2., 6.); vec2 fpos fract(st); vec2 ipos floor(st); if (ipos.x 1.0) fpos.x 1.-fpos.x; if (ipos.y 1.0){ return a? box(fpos-vec2(0.03, 0.), vec2(1.)) : box(fpos, vec2(0.84, 1.)); } else if (ipos.y 2.0){ return b? box(fpos-vec2(0.03, 0.), vec2(1.)) : box(fpos, vec2(0.84, 1.)); } else if (ipos.y 3.0){ return c? box(fpos-vec2(0.03, 0.), vec2(1.)) : box(fpos, vec2(0.84, 1.)); } else if (ipos.y 4.0){ return d? box(fpos-vec2(0.03, 0.), vec2(1.)) : box(fpos, vec2(0.84, 1.)); } else if (ipos.y 5.0){ return e? box(fpos-vec2(0.03, 0.), vec2(1.)) : box(fpos, vec2(0.84, 1.)); } else if (ipos.y 6.0){ return f? box(fpos-vec2(0.03, 0.), vec2(1.)) : box(fpos, vec2(0.84, 1.)); } return 0.0; } float hex(vec2 st, float N){ bool b[6]; float remain floor(mod(N, 64.)); for (int i 0; i 6; i){ b[i] mod(remain, 2.)1.?true:false; remain ceil(remain/2.); } return hex(st, b[0], b[1], b[2], b[3], b[4], b[5]); } vec3 random3(vec3 c) { float j 4096.0*sin(dot(c, vec3(17.0, 59.4, 15.0))); vec3 r; r.z fract(512.0*j); j * .125; r.x fract(512.0*j); j * .125; r.y fract(512.0*j); return r-0.5; } float snoise(vec3 p) { vec3 s floor(p dot(p, vec3(F3))); vec3 x p - s dot(s, vec3(G3)); vec3 e step(vec3(0.0), x - x.yzx); vec3 i1 e*(1.0 - e.zxy); vec3 i2 1.0 - e.zxy*(1.0 - e); vec3 x1 x - i1 G3; vec3 x2 x - i2 2.0*G3; vec3 x3 x - 1.0 3.0*G3; vec4 w, d; w.x dot(x, x); w.y dot(x1, x1); w.z dot(x2, x2); w.w dot(x3, x3); w max(0.6 - w, 0.0); d.x dot(random3(s), x); d.y dot(random3(s i1), x1); d.z dot(random3(s i2), x2); d.w dot(random3(s 1.0), x3); w * w; w * w; d * w; return dot(d, vec4(52.0)); } void main() { vec2 st gl_FragCoord.xy / u_resolution; st.x * u_resolution.x/u_resolution.y; vec3 color vec3(0.0); float t u_time*0.5; float df 1.0; df mix(hex(st,t),hex(st,t1.),fract(t)); df snoise(vec3(st*75.,t*0.1))*0.03; color mix(vec3(0.),vec3(1.),step(0.7,df)); FragColor vec4(color, 1.0f); }三、网络噪音Cellular Noise程序化纹理技术要理解它背后的原理我们需要从迭代开始思考。你可能已经知道迭代是什么意思对就是使用for循环。GLSL 的for循环中只有一个需要注意的我们检查循环是否继续的次数必须是一个常数const. 所以没有动态循环——迭代的次数必须是固定的。网格噪声基于距离场这里的距离是指到一个特征点集最近的点的距离。比如说我们要写一个 4 个特征点的距离场我们应该做什么呢对每一个像素计算它到最近的特征点的距离。也就是说我们需要遍历所有 4 个特征点计算他们到当前像素点的距离并把最近的那个距离存下来。// A variable to store the closest distance to a point float min_dist 100.; min_dist min(min_dist, distance(st, point_a)); min_dist min(min_dist, distance(st, point_b)); min_dist min(min_dist, distance(st, point_c)); min_dist min(min_dist, distance(st, point_d));用一个for循环遍历特征点集的数组用一个 min() 函数来获得最小距离
返回列表