【译】创意编码之噪音

【译】创意编码之噪音

原文:https://varun.ca/noise/
作者:Ahmad Shadeed
译者:NSGUF

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bGmGeXsB-1658998821080)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e111af665402499ab06e1335579b5196~tplv-k3u1fbpfcp-watermark.image?)]

噪音是一种创意编码中不可或缺的工具。我们使用它来生成各种各样的仿自然形态的效果,如云,风景以及轮廓等;或者以更逼真的行为移动和扭曲对象;

表面上看,噪音似乎很容易使用,但是它有非常多层次,这篇文章深入研究了什么是噪音,它的变种有哪些,如何在网络和应用程序上使用;也会展示很多的例子,非常多的例子!

噪音是什么?

假设你想在屏幕上移动一个物体。动画师会使用关键帧和补帧来描述这个确切的运动。生成类似这个动画师的艺术家依赖于算法;

那么,math.random()可以实现吗?

不行,随机就太不自然了,看下面这个粉红色的球,到处弹跳,这就很恶心了🥴;

我们需要更平滑,更自然的随机性,这个(黄色的球)就是噪音函数生成的,美观多了;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fmfZkUIL-1658998821081)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e51d0659c5da4f348bf5180b58db3b8c~tplv-k3u1fbpfcp-watermark.image?)]

自然随机的想法在创意编码中出现了一遍又一遍。例如:我们经常使用噪音函数生成纹理,移动或扭曲物体;

在网络上生成噪音

两种类型噪音——Perlin和Simplex

在1980年初期,Ken Perlin在做Tron时开发了Perlin噪音并因这个特效获得奥斯卡奖。然后他在此这种特效上改进开发了Simplex,这种新算法运行速度更快。我将会专注于后者,并在我的例子中使simplex-noise库;

噪音函数接受两个输入(用于生成输出)并且返回一个-1到1的值。这个输出结合了Math.sin()Math.random(),随机波就是我描述他的方式;

import SimplexNoise from 'simplex-noise';

const simplex = new SimplexNoise();
const y = simplex.noise2D(x * frequency, 0) * amplitude;

基础力学和波浪的工作原理相似,你可以通过调整频率和振幅来控制波浪的速度和幅度;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X1z42LKQ-1658998821081)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/64d5e407a3354523ad44ab44b875c718~tplv-k3u1fbpfcp-watermark.image?)]

emm,二维噪音,发生了什么?

噪音维度

噪音算法可以实现多维度。这里是将维度视为噪音生成器的输入数量,2个输入为2D,三个是3D,以此类推;

选择哪种维度,取决于使用的生成器的变量,让我们看几个例子:

💡 从这里开始,每个例子都会有个通过指向实际源码嵌入的源码卡片,在某些情况下,你可以调整变量;(翻译我是使用的gif

一维噪音 —— 波动

从技术上讲,是没有一维噪音的。你可以通过将0作为第二个参数给到simplex noise2D得到1维噪音;架设你想让这个移动的球看起来比较自然,可以增加x坐标并生成y坐标;

x += 0.1;
y = simplex.noise2D(x * frequency, 0) * amplitude;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wVdb6brW-1658998821081)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8859eaadd15d411dbc8995bef6bc7719~tplv-k3u1fbpfcp-watermark.image?)]

二维噪音 —— 地形生成器

我们可以通过移动z轴方向的顶点,将一个水平2D平面转换成丘陵地形,使用x,y轴坐标来生成z坐标位置;

就这样,我们有了一个地形生成器🏔️;

z = simplex.noise2D(x * frequency, y * frequency) * amplitude;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WLrok4pO-1658998821082)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1d73ae19d6ce45979cd2286bd37df285~tplv-k3u1fbpfcp-watermark.image?)]

三维噪音——顶点位移

你可能已经见过这种自然扭曲的球体,它们通过移动球体顶点生成;使用顶点坐标(x,y,z)来生成扭曲的位置变量,然后通过移动顶点生成放射的形状;

const distortion =
simplex.noise3D(x * frequency, y * frequency, z * frequency) * amplitude;

newPosition = position.normalize().multiplyScalar(distortion);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jWRUe0VR-1658998821082)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1e808e90e3c542d2b7a0692daec83c2d~tplv-k3u1fbpfcp-watermark.image?)]

四维噪音—— 动态扭曲效果

我们可以通过4维噪音来生成一个不停动态扭曲的球,输入分别是顶点坐标(x,y,z)时间。这项技术常用于创造类似火球的效果;

const distortion =
simplex.noise4D(
x * frequency,
y * frequency,
z * frequency,
time * frequency
) * amplitude;

newPosition = position.normalize().multiplyScalar(distortion);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qUcIcRLh-1658998821082)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/99d17ff2ca714953b15cb278e9023a24~tplv-k3u1fbpfcp-watermark.image?)]

在上面的大多数例子里我们都使用了振幅,这是程序中缩放噪音输出的方式,你还可以使用插值将噪音输出映射到选择的指定范围;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UzilE5mk-1658998821083)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5942aad65bad41a8b4f079109ba366c6~tplv-k3u1fbpfcp-watermark.image?)]

现在我们已经掌握了基础知识,让我们看一些噪音的其他应用;

纹理

使用(x,y)坐标,生成二维的表格格式的噪音,看起来像这样:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-32VSSpUj-1658998821083)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/edf582b085f04a8788982ad7cc006a95~tplv-k3u1fbpfcp-watermark.image?)]

使用方式:

for (let y = 0; y < gridSize[1]; y++) {
for (let x = 0; x < gridSize[0]; x++) {
const n = simplex.noise2D(
x / (gridSize[0] * 0.75),
y / (gridSize[1] * 0.75)
);
}
}

这是我们的出发点。
我们可以使用Marching Squares算法将2D数据转换成等高线。使用Canvas,SVG,WebGL或者其他你喜欢的工具,我最近使用SVG来生成带有轮廓的卡片,这方面相关的完整教程,请查看https://storybook.js.org/blog/generative-image-service/📸;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b8Tgu6cx-1658998821084)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a31d87968fc1452884116e2ae9ce4e12~tplv-k3u1fbpfcp-watermark.image?)]

关于噪音,最酷的事情是你可以添加时间维度,来给你的图片添加动画;

simplex.noise3D(x / (gridSize[0] * 0.75), y / (gridSize[1] * 0.75), time);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P1npnNEe-1658998821084)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/56869babab2b40f8b7fd696d85e6c717~tplv-k3u1fbpfcp-watermark.image?)]

老实讲,噪音的二维数据是非常实用的,这可以做很多的事情,其中一个是我特别喜欢——噪音领域;

让我们回到最初的灰度输出,这里可以映射出一个更有趣的色阶,你可以获取到等离子;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YvFdMnYn-1658998821085)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/afe83871233e436ba4dbd8a9cef24fa6~tplv-k3u1fbpfcp-watermark.image?)]

或者从矩形网格开始,通过使用噪音来控制颜色和角度,将其变成向量场;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TT1qsUjB-1658998821085)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/21e84885f83c4671a3856c3417107517~tplv-k3u1fbpfcp-watermark.image?)]

噪音粒子

向量场很酷,但是流场更让人兴奋。这是我去年画的图;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NYiqx5Ek-1658998821086)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1ec31486a00040759f9dfc6283936435~tplv-k3u1fbpfcp-watermark.image?)]

注意笔的轨迹。每一划都是通过将粒子放到向量场上来生成的。然后追踪它的路径。💫

好吧,让我们分解这个过程。

创建流场

第一步,创建一个向量场。和之前一样。但这一次,我们不会为向量场设置动画。

第 2 步,将一堆粒子放到画布上。它们的运动方向基于底层向量场。向前迈出一步,找到新的方向并重复。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OciwyyEC-1658998821086)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/056cfea019b548dd9caf68c83d4fec76~tplv-k3u1fbpfcp-watermark.image?)]

function moveParticle(particle) {
// Calculate direction from noise
const angle =
simplex.noise2D(particle.x * FREQUENCY, particle.y * FREQUENCY) * AMPLITUDE;

// Update the velocity of the particle
// based on the direction
particle.vx += Math.cos(angle) * STEP;
particle.vy += Math.sin(angle) * STEP;

// Move the particle
particle.x += particle.vx;
particle.y += particle.vy;

// Use damping to slow down the particle (think friction)
particle.vx *= DAMPING;
particle.vy *= DAMPING;

particle.line.push([particle.x, particle.y]);
}

