martinlaxenaire/react-curtains

Multiple glitches on multiple planes (video/image)

afk-mario opened this issue · 1 comments

I'm building the following website

And have some issues:

  • Sometimes the canvas won't load until I manually resize the browser window.
  • Sometimes the canvas would load but the image is distorted
    image
  • The planes seem to be out of sync with he DOM elements position a lot of the time.
  • Sometimes the plane just doesn't load the texture.

I was hoping there is something obvious I'm missing and the reason why I'm seeing all this issues, will work between today and tomorrow on building a Sandbox with the issue more complete and isolated, meanwhile here is the basic setup I have.

Here is the code I use for my planes:

import React, { useRef, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Vec2 } from 'curtainsjs';
import { Plane as BasePlane } from 'react-curtains';

import { vertexShader, fragmentShader } from 'shaders/chromatic-aberration';

import style from './style.module.css';

function Plane({ children, className, sensibility, damp, onReady }) {
  const ref = useRef();
  const isIn = useRef(false);
  const mouse = useRef(new Vec2());
  const nMouse = useRef(new Vec2());

  const uniforms = {
    time: {
      name: 'u_time',
      type: '1f',
      value: 0,
    },
    mouse: {
      // our mouse position
      name: 'u_mouse',
      type: '2f',
      value: mouse.current,
    },
  };

  useEffect(() => {
    const el = ref.current;
    const onMouseMove = (e) => {
      mouse.current.set(e.clientX, e.clientY);
      isIn.current = true;
    };

    const onTouchMove = (e) => {
      isIn.current = true;
      mouse.current.set(e.touches[0].clientX, e.touches[0].clientY);
    };

    const deactivateMouse = () => {
      isIn.current = false;
    };

    if (el) {
      el.addEventListener('mousemove', onMouseMove);
      el.addEventListener('touchmove', onTouchMove, { passive: true });
      el.addEventListener('mouseout', deactivateMouse);
      el.addEventListener('touchend', deactivateMouse);
    }

    return () => {
      if (el) {
        el.removeEventListener('mousemove', onMouseMove);
        el.removeEventListener('touchmove', onTouchMove, {
          passive: true,
        });
        el.removeEventListener('mouseenter', deactivateMouse);
        el.removeEventListener('mouseout', deactivateMouse);
        el.removeEventListener('touchend', deactivateMouse);
      }
    };
  });

  const onRender = (plane) => {
    plane.uniforms.time.value += 1;
    const mouseCoords = plane
      .mouseToPlaneCoords(mouse.current)
      .multiplyScalar(-sensibility);

    const oldX = isIn.current ? mouseCoords.x : 0;
    const oldY = isIn.current ? mouseCoords.y : 0;

    const x = nMouse.current.x + (oldX - nMouse.current.x) * damp;
    const y = nMouse.current.y + (oldY - nMouse.current.y) * damp;

    nMouse.current.set(x, y);

    // update our mouse position uniform
    plane.uniforms.mouse.value = nMouse.current;
  };

  return (
    <div
      ref={ref}
      className={`${className} ${style.wrapper} image-element-wrapper`}
    >
      <BasePlane
        className={`${style.plane} plane`}
        vertexShader={vertexShader}
        fragmentShader={fragmentShader}
        uniforms={uniforms}
        onRender={onRender}
        onReady={onReady}
      >
        {children}
      </BasePlane>
    </div>
  );
}

Plane.propTypes = {
  className: PropTypes.string,
  children: PropTypes.node.isRequired,
  sensibility: PropTypes.number,
  damp: PropTypes.number,
  onReady: PropTypes.func,
};

Plane.defaultProps = {
  className: null,
  sensibility: 0.2,
  damp: 0.2,
  onReady: () => {},
};

export default Plane;

Shader

export const vertexShader = `
	precision mediump float;

	attribute vec3 aVertexPosition;
	attribute vec2 aTextureCoord;

	uniform mat4 uMVMatrix;
	uniform mat4 uPMatrix;

	uniform mat4 uTextureMatrix0;

	varying vec3 vVertexPosition;
	varying vec2 vTextureCoord;

	void main() {
			gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);

			// varyings
			vVertexPosition = aVertexPosition;
			vTextureCoord = (uTextureMatrix0 * vec4(aTextureCoord, 0.0, 1.0)).xy;
	}
`;

export const fragmentShader = `
		precision mediump float;

		varying vec3 vVertexPosition;
		varying vec2 vTextureCoord;

		uniform sampler2D uSampler0;

		uniform float u_time;
		uniform vec2 u_mouse;

		vec2 p = u_mouse;

		void main() {
				float limit = 0.1;
				float t = u_time * 0.01;
		
				vec2 textureCoord = vTextureCoord;
				vec4 originalR = texture2D(uSampler0, (vTextureCoord) +  p * 1.0);
				vec4 originalG = texture2D(uSampler0, vTextureCoord + p * 0.6);
				vec4 originalB = texture2D(uSampler0, vTextureCoord  + p * 0.2);


				vec4 red = vec4(originalR.r, 0.0, 0.0, 1.0);
				vec4 green = vec4(0.0, originalG.g, 0.0, 1.0);
				vec4 blue = vec4(0.0, 0.0, originalB.b, 1.0);

				gl_FragColor = texture2D(uSampler0, textureCoord);
				gl_FragColor = red + green + blue;
		}
`;

Hey @afk-mario,

wow, this is a weird one!
I suspect this could be due to a CSS issue (ie the curtains container CSS is loaded after the canvas has been appended - explaining why the issue disappears after a window resize). A codesandbox would be greatly appreciated!

Cheers,