Skip to content

Commit e537d66

Browse files
Added iMouse as uniform
iMouse has normalized values [x, y, x_prev, y_prev]
1 parent 0590252 commit e537d66

File tree

8 files changed

+110
-115
lines changed

8 files changed

+110
-115
lines changed

example/src/examples/Flow.js

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,18 @@ import flow_buffer from '../shader/flow_buffer.glsl?raw';
44
import ImageLoader from "../utils/ImageLoader";
55

66
export default class Flow {
7-
constructor(wrapper, options = {}) {
8-
this.wrapper = wrapper;
7+
constructor(wrapper, options = {}) {
8+
this.wrapper = wrapper;
99

10-
this.renderer = ImageEffectRenderer.createTemporary(this.wrapper, flow_image, options);
10+
this.renderer = ImageEffectRenderer.createTemporary(this.wrapper, flow_image, options);
1111

12-
this.mouseX = 0;
13-
this.mouseY = 0;
14-
this.prevMouseX = 0;
15-
this.prevMouseY = 0;
12+
this.renderer.createBuffer(0, flow_buffer);
13+
this.renderer.buffers[0].setImage(0, this.renderer.buffers[0], {type: WebGLRenderingContext.FLOAT});
14+
this.renderer.setImage(1, this.renderer.buffers[0]);
1615

17-
this.renderer.createBuffer(0, flow_buffer);
18-
this.renderer.buffers[0].setImage(0, this.renderer.buffers[0], {type: WebGLRenderingContext.FLOAT});
19-
this.renderer.setImage(1, this.renderer.buffers[0]);
20-
21-
const canvas = this.renderer.canvas;
22-
23-
canvas.onmousedown = () => {
24-
this.mouseDown = true;
25-
};
26-
27-
canvas.onmouseenter = canvas.onmousemove = (e) => {
28-
const bounds = canvas.getBoundingClientRect();
29-
const x = Math.max(0, Math.min(1, (e.clientX - bounds.left) / bounds.width));
30-
const y = Math.max(0, Math.min(1, (e.clientY - bounds.top) / bounds.height));
31-
this.mouseX = x;
32-
this.mouseY = 1 - y;
33-
};
34-
35-
this.renderer.tick(() => {
36-
this.renderer.buffers[0].setUniformVec4('uMouse', this.mouseX, this.mouseY, this.prevMouseX, this.prevMouseY);
37-
this.prevMouseX = this.mouseX;
38-
this.prevMouseY = this.mouseY;
39-
});
40-
41-
ImageLoader.loadImages(['./paddo.jpg']).then(([mask]) => {
42-
this.renderer.setImage(0, mask, {flipY: true});
43-
this.renderer.play();
44-
});
45-
}
16+
ImageLoader.loadImages(['./paddo.jpg']).then(([mask]) => {
17+
this.renderer.setImage(0, mask, {flipY: true});
18+
this.renderer.play();
19+
});
20+
}
4621
}

example/src/examples/FluidDynamics.js

Lines changed: 37 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,68 +4,41 @@ import fluid_paint from '../shader/fluid_paint.glsl?raw';
44
import fluid_image from '../shader/fluid_image.glsl?raw';
55

