I am using three.js to generate a mesh based on information obtained from elements in the DOM, and then using fragment shaders to apply a ripple effect to the texture. I want the ripple effect to be applied only when the bottom edge of element A and the top edge of element B in the DOM pass by (strictly speaking, approach) the bottom edge of element A and the top edge of element B, respectively. I’m trying to do the following calculations, but I can’t get it to work, so I’d like to know how to reproduce this, either by sending information about the DOM from the JavaScript side to the shader side, or by detecting this top and bottom edge on the shader side alone.
JavaScript
const triggerTopRect = this.$elementA.getBoundingClientRect()
const rectBottom = triggerTopRect.bottom
const meshScreenY = this.windowHeight / 2 - this.mesh.position.y
this.uniforms.uRipplePos.value = 1.5 - (rectBottom / this.windowHeight)
Fragment Shader
precision highp float;
uniform vec2 uMeshSize;
uniform vec2 uTextureSize;
uniform vec2 uViewportSize;
uniform sampler2D uTexture;
uniform float uRippleStrength;
uniform float uRipplePos;
varying vec2 vUv;
float ripple(float uv, float time, float progress) {
float distance = length(((uv) + (time * 2.0)));
return tan(distance * (1.0)) * (progress * -1.85);
}
float rippleLine(float uv, float time, float progress, float multi) {
float distance = length((uv * 3.0) + (time * 1.4));
return tan(distance * (1.0)) * (multi * progress);
}
void main() {
vec2 ratio = vec2(
min((uMeshSize.x / uMeshSize.y) / (uTextureSize.x / uTextureSize.y), 1.0),
min((uMeshSize.y / uMeshSize.x) / (uTextureSize.y / uTextureSize.x), 1.0)
);
vec2 uv = vec2(
vUv.x * ratio.x + (1.0 - ratio.x) * 0.5,
vUv.y * ratio.y + (1.0 - ratio.y) * 0.5
);
float rippleLine1 = rippleLine(
uv.y,
1.0 + uRipplePos,
abs(uRipplePos),
-0.72
) * (0.1 * (1.0 - abs(uRipplePos)));
vec2 newUv = vec2(uv.x, uv.y + rippleLine1);
vec4 texture = texture2D(uTexture, newUv);
gl_FragColor = texture;
}