当前位置: 首页 > news >正文

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之高级OpenGL(1)

8、LearnOpenGL之高级OpenGL(2)

9、LearnOpenGL之骨骼动画

10、LearnOpenGL之Shader编程用算法绘画

11、LearnOpenGL之Shader编程——生成设计

——————————————————————————————————————————

—————————————————— 效果展示 ————————————————————

一、随机:

随机性是熵的最大表现。我们如何在看似可预测而且严苛的代码环境中生成随机性呢?

sin函数其波形的分数部分。值域为-1.01.0之间的sin() 函数被取了小数点后的部分(这里实际是指模1)),返回0.01.0间的正值。我们可以用这种效果通过把正弦函数打散成小片段来得到一些伪随机数。如何实现呢?通过在sin(x)的值上乘以大些的数。

控制混沌:

使用随机会很难;它不是太混沌难测就是有时又不够混乱。谨记我们用的rand()是确定性随机,也被称作是伪随机。这就意味着, 就rand(1.)为例,总会返回相同的值。

2D随机:

现在我们对随机有了深入的理解,是时候将它应用到二维,x轴和y轴。为此我们需要将一个二维向量转化为一维浮点数。这里有几种不同的方法来实现,但 dot() 函数在这个例子中尤其有用。它根据两个向量的方向返回一个0.01.0之间的值。

用 dot() 函数在这个例子中尤其有用。它根据两个向量的方向返回一个0.01.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.x+0.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, .5+b*.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(a+u_time*2., 3.14*2.)-3.14)/3.6; float f = radius; m += noise(st+u_time*0.1)*.5; a *= 1.+abs(atan(u_time*0.2))*.1; a *= 1.+noise(st+u_time*0.1)*0.1; f += sin(a*50.)*noise(st+u_time*.2)*.1; f += (sin(a*20.)*.1*pow(m, 2.)); return 1.-smoothstep(f, f+0.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(pos+vel)*.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(pos+vel)*.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 we'll 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.5+a/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,t+1.),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() 函数来获得最小距离

http://www.jsqmd.com/news/1361172/

相关文章:

  • 如何在macOS上免费运行Windows应用:Whisky完整使用指南
  • 2026寄件实测:分人群渠道推荐 - 快递物流实时资讯
  • 终极教程:使用timm库提取ViT-B-16-SigLIP-256图像特征的完整步骤
  • 基于Godot引擎的战棋RPG开发框架:模块化设计与核心实现
  • 三步掌握QQ空间历史说说备份:你的青春记忆永久保存方案
  • ABAP内表数据追加操作与性能优化指南
  • 新能源消纳与储能优化调度:Matlab实现与工程实践
  • 门店小程序怎么做?预约、核销、会员储值和到店服务方案对比
  • ViT-B-16-SigLIP-256完全解析:革命性图像文本对比模型如何重塑零样本分类
  • LabStreamingLayer核心功能解析:从设备连接到数据可视化的完整流程
  • Qwen3-VL-32B Ultra Heretic H3模型深度剖析:从架构到核心功能
  • NEORV32架构深度解析:如何用模块化设计打造极致灵活的RISC-V微控制器
  • 为什么edgenext_x_small.in1k是移动视觉首选?0.5 GMACs低算力模型性能评测
  • Yocto:.bbclass文件
  • 番茄小说下载器:5步构建个人离线图书馆的完整指南
  • 终极GTA兼容性修复指南:如何让经典GTA游戏在现代Windows系统完美运行
  • CreuSAT开发者教程:用Rust实现高效验证的SAT求解算法
  • ChatGPT Plus升级全攻略:解决区域限制与支付难题
  • Java进制转换:Integer.toString()高效实现方案
  • 未来已来:NVIDIA GR00T-N1.6-fractal开启人形机器人开发新纪元
  • LeetCode盛水问题:双指针算法详解与优化
  • 小程序商城和多商户平台有什么区别?微信开店、平台招商和分账结算怎么选
  • 3分钟快速上手XSStrike:终极XSS漏洞扫描工具完全指南
  • QQ群数据采集神器:3分钟批量获取精准社群信息,开启数据驱动新纪元
  • VisualCppRedist AIO:一站式解决Windows C++运行时依赖的终极方案
  • nile.js核心组件解析:Broadcaster与Viewer如何实现P2P视频流传输
  • 阳江物联网开发公司哪家强?2026年实操指南深圳市创新梦想科技有限公司(阳江销售部) - 热点品牌推荐
  • 如何快速上手GR00T-N1.6-fractal:从安装到运行的完整指南
  • 原神抽卡记录导出工具:3分钟免费获取完整抽卡数据分析指南
  • 进销云掌柜:中小微企业云端进销存管理解决方案