66
export default class FluidDynamics {
7-
constructor(wrapper, options = {}) {
8-
this.wrapper = wrapper;
9-
10-
this.renderer = ImageEffectRenderer.createTemporary(this.wrapper, fluid_image, {loop: true, ...options});
11-
12-
this.mouseX = 0;
13-
this.mouseY = 0;
14-
this.prevMouseX = 0;
15-
this.prevMouseY = 0;
16-
17-
// fluid dynamics
18-
this.renderer.createBuffer(0, fluid_dynamics, {
19-
type: WebGLRenderingContext.FLOAT,
20-
clampX: false,
21-
clampY: false,
22-
pixelRatio: 0.5
23-
});
24-
this.renderer.createBuffer(1, fluid_dynamics, {
25-
type: WebGLRenderingContext.FLOAT,
26-
clampX: false,
27-
clampY: false,
28-
pixelRatio: 0.5
29-
});
30-
this.renderer.createBuffer(2, fluid_dynamics, {
31-
type: WebGLRenderingContext.FLOAT,
32-
clampX: false,
33-
clampY: false,
34-
pixelRatio: 0.5
35-
});
36-
37-
this.renderer.buffers[0].setImage(0, this.renderer.buffers[2]);
38-
this.renderer.buffers[1].setImage(0, this.renderer.buffers[0]);
39-
this.renderer.buffers[2].setImage(0, this.renderer.buffers[1]);
40-
41-
// fluid paint
42-
this.renderer.createBuffer(3, fluid_paint, {
43-
type: WebGLRenderingContext.FLOAT,
44-
clampX: false,
45-
clampY: false
46-
});
47-
this.renderer.buffers[3].setImage(0, this.renderer.buffers[2]);
48-
this.renderer.buffers[3].setImage(1, this.renderer.buffers[3]);
49-
50-
this.renderer.setImage(0, this.renderer.buffers[3]);
51-
52-
const canvas = this.renderer.canvas;
53-
54-
canvas.onmouseenter = canvas.onmousemove = (e) => {
55-
const bounds = canvas.getBoundingClientRect();
56-
const x = Math.max(0, Math.min(1, (e.clientX - bounds.left) / bounds.width));
57-
const y = Math.max(0, Math.min(1, (e.clientY - bounds.top) / bounds.height));
58-
this.mouseX = x;
59-
this.mouseY = 1 - y;
60-
};
61-
62-
this.renderer.tick(() => {
63-
this.renderer.buffers[0].setUniformVec4('uMouse', this.mouseX, this.mouseY, this.prevMouseX, this.prevMouseY);
64-
this.renderer.buffers[1].setUniformVec4('uMouse', this.mouseX, this.mouseY, this.prevMouseX, this.prevMouseY);
65-
this.renderer.buffers[2].setUniformVec4('uMouse', this.mouseX, this.mouseY, this.prevMouseX, this.prevMouseY);
66-
this.renderer.buffers[3].setUniformVec4('uMouse', this.mouseX, this.mouseY, this.prevMouseX, this.prevMouseY);
67-
this.prevMouseX = this.mouseX;
68-
this.prevMouseY = this.mouseY;
69-
});
70-
}
7+
constructor(wrapper, options = {}) {
8+
this.wrapper = wrapper;
9+
10+
this.renderer = ImageEffectRenderer.createTemporary(this.wrapper, fluid_image, {loop: true, ...options});
11+
12+
// fluid dynamics
13+
this.renderer.createBuffer(0, fluid_dynamics, {
14+
type: WebGLRenderingContext.FLOAT,
15+
clampX: false,
16+
clampY: false
17+
});
18+
this.renderer.createBuffer(1, fluid_dynamics, {
19+
type: WebGLRenderingContext.FLOAT,
20+
clampX: false,
21+
clampY: false
22+
});
23+
this.renderer.createBuffer(2, fluid_dynamics, {
24+
type: WebGLRenderingContext.FLOAT,
25+
clampX: false,
26+
clampY: false
27+
});
28+
29+
this.renderer.buffers[0].setImage(0, this.renderer.buffers[2]);
30+
this.renderer.buffers[1].setImage(0, this.renderer.buffers[0]);
31+
this.renderer.buffers[2].setImage(0, this.renderer.buffers[1]);
32+
33+
// fluid paint
34+
this.renderer.createBuffer(3, fluid_paint, {
35+
type: WebGLRenderingContext.FLOAT,
36+
clampX: false,
37+
clampY: false
38+
});
39+
this.renderer.buffers[3].setImage(0, this.renderer.buffers[2]);
40+
this.renderer.buffers[3].setImage(1, this.renderer.buffers[3]);
41+
42+
this.renderer.setImage(0, this.renderer.buffers[3]);
43+
}
7144
}

