我有一个简单的粒子方块,我想随着鼠标的移动而移动,映射到-1到1,这样它的左下角就会粘在光标上。
这在顶点着色中相当容易,您只需将 mouse.xy 添加到 pos.xy 即可。但我想使用 GPGPU 方法来保存粒子状态并用它做一些事情。
我无法通过鼠标移动使整个方块移动并停止。如何修改我的着色器代码,以便使整个方块移动与鼠标移动同步,如下面的视频所示?
这是我的着色器代码:
void main() {
vec2 uv = vUv;
vec4 pos = texture2D( tMap, vUv );
vec2 mouse = uMouse;
vec2 targetPos = mouse + pos.xy;
float targetLen = length( mouse );
float len = distance( mouse.xy, pos.xy ); // this needs to shrink for every particle together
pos.xy += ( targetPos - pos.xy ) * .01 * len;
gl_FragColor = pos;
}
我知道我的方法是错误的,因为每一帧,
pos.xy
都会在纹理中被重写,并且我们不断向其中添加 mouse.xy。但我可以通过什么方式真正修复偏移量,以便 distance
函数不断缩小每个粒子的速度呢?
我修改了你的fiddle代码(https://jsfiddle.net/zn8sm5gx/),你现在可以看看它是否符合你的期望。
您真正想要做的是计算第
n-1
帧和第 n
帧处鼠标位置之间的增量,然后将此增量添加到着色器中的 pos
,例如:
precision highp float;
uniform float uTime;
uniform sampler2D tMap;
uniform vec2 uMouse;
uniform vec2 uLastMouse;
varying vec2 vUv;
void main() {
vec4 pos = texture2D( tMap, vUv );
vec2 moveDelta = uMouse - uLastMouse;
pos.xy += moveDelta;
gl_FragColor = pos;
}
只需将最后一帧的鼠标位置记录在一个统一变量中,并在前帧的基础上更新它。您可以通过解耦
mousemove
事件的处理并设置渲染状态来实现此目的:
// EVENTS
#events(){
this.currentMouse = new Vec2();
this.lastMouse = new Vec2();
this.mouseMoved = false;
document.addEventListener('mousemove', ( e ) => {
this.progress = 0;
this.mouseMoved = true;
this.lastMouse = this.currentMouse.clone();
this.currentMouse.x = ( e.pageX / this.gl.renderer.width ) * 2 - 1;
this.currentMouse.y = ( e.pageY / this.gl.renderer.height ) * 2 - 1;
});
}
// ANIMATE
#animate(){
// UPDATING VALUES
// this.speed = (t * 0.000007) % 1;
this.speed += .007;
if (this.mouseMoved) {
this.positionBuffer.passes[0].uniforms.uMouse.value = new Vec2( this.currentMouse.x, -this.currentMouse.y );
this.positionBuffer.passes[0].uniforms.uLastMouse.value = new Vec2( this.lastMouse.x, -this.lastMouse.y );
this.mouseMoved = false;
} else {
this.positionBuffer.passes[0].uniforms.uLastMouse.value = new Vec2( this.currentMouse.x, -this.currentMouse.y );
}
this.sourceMesh.program.uniforms.uTime.value = this.speed;
this.positionBuffer.passes[0].uniforms.uTime.value = this.speed;
this.positionBuffer.render();
this.renderer.render({ scene: this.sourceMesh.scene, camera: this.camera });
requestAnimationFrame( this.#animate.bind(this) );
}
这里
#events
重点关注更新“最后更改的鼠标位置”,并使用布尔值通知渲染例程此更改是否发生在最后一帧。