第三步:追踪粒子的位置,以追踪其路径;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GhdgB1fI-1658998821087)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4a2afcbc342d4a0abd42264146c7058a~tplv-k3u1fbpfcp-watermark.image?)]

添加更多的粒子和颜色,我们就可以获得流场;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UxY17WUH-1658998821087)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2b4c339650924f69a14ccd2b38e0ce0b~tplv-k3u1fbpfcp-watermark.image?)]

粒子系统

说到粒子,噪声也出现在粒子系统中。对于像雨、雪或五彩纸屑等效果,你希望模拟一个看起来很自然的运动。想象一个五彩纸屑颗粒飘向地面。粒子不会直线移动。由于空气阻力,它们会漂浮和摆动。噪声是添加仿自然形态非常好的工具。

const wiggle = {
x: simplex.noise2D(particle.x * frequency, time) * amplitude,
y: simplex.noise2D(particle.y * frequency, time) * amplitude,
};
particle.x += wiggle.x;
particle.y += wiggle.y;

想深入了解,详情请看:https://varun.ca/confetti/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7vvQ7R0l-1658998821087)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d18b835a4c3d4dd48af6f971f56be623~tplv-k3u1fbpfcp-watermark.image?)]

着色器

让我们回到那些动画斑点。使用着色器操作和设置3D动画几何图形的效率要高得多。但是着色器本身是一个完全不同的世界。对于初学者来说,有一个特殊的 WebGL 版本的噪音,gsl-noise。我们需要使用 glslify 将它导入到我们的着色器中。

我们会慢慢来,先从 2D 开始。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KZ6BwuB2-1658998821088)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6d365e65cb4f4a61b61a4eec4b30768f~tplv-k3u1fbpfcp-watermark.image?)]

上面的动画与我们之前看到的轮廓非常相似。它是通过片段着色器实现的。这意味着我们为canvas的每个像素运行相同的程序。

注意到pragma 行了吗?那是我们导入 webgl-noise。然后用它为每个像素位置 vUv 生成噪声数据。

这部分现在看起来应该很熟悉了。

fragment.glsl

precision highp float;
uniform float time;
uniform float density;
varying vec2 vUv;

#define PI 3.141592653589793
#pragma glslify: noise = require(glsl-noise/simplex/3d);

float patternZebra(float v){
float d = 1.0 / density;
float s = -cos(v / d * PI * 2.);
return smoothstep(.0, .1 * d, .1 * s / fwidth(s));
}

void main() {
// Generate noise data float amplitude = 1.0; float frequency = 1.5; float noiseValue = noise(vec3(vUv * frequency, time)) * amplitude;  // Convert noise data to rings
float t = patternZebra(noiseValue);
vec3 color = mix(vec3(1.,0.4,0.369), vec3(0.824,0.318,0.369), t);
// Clip the rings to a circle
float dist = length(vUv - vec2(0.5, 0.5));
float alpha = smoothstep(0.250, 0.2482, dist);

gl_FragColor = vec4(color, alpha);
}

片段着色器具有用于绘制形状的距离函数的概念。 patternZebra 就是一个将噪声数据转换为环的示例。本质上,它返回 0 或 1。然后我们用它来选择混合的颜色。最后,使用另一个距离函数来剪裁圆形边界。

看起来很基础?

好吧,着色器的惊人之处在于,你可以将它们变成一种材质并将其应用于更复杂的几何体。

噪声材质

我们可以从上面获取相同的 2D mars 着色器。将其转换为 ThreeJS 着色器材质。然后使用顶点位置 vPosition 代替 vUv 生成噪声。 瞧,我们有一个 3D mars!

const material = new THREE.ShaderMaterial({
extensions: {
derivatives: true,
},
uniforms: {
time: { value: 0 },
density: { value: 1.0 },
},
vertexShader: /*glsl*/ ` varying vec3 vPosition; void main () { vPosition = position; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `,
fragmentShader: glslify(/* glsl */ ` precision highp float; varying vec3 vPosition; uniform float time; uniform float density; #pragma glslify: noise = require(glsl-noise/simplex/4d); #define PI 3.141592653589793 float patternZebra(float v){ float d = 1.0 / density; float s = -cos(v / d * PI * 2.); return smoothstep(.0, .1 * d, .1 * s / fwidth(s)); } void main () { float frequency = .6; float amplitude = 1.5; float v = noise(vec4(vPosition * frequency, sin(PI * time))) * amplitude; float t = patternZebra(v); vec3 fragColor = mix(vec3(1.,0.4,0.369), vec3(0.824,0.318,0.369), t); gl_FragColor = vec4(fragColor, 1.); } `),
});

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iplAlFUi-1658998821088)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/35281e84fe85477292ad62c73187d207~tplv-k3u1fbpfcp-watermark.image?)]

老实说,这只是一个开始。着色器开辟了许多可能性。就像下面的例子

不仅是噪声映射到颜色,还可以是透明度。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DyH2dBpc-1658998821088)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/891b024e400f47409da1ce0b7744afbb~tplv-k3u1fbpfcp-watermark.image?)]

光泽斑点

与顶点置换背后的想法非常相似。我们编写了一个顶点着色器来转换球体的每个顶点,而不是片段着色器。同样,使用着色器材质应用。

vertex.glsl

precision highp float;
varying vec3 vNormal;

#pragma glslify: snoise4 = require(glsl-noise/simplex/4d)

uniform float u_time;
uniform float u_amplitude;
uniform float u_frequency;

void main () {
vNormal = normalMatrix * normalize(normal); float distortion = snoise4(vec4(normal * u_frequency, u_time)) * u_amplitude; vec3 newPosition = position + (normal * distortion);
gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
}

加上一些 matcap,你就会得到一些有光泽的动画斑点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vVFKC4s2-1658998821089)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8b71c2607dce4f929ab924f6225d434d~tplv-k3u1fbpfcp-watermark.image?)]

轮到你创造噪音了

那真是一段旅程。运动、纹理、场、粒子系统和置换——噪声都能做。它确实是创意编码世界的主力军。

很明显,你想玩噪音😁

我已经为你准备了一个小小的入门 CodePen。它旋转了一个噪声网格并将其映射到一个字形数组。只需从修改数组开始,看看你能走多远。

const glyphs = ['¤', '✳', '●', '◔', '○', '◕', '◐', '◑', '◒'];

或者,如果您正在寻找更高级的东西,请查看noisedeck.app。它就像一个只用于视觉效果的合成器。

原文:https://varun.ca/noise/
作者:Ahmad Shadeed
译者:NSGUF

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2W3b0xPg-1658998815215)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e111af665402499ab06e1335579b5196~tplv-k3u1fbpfcp-watermark.image?)]

噪音是一种创意编码中不可或缺的工具。我们使用它来生成各种各样的仿自然形态的效果,如云,风景以及轮廓等;或者以更逼真的行为移动和扭曲对象;

表面上看,噪音似乎很容易使用,但是它有非常多层次,这篇文章深入研究了什么是噪音,它的变种有哪些,如何在网络和应用程序上使用;也会展示很多的例子,非常多的例子!

噪音是什么?

假设你想在屏幕上移动一个物体。动画师会使用关键帧和补帧来描述这个确切的运动。生成类似这个动画师的艺术家依赖于算法;

那么,math.random()可以实现吗?

不行,随机就太不自然了,看下面这个粉红色的球,到处弹跳,这就很恶心了🥴;

我们需要更平滑,更自然的随机性,这个(黄色的球)就是噪音函数生成的,美观多了;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EaB58jTV-1658998815216)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e51d0659c5da4f348bf5180b58db3b8c~tplv-k3u1fbpfcp-watermark.image?)]

自然随机的想法在创意编码中出现了一遍又一遍。例如:我们经常使用噪音函数生成纹理,移动或扭曲物体;

在网络上生成噪音

两种类型噪音——Perlin和Simplex

在1980年初期,Ken Perlin在做Tron时开发了Perlin噪音并因这个特效获得奥斯卡奖。然后他在此这种特效上改进开发了Simplex,这种新算法运行速度更快。我将会专注于后者,并在我的例子中使simplex-noise库;

噪音函数接受两个输入(用于生成输出)并且返回一个-1到1的值。这个输出结合了Math.sin()Math.random(),随机波就是我描述他的方式;

import SimplexNoise from 'simplex-noise';

const simplex = new SimplexNoise();
const y = simplex.noise2D(x * frequency, 0) * amplitude;