example/src/shader/flow_buffer.glsl

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
uniform vec4 uMouse;
2-
31
vec3 mouseInput(vec2 uv) {
4-
vec2 d = uv - uMouse.xy;
2+
vec2 d = uv - iMouse.xy;
53
d.x *= iResolution.x / iResolution.y;
6-
return vec3((uMouse.zw-uMouse.xy) * 20. * smoothstep(.2, 0., length(d)), 0);
4+
return vec3((iMouse.zw-iMouse.xy) * 20. * smoothstep(.2, 0., length(d)), 0);
75
}
86

97
void mainImage(out vec4 fragColor, in vec2 fragCoord) {

example/src/shader/fluid_dynamics.glsl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
uniform vec4 uMouse;
21
uniform float uMouseDown;
32

43
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
@@ -25,7 +24,7 @@ void mainImage(out vec4 fragColor, in vec2 fragCoord) {
2524
vec2 viscosityForce = 0.55*(tu.xy + td.xy + tr.xy + tl.xy - 4.0*me.xy);
2625
me.xyw = texture(iChannel0, uv - me.xy*(dt/iResolution.xy)).xyw;
2726

28-
vec2 externalForces = clamp(vec2(uMouse.xy - uMouse.zw) * (.4 / max(dot(uv - uMouse.xy, uv - uMouse.xy), .05)), -1., 1.);
27+
vec2 externalForces = clamp(vec2(iMouse.xy - iMouse.zw) * (.4 / max(dot(uv - iMouse.xy, uv - iMouse.xy), .05)), -1., 1.);
2928

3029
// Semi−lagrangian advection.
3130
me.xy += dt*(viscosityForce.xy + externalForces) - 0.2*DdX;

example/src/shader/fluid_paint.glsl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
uniform vec4 uMouse;
2-
uniform float uMouseDown;
3-
41
// The MIT License
52
// Copyright © 2015 Inigo Quilez
63
// https://www.shadertoy.com/view/ll2GD3
@@ -19,7 +16,7 @@ void mainImage(out vec4 fragColor, in vec2 fragCoord) {
1916

2017
vec3 newCol = pal(iTime, vec3(0.5, 0.5, 0.5), vec3(0.5, 0.5, 0.5), vec3(1.0, 1.0, 1.0), vec3(0.0, 0.10, 0.20));
2118

22-
col += newCol * 0.01*distance(uMouse.xy, uMouse.zw)/(dot(uv - uMouse.xy, uv - uMouse.xy)+0.002);
19+
col += newCol * 0.01*distance(iMouse.xy, iMouse.zw)/(dot(uv - iMouse.xy, uv - iMouse.xy)+0.002);
2320

2421
col = clamp(0.998 * col - 0.00005, 0., 5.);
2522
fragColor = vec4(col, 1.);

src/lib/MouseListener.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
let mouseX: number = -0;
2+
let mouseY: number = -0;
3+
let mouseBinded: boolean = false;
4+
5+
export function bindMouseListener(container: HTMLElement) {
6+
if (mouseBinded) {
7+
return;
8+
}
9+
mouseBinded = true;
10+
container.addEventListener('mousemove', (event) => {
11+
mouseX = event.clientX;
12+
mouseY = event.clientY;
13+
}, {passive: true});
14+
}
15+
16+
export function getMousePosition(): [number, number] {
17+
return [mouseX, mouseY];
18+
}
19+
20+
export type Rect = {
21+
left: number,
22+
top: number,
23+
width: number,
24+
height: number,
25+
}
26+
27+
export function getNormalizedMousePosition(container: Rect, mouse: [number, number]): [number, number] {
28+
const x = (mouse[0] - container.left) / container.width;
29+
const y = 1 - (mouse[1] - container.top) / container.height;
30+
return [x, y];
31+
}

src/lib/Renderer.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class Renderer {
4343

4444
public gl: WebGLInstance;
4545
protected frame: number = 0;
46-
46+
protected mouse: [number, number, number, number] = [0, 0, 0, 0];
4747
private uniforms: { [k: string]: Uniform } = {};
4848
private textures: Texture[] = [];
4949

@@ -55,6 +55,10 @@ export class Renderer {
5555
return this.program.shaderCompiled;
5656
}
5757

58+
public get iMouseUsed(): boolean {
59+
return this.program.getUniformLocation('iMouse') !== null;
60+
}
61+
5862
/**
5963
* Set an image to a slot for rendering.
6064
* Possible images can be image elements, video elements, canvas elements, or buffers.
@@ -210,6 +214,9 @@ export class Renderer {
210214
this.setUniformFloat('iAspect', width / height);
211215
this.setUniformVec2('iResolution', width, height);
212216

217+
const mouse = this.main.mouse;
218+
this.setUniformVec4('iMouse', mouse[0], mouse[1], mouse[2], mouse[3]);
219+
213220
this.gl.setUniforms(this.uniforms, this.program);
214221
this.gl.bindTextures(this.textures);
215222
this.gl.drawQuad(this.program.getAttributeLocation('aPos'), this.program.getAttributeLocation('aUV'));

src/lib/RendererInstance.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type {ImageEffectRendererOptions} from "./ImageEffectRenderer.js";
33
import {Renderer} from "./Renderer.js";
44
import {type BufferOptions, RendererBuffer} from "./RendererBuffer.js";
55
import Program from "./Program.js";
6+
import {bindMouseListener, getMousePosition, getNormalizedMousePosition} from "./MouseListener.js";
67

78
export class RendererInstance extends Renderer {
89
private static index: number = 0;
@@ -42,10 +43,10 @@ export class RendererInstance extends Renderer {
4243
this.canvas = <HTMLCanvasElement>this.gl.canvas;
4344
}
4445
Object.assign(this.canvas.style, {
45-
inset: '0',
46-
width: '100%',
47-
height: '100%',
48-
margin: '0',
46+
inset: '0',
47+
width: '100%',
48+
height: '100%',
49+
margin: '0',
4950
display: 'block',
5051
});
5152

@@ -69,6 +70,10 @@ export class RendererInstance extends Renderer {
6970
return (this.options.loop || this.drawOneFrame) && this.width > 0 && this.height > 0 && (!this.options.asyncCompile || this.allShadersCompiled);
7071
}
7172

73+
public override get iMouseUsed(): boolean {
74+
return super.iMouseUsed || this.buffers.some(buffer => buffer && buffer.iMouseUsed);
75+
}
76+
7277
private get allShadersCompiled(): boolean {
7378
return this.shaderCompiled && this.buffers.every(buffer => buffer && buffer.shaderCompiled);
7479
}
@@ -143,6 +148,12 @@ export class RendererInstance extends Renderer {
143148

144149
this.tickFuncs.forEach(func => func(dt));
145150

151+
if (this.iMouseUsed) {
152+
const xprev = this.mouse[0], yprev = this.mouse[1];
153+
const [x, y] = getNormalizedMousePosition(this.container.getBoundingClientRect(), getMousePosition());
154+
this.mouse = [x, y, xprev, yprev];
155+
}
156+
146157
// update buffers
147158
this.buffers.forEach(buffer => {
148159
if (buffer) {
@@ -164,6 +175,10 @@ export class RendererInstance extends Renderer {
164175
this._ready = true;
165176
this.readyFuncs.forEach(func => func());
166177
this.readyFuncs = [];
178+
179+
if (this.iMouseUsed) {
180+
bindMouseListener(document.body);
181+
}
167182
}
168183
}
169184
}

0 commit comments

Comments
 (0)