Vignette.js 2.31 KB
Newer Older
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
1
import React from "react";
2
import GL from "gl-react";
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
3
import { Surface } from "gl-react-native";
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
4 5 6 7 8 9 10 11 12 13 14 15 16

const shaders = GL.Shaders.create({
  imageVignette: {
    frag: `
precision highp float;
varying vec2 uv;

uniform float time;
uniform float amp;
uniform float freq;
uniform sampler2D texture;
uniform float moving;

17
uniform vec2 finger;
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
18

19
vec2 lookup (vec2 offset, float amp2) {
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
20
  return mod(
21
    uv + amp2 * amp * vec2(cos(freq*(uv.x+offset.x)+time),sin(freq*(uv.y+offset.x)+time)) + vec2(moving * time/10.0, 0.0),
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
22 23 24 25
    vec2(1.0));
}

void main() {
26 27
  float dist = distance(uv, finger);
  float amp2 = pow(1.0 - dist, 2.0);
28 29
  float colorSeparation = 0.02 * mix(amp2, 1.0, 0.5);
  vec2 orientation = vec2(1.0, 0.0);
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
30 31
  gl_FragColor = vec4(
    vec3(
32 33
    texture2D(texture, lookup(colorSeparation * orientation, amp2)).r,
    texture2D(texture, lookup(-colorSeparation * orientation, amp2)).g,
34 35
    texture2D(texture, lookup(vec2(0.0), amp2)).b),
    1.0-min(0.95, pow(1.8 * distance(uv, finger), 4.0) + 0.5 * pow(distance(fract(50.0 * uv.y), 0.5), 2.0)));
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
36 37 38 39 40
}
`
  }
});

41
class Vignette extends React.Component {
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
42
  constructor(props) {
43 44 45 46 47 48
    super(props);
    this.onResponderMove = this.onResponderMove.bind(this);
    this.state = {
      finger: [0.5, 0.5]
    };
  }
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
49
  onResponderMove(evt) {
50 51
    const { width, height } = this.props;
    const { locationX, locationY } = evt.nativeEvent;
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
52
    this.setState({ finger: [locationX / width, 1 - locationY / height] });
53 54
  }

Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
55
  render() {
56
    const { width, height, time, source } = this.props;
57
    const { finger } = this.state;
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
    return (
      <Surface
        width={width}
        height={height}
        backgroundColor="transparent"
        setZOrderOnTop
        preload
        onStartShouldSetResponder={() => true}
        onMoveShouldSetResponder={() => true}
        onLoad={() => console.log("Vignette onLoad")}
        onProgress={e => console.log("Vignette onProgress", e.nativeEvent)}
        onResponderMove={this.onResponderMove}
      >
        <GL.Node
          shader={shaders.imageVignette}
          uniforms={{
            time: time,
            freq: 10 + 2 * Math.sin(0.7 * time),
            texture: source,
            amp: 0.05 + Math.max(0, 0.03 * Math.cos(time)),
            moving: 0,
            finger: finger
          }}
        />
      </Surface>
    );
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
84 85 86 87
  }
}

module.exports = Vignette;