基础力学和波浪的工作原理相似,你可以通过调整频率和振幅来控制波浪的速度和幅度;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-olxqSIDO-1658998815216)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/64d5e407a3354523ad44ab44b875c718~tplv-k3u1fbpfcp-watermark.image?)]

emm,二维噪音,发生了什么?

噪音维度

噪音算法可以实现多维度。这里是将维度视为噪音生成器的输入数量,2个输入为2D,三个是3D,以此类推;

选择哪种维度,取决于使用的生成器的变量,让我们看几个例子:

💡 从这里开始,每个例子都会有个通过指向实际源码嵌入的源码卡片,在某些情况下,你可以调整变量;(翻译我是使用的gif

一维噪音 —— 波动

从技术上讲,是没有一维噪音的。你可以通过将0作为第二个参数给到simplex noise2D得到1维噪音;架设你想让这个移动的球看起来比较自然,可以增加x坐标并生成y坐标;

x += 0.1;
y = simplex.noise2D(x * frequency, 0) * amplitude;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KDKwSLfQ-1658998815217)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8859eaadd15d411dbc8995bef6bc7719~tplv-k3u1fbpfcp-watermark.image?)]

二维噪音 —— 地形生成器

我们可以通过移动z轴方向的顶点,将一个水平2D平面转换成丘陵地形,使用x,y轴坐标来生成z坐标位置;

就这样,我们有了一个地形生成器🏔️;

z = simplex.noise2D(x * frequency, y * frequency) * amplitude;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-utWGuuIB-1658998815217)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1d73ae19d6ce45979cd2286bd37df285~tplv-k3u1fbpfcp-watermark.image?)]

三维噪音——顶点位移

你可能已经见过这种自然扭曲的球体,它们通过移动球体顶点生成;使用顶点坐标(x,y,z)来生成扭曲的位置变量,然后通过移动顶点生成放射的形状;

const distortion =
simplex.noise3D(x * frequency, y * frequency, z * frequency) * amplitude;

newPosition = position.normalize().multiplyScalar(distortion);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dhYIK1zz-1658998815218)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1e808e90e3c542d2b7a0692daec83c2d~tplv-k3u1fbpfcp-watermark.image?)]

四维噪音—— 动态扭曲效果

我们可以通过4维噪音来生成一个不停动态扭曲的球,输入分别是顶点坐标(x,y,z)时间。这项技术常用于创造类似火球的效果;

const distortion =
simplex.noise4D(
x * frequency,
y * frequency,
z * frequency,
time * frequency
) * amplitude;

newPosition = position.normalize().multiplyScalar(distortion);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OkQSI1Cu-1658998815218)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/99d17ff2ca714953b15cb278e9023a24~tplv-k3u1fbpfcp-watermark.image?)]

在上面的大多数例子里我们都使用了振幅,这是程序中缩放噪音输出的方式,你还可以使用插值将噪音输出映射到选择的指定范围;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qPcyn2Bp-1658998815219)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5942aad65bad41a8b4f079109ba366c6~tplv-k3u1fbpfcp-watermark.image?)]

现在我们已经掌握了基础知识,让我们看一些噪音的其他应用;

纹理

使用(x,y)坐标,生成二维的表格格式的噪音,看起来像这样:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qiTBxcA4-1658998815220)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/edf582b085f04a8788982ad7cc006a95~tplv-k3u1fbpfcp-watermark.image?)]

使用方式:

for (let y = 0; y < gridSize[1]; y++) {
for (let x = 0; x < gridSize[0]; x++) {
const n = simplex.noise2D(
x / (gridSize[0] * 0.75),
y / (gridSize[1] * 0.75)
);
}
}

这是我们的出发点。
我们可以使用Marching Squares算法将2D数据转换成等高线。使用Canvas,SVG,WebGL或者其他你喜欢的工具,我最近使用SVG来生成带有轮廓的卡片,这方面相关的完整教程,请查看https://storybook.js.org/blog/generative-image-service/📸;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PkDlIj33-1658998815220)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a31d87968fc1452884116e2ae9ce4e12~tplv-k3u1fbpfcp-watermark.image?)]

关于噪音,最酷的事情是你可以添加时间维度,来给你的图片添加动画;

simplex.noise3D(x / (gridSize[0] * 0.75), y / (gridSize[1] * 0.75), time);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V4ih7BQX-1658998815221)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/56869babab2b40f8b7fd696d85e6c717~tplv-k3u1fbpfcp-watermark.image?)]

