创造性的编码者的梦想是统治他们屏幕上的像素。将它们排列成美丽的图案,并对它们做任何你想做的事。嗯,这正是我们在这个演示中要做的事情。让我们用鼠标光标的力量来扭曲和统治像素,就像了不起的无限坏蛋网站的开发者所做的那样!
设置
场景和往常一样,我们只是在屏幕上创建一个全屏图像,所以它保留了长宽比,并通过glsl着色器应用其 "背景尺寸:覆盖"。最后,我们有一个为整个视口拉伸的几何体,和一个像这样的小着色器。
vec2 newUV = (vUv - vec2(0.5))*aspect + vec2(0.5);
gl_FragColor = texture2D(uTexture,newUV);
整个东西只是显示图像,还没有扭曲。
壮观的数据纹理
我希望这时你已经知道,WebGL中的任何纹理基本上都是与每个像素的颜色相对应的数字。
Three.js有一个特定的API来逐个像素地创建你自己的纹理。不出所料,它被称为DataTexture。因此,让我们为我们的演示创建另一个纹理,用随机数字。
const size = rows * columns;
const data = new Float32Array(3 * size);
for(let i = 0; i < size; i++) {
const stride = i * 3;
let r = Math.random() * 255 ;
let r1 = Math.random() * 255 ;
data[stride] = r; // red, and also X
data[stride + 1] = r1; // green, and also Y
data[stride + 2] = 0; // blue
}
this.texture = new THREE.DataTexture(data, width, height, THREE.RGBFormat, THREE.FloatType);
这在很大程度上是基于文档中的默认例子。唯一的区别是,我们使用的是 FloatType 纹理,所以我们不受限于整数。其中一个有趣的事情是,数字应该在0到255之间,尽管在GLSL中它反正是0...1的范围。你应该记住这一点,所以你要使用正确的数字范围。
还有一个有趣的想法是,GLSL并不真正关心你的数据结构中的数字是什么意思。它既可以是color.rgb,也可以是color.xyz。而这正是我们将在这里使用的,我们并不关心这个纹理的确切颜色,我们将把它作为我们的演示的一个变形来使用只是作为GLSL的一个不错的数据结构。
但是,只是为了更好地理解,当你想预览纹理时,这就是纹理的样子。

你看到这些大的矩形是因为我选择了类似25×35的DataTexture尺寸,这是非常低的分辨率。
另外,它有颜色是因为我使用了两个不同的随机数作为XY(红-绿)变量,这导致了这个结果。
所以现在,我们已经可以在我们的片段着色器中使用这个纹理作为变形了。
vec4 color = texture2D(uTexture,newUV);
vec4 offset = texture2D(uDataTexture,vUv);
// we are distorting UVs with new texture values
gl_FragColor = texture2D(uTexture,newUV - 0.02*offset.rg);
鼠标和它的力量
那么现在,让我们把它变成动态的!我们需要一些东西。我们将需要一些东西。首先,我们需要鼠标的位置和速度。还有,鼠标的半径,也就是说,鼠标在什么距离上会扭曲我们的图像。
一个简短的解释。在动画的每一步,我将循环浏览我的网格单元,也就是DataTexture的像素。并根据鼠标的位置和速度分配一些值。第二,我将放宽扭曲的程度。这需要做的是,如果用户停止移动鼠标,失真就应该降到0。
所以,现在的代码看起来是这样的,为了更好地理解这个概念,简化了一点。
let data = DataTexture.image.data;
// loop through all the pixels of DataTexture
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
// get distance between mouse, and current DataTexture pixel
let distance = distanceBetween(mouse, [i,j])
if (distance < maxDistance) {
let index = 3 * (i + this.size * j); // get the pixel coordinate on screen
data[index] = this.mouse.vX ; // mouse speed
data[index + 1] = this.mouse.vY ; // mouse speed
}
}
// slowly move system towards 0 distortion
for (let i = 0; i < data.length; i += 3) {
data[i] *= 0.9
data[i + 1] *= 0.9
}
DataTexture.needsUpdate = true;
为了使它看起来更好,我们添加了一些东西,但概念就在这里。如果你曾经使用过粒子系统,这正是这个概念,只是我们的粒子从不移动,我们只是改变粒子的一些值(每个大像素内的扭曲)。
结果
我在最后的演示中保留了设置,所以你可以玩玩参数,想出你自己独特的动画感觉。让我知道它给了你什么创作灵感