老实讲,噪音的二维数据是非常实用的,这可以做很多的事情,其中一个是我特别喜欢——噪音领域;

让我们回到最初的灰度输出,这里可以映射出一个更有趣的色阶,你可以获取到等离子;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4qr5JfT5-1658998815221)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/afe83871233e436ba4dbd8a9cef24fa6~tplv-k3u1fbpfcp-watermark.image?)]

或者从矩形网格开始,通过使用噪音来控制颜色和角度,将其变成向量场;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vf4cq6A8-1658998815221)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/21e84885f83c4671a3856c3417107517~tplv-k3u1fbpfcp-watermark.image?)]

噪音粒子

向量场很酷,但是流场更让人兴奋。这是我去年画的图;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NqzHXmf3-1658998815222)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1ec31486a00040759f9dfc6283936435~tplv-k3u1fbpfcp-watermark.image?)]

注意笔的轨迹。每一划都是通过将粒子放到向量场上来生成的。然后追踪它的路径。💫

好吧,让我们分解这个过程。

创建流场

第一步,创建一个向量场。和之前一样。但这一次,我们不会为向量场设置动画。

第 2 步,将一堆粒子放到画布上。它们的运动方向基于底层向量场。向前迈出一步,找到新的方向并重复。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eFIPhLA9-1658998815223)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/056cfea019b548dd9caf68c83d4fec76~tplv-k3u1fbpfcp-watermark.image?)]

function moveParticle(particle) {
// Calculate direction from noise
const angle =
simplex.noise2D(particle.x * FREQUENCY, particle.y * FREQUENCY) * AMPLITUDE;

// Update the velocity of the particle
// based on the direction
particle.vx += Math.cos(angle) * STEP;
particle.vy += Math.sin(angle) * STEP;

// Move the particle
particle.x += particle.vx;
particle.y += particle.vy;

// Use damping to slow down the particle (think friction)
particle.vx *= DAMPING;
particle.vy *= DAMPING;

particle.line.push([particle.x, particle.y]);
}

第三步:追踪粒子的位置,以追踪其路径;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lxzMUEid-1658998815223)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4a2afcbc342d4a0abd42264146c7058a~tplv-k3u1fbpfcp-watermark.image?)]

添加更多的粒子和颜色,我们就可以获得流场;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wvp7CNao-1658998815224)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2b4c339650924f69a14ccd2b38e0ce0b~tplv-k3u1fbpfcp-watermark.image?)]

粒子系统

说到粒子,噪声也出现在粒子系统中。对于像雨、雪或五彩纸屑等效果,你希望模拟一个看起来很自然的运动。想象一个五彩纸屑颗粒飘向地面。粒子不会直线移动。由于空气阻力,它们会漂浮和摆动。噪声是添加仿自然形态非常好的工具。

const wiggle = {
x: simplex.noise2D(particle.x * frequency, time) * amplitude,
y: simplex.noise2D(particle.y * frequency, time) * amplitude,
};
particle.x += wiggle.x;
particle.y += wiggle.y;

想深入了解,详情请看:https://varun.ca/confetti/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zy2aBcCM-1658998815224)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d18b835a4c3d4dd48af6f971f56be623~tplv-k3u1fbpfcp-watermark.image?)]

着色器

让我们回到那些动画斑点。使用着色器操作和设置3D动画几何图形的效率要高得多。但是着色器本身是一个完全不同的世界。对于初学者来说,有一个特殊的 WebGL 版本的噪音,gsl-noise。我们需要使用 glslify 将它导入到我们的着色器中。

我们会慢慢来,先从 2D 开始。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VNsYzxfD-1658998815225)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6d365e65cb4f4a61b61a4eec4b30768f~tplv-k3u1fbpfcp-watermark.image?)]

上面的动画与我们之前看到的轮廓非常相似。它是通过片段着色器实现的。这意味着我们为canvas的每个像素运行相同的程序。

注意到pragma 行了吗?那是我们导入 webgl-noise。然后用它为每个像素位置 vUv 生成噪声数据。

这部分现在看起来应该很熟悉了。

fragment.glsl

precision highp float;
uniform float time;
uniform float density;
varying vec2 vUv;

#define PI 3.141592653589793
#pragma glslify: noise = require(glsl-noise/simplex/3d);

float patternZebra(float v){
float d = 1.0 / density;
float s = -cos(v / d * PI * 2.);
return smoothstep(.0, .1 * d, .1 * s / fwidth(s));
}

void main() {
// Generate noise data float amplitude = 1.0; float frequency = 1.5; float noiseValue = noise(vec3(vUv * frequency, time)) * amplitude;  // Convert noise data to rings
float t = patternZebra(noiseValue);
vec3 color = mix(vec3(1.,0.4,0.369), vec3(0.824,0.318,0.369), t);
// Clip the rings to a circle
float dist = length(vUv - vec2(0.5, 0.5));
float alpha = smoothstep(0.250, 0.2482, dist);

gl_FragColor = vec4(color, alpha);
}

片段着色器具有用于绘制形状的距离函数的概念。 patternZebra 就是一个将噪声数据转换为环的示例。本质上,它返回 0 或 1。然后我们用它来选择混合的颜色。最后,使用另一个距离函数来剪裁圆形边界。

看起来很基础?

好吧,着色器的惊人之处在于,你可以将它们变成一种材质并将其应用于更复杂的几何体。

噪声材质

我们可以从上面获取相同的 2D mars 着色器。将其转换为 ThreeJS 着色器材质。然后使用顶点位置 vPosition 代替 vUv 生成噪声。 瞧,我们有一个 3D mars!

const material = new THREE.ShaderMaterial({
extensions: {
derivatives: true,
},
uniforms: {
time: { value: 0 },
density: { value: 1.0 },
},
vertexShader: /*glsl*/ ` varying vec3 vPosition; void main () { vPosition = position; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `,
fragmentShader: glslify(/* glsl */ ` precision highp float; varying vec3 vPosition; uniform float time; uniform float density; #pragma glslify: noise = require(glsl-noise/simplex/4d); #define PI 3.141592653589793 float patternZebra(float v){ float d = 1.0 / density; float s = -cos(v / d * PI * 2.); return smoothstep(.0, .1 * d, .1 * s / fwidth(s)); } void main () { float frequency = .6; float amplitude = 1.5; float v = noise(vec4(vPosition * frequency, sin(PI * time))) * amplitude; float t = patternZebra(v); vec3 fragColor = mix(vec3(1.,0.4,0.369), vec3(0.824,0.318,0.369), t); gl_FragColor = vec4(fragColor, 1.); } `),
});

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ftgOt9Bn-1658998815225)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/35281e84fe85477292ad62c73187d207~tplv-k3u1fbpfcp-watermark.image?)]

老实说,这只是一个开始。着色器开辟了许多可能性。就像下面的例子

不仅是噪声映射到颜色,还可以是透明度。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AQOqQDy2-1658998815225)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/891b024e400f47409da1ce0b7744afbb~tplv-k3u1fbpfcp-watermark.image?)]

光泽斑点

与顶点置换背后的想法非常相似。我们编写了一个顶点着色器来转换球体的每个顶点,而不是片段着色器。同样,使用着色器材质应用。

vertex.glsl

precision highp float;
varying vec3 vNormal;

#pragma glslify: snoise4 = require(glsl-noise/simplex/4d)

uniform float u_time;
uniform float u_amplitude;
uniform float u_frequency;

void main () {
vNormal = normalMatrix * normalize(normal); float distortion = snoise4(vec4(normal * u_frequency, u_time)) * u_amplitude; vec3 newPosition = position + (normal * distortion);
gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
}

加上一些 matcap,你就会得到一些有光泽的动画斑点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OMCV3GZg-1658998815226)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8b71c2607dce4f929ab924f6225d434d~tplv-k3u1fbpfcp-watermark.image?)]

轮到你创造噪音了

那真是一段旅程。运动、纹理、场、粒子系统和置换——噪声都能做。它确实是创意编码世界的主力军。

很明显,你想玩噪音😁

我已经为你准备了一个小小的入门 CodePen。它旋转了一个噪声网格并将其映射到一个字形数组。只需从修改数组开始,看看你能走多远。

const glyphs = ['¤', '✳', '●', '◔', '○', '◕', '◐', '◑', '◒'];

或者,如果您正在寻找更高级的东西,请查看noisedeck.app。它就像一个只用于视觉效果的合成器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值