regl+gl-matrix实现三维立方体镜面文字动画代码

代码语言:html

所属分类:三维

代码描述:regl+gl-matrix实现三维立方体镜面文字动画代码

代码标签: regl gl-matrix 三维 立方体 镜面 文字 动画 代码

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
<style>
    html, body {
  background-color: #000;
  min-height: 100%;
}

canvas {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.dribbble {
  position: fixed;
  display: block;
  right: 20px;
  bottom: 20px;
}
.dribbble img {
  display: block;
  height: 28px;
}

.twitter {
  position: fixed;
  display: block;
  right: 64px;
  bottom: 14px;
}
.twitter svg {
  width: 32px;
  height: 32px;
  fill: #1da1f2;
}
</style>

</head>

<body>

        <canvas class="canvas" width="500" height="500"></canvas>


    <!-- dribbble - twitter -->
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/regl.min.js"></script>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/gl-matrix-min.js"></script>
    <script >
        
        const cubeCanvas = document.querySelector(".canvas");

const regl = createREGL({
  canvas: cubeCanvas,
  attributes: {
    antialias: true,
    alpha: false,
  },
});

let tick;

const play = (action) => {
  if (!tick) {
    tick = regl.frame(action);
  }
};

const stop = () => {
  if (tick) {
    tick.cancel();
    tick = null;
  }
};

const Texture = (regl, src) => {
  const texture = regl.texture();

  const image = new Image();

  image.src = src;

  image.onload = function () {
    texture({
      data: image,
      flipY: true,
      min: "mipmap",
    });
  };

  return texture;
};

const emptyTexture = regl.texture();

const CONTENT_CONFIG = {
  translateX: 0,
  translateY: 0,
  translateZ: 0,
  rotation: 0,
  rotateX: 1,
  rotateY: 1,
  rotateZ: 1,
  scale: 1,
};

const contentDraw = regl({
  frag: `
    precision mediump float;
    #define GLSLIFY 1
    
    uniform vec2 u_resolution;
    uniform sampler2D u_texture;
    uniform int u_maskId;
    uniform int u_typeId;
    uniform sampler2D u_displacement;
    uniform sampler2D u_mask;
    uniform float u_tick;
    
    varying vec2 v_uv;
    
    const float PI2 = 6.283185307179586;
    
    const float PI = 3.141592653589793;
    const float PI2_0 = 6.28318530718;
    
    mat2 scale(vec2 value) {
      return mat2(value.x, 0.0, 0.0, value.y);
    }
    
    mat2 rotate2d(float value){
      return mat2(cos(value), -sin(value), sin(value), cos(value));
    }
    
    vec3 gradient1(vec2 st, float tick) {
      vec3 c1 = vec3(253.0/255.0, 142.0/255.0,  98.0/255.0);
      vec3 c2 = vec3(251.0/255.0,  83.0/255.0, 184.0/255.0);
      vec3 c3 = c2;
      vec3 c4 = vec3( 57.0/255.0,  15.0/255.0, 248.0/255.0);
    
      st.y = 1.0 - st.y;
    
      vec2 toCenter = vec2(0.55, 0.58) - st;
      float angle = atan(toCenter.y, toCenter.x) / PI;
    
      vec3 colorA = mix(c1, c2, smoothstep(0.0, 0.5, angle));
    
      st -= vec2(0.5);
      st *= scale(vec2(1.4));
      st *= rotate2d(-1.44);
      st += vec2(0.5);
    
      vec3 colorB = mix(c2, c3, smoothstep(0.3, 0.8, st.x));
      colorB = mix(colorB, c4, smoothstep(0.55, 1.0, st.x));
    
      return mix(colorA, colorB, smoothstep(0.28, 0.65, st.x));
    }
    
    vec3 gradient2(vec2 st, float tick) {
      vec3 c1 = vec3(1.0, 0.8, 0.2);
      vec3 c2 = vec3(0.92, 0.20, 0.14);
    
      st -= vec2(0.5);
      st *= scale(vec2(3.8));
      st *= rotate2d(tick * PI);
      st += vec2(0.5);
    
      return mix(c1, c2, st.x);
    }
    
    vec3 gradient3(vec2 st, float tick) {
      vec3 c1 = vec3(229.0/255.0, 255.0/255.0, 196.0/255.0);
      vec3 c2 = vec3(200.0/255.0, 255.0/255.0, 224.0/255.0);
      vec3 c3 = vec3(180.0/255.0, 255.0/255.0, 245.0/255.0);
      vec3 c4 = vec3(203.0/255.0, 223.0/255.0, 255.0/255.0);
      vec3 c5 = vec3(233.0/255.0, 201.0/255.0, 255.0/255.0);
    
      st -= vec2(0.5);
      st *= scale(vec2(1.2));
      st *= rotate2d(tick * (PI / 2.5));
      st += vec2(0.5);
    
      vec3 colorB = mix(c1, c2, smoothstep(0.0, 0.25, st.x));
      colorB = mix(colorB, c3, smoothstep(0.25, 0.5, st.x));
      colorB = mix(colorB, c4, smoothstep(0.5, 0.75, st.x));
      colorB = mix(colorB, c5, smoothstep(0.75, 1.0, st.x));
    
      return colorB;
    }
    
    vec3 gradients(int type, vec2 st, float tick) {
      if (type == 1) {
        return gradient1(st, tick);
      } else if (type == 2) {
        return gradient2(st, tick);
      } else if (type == 3) {
        return gradient3(st, tick);
      }
    }
    
    void main() {
      vec2 st = gl_FragCoord.xy / u_resolution;
    
      vec4 displacement = texture2D(u_displacement, st);
      
      vec2 direction = vec2(cos(displacement.r * PI2), sin(displacement.r * PI2));
      float length = displacement.g;
    
      vec2 newUv = v_uv;
    
      newUv.x += (length * 0.07) * direction.x;
      newUv.y += (length * 0.07) * direction.y;
    
      vec4 texture = texture2D(u_texture, newUv);
      float tick = u_tick * 0.009;
    
      vec3 color = gradients(u_typeId, v_uv, tick);
    
      texture.rgb = color + (texture.rgb * color);
    
      vec4 mask = texture2D(u_mask, st);
    
      int maskId = int(mask.r * 4.0 + mask.g * 2.0 + mask.b * 1.0);
    
      if (maskId == u_maskId) {
        gl_FragColor = vec4(texture.rgb, texture.a * mask.a);
      } else {
        discard;
      }
    }
  `,
  vert: `
    precision mediump float;
    #define GLSLIFY 1

    attribute vec3 a_position;
    attribute vec2 a_uv;

    uniform mat4 u_projection;
    uniform mat4 u_view;
    uniform mat4 u_world;

    varying vec2 v_uv;

    void main() {
      v_uv = a_uv;

      gl_Position = u_projection * u_view * u_world * vec4(a_position, 1);
    }
  `,
  attributes: {
    a_position: [
      [-1, -1, 0],
      [1, -1, 0],
      [1, 1, 0],
      [-1, 1, 0],
    ],
    a_uv: [
      [0, 0],
      [1, 0],
      [1, 1],
      [0, 1],
    ],
  },
  uniforms: {
    u_texture: regl.prop("texture"),
    u_typeId: regl.prop("typeId"),
    u_maskId: regl.prop("maskId"),
  },
  depth: {
    enable: true,
    mask: false,
    func: "less",
  },
  blend: {
    enable: true,
    func: {
      srcRGB: "src alpha",
      srcAlpha: 1,
      dstRGB: "one minus src alpha",
      dstAlpha: 1,
    },
    equation: {
      rgb: "add",
      alpha: "add",
    },
    color: [0, 0, 0, 0],
  },
  elements: [0, 1, 2, 0, 2, 3],
  count: 6,
});

const contentSetup = regl({
  context: {
    world: () => {
      const {
        translateX,
        translateY,
        translateZ,
        rotation,
        rotateX,
        rotateY,
        rotateZ,
        scale,
      } = CONTENT_CONFIG;

      const world = mat4.create();

      mat4.translate(world, world, [translateX, translateY, translateZ]);
      mat4.rotate(world, world, rotation, [rotateX, rotateY, rotateZ]);
      mat4.scale(world, world, [scale, scale, scale]);

      return world;
    },
    mask: (context, { mask }) => {
      return mask || emptyTexture;
    },
    displacement: (context, { displacement }) => {
      return displacement || emptyTexture;
    },
  },
  uniforms: {
    u_world: regl.context("world"),
    u_mask: regl.context("mask"),
    u_displacement: regl.context("displacement"),
    u_tick: regl.context("tick"),
  },
});

const content = (props) => {
  contentSetup(props, (context, { textures }) => {
    regl.clear({
      color: [0, 0, 0, 0],
      depth: 1,
    });

    contentDraw(textures);
  });
};

const ContentTypes = {
  GRADIENT: 1,
  RED: 2,
  BLUE: 3,
};

const emptyCube = regl.cube();

const CUBE_CONFIG = {
  translateX: 0,
  translateY: 0,
  translateZ: 0,
  rotation: 0,
  rotateX: 1,
  rotateY: 1,
  rotateZ: 1,
  scale: 1,
  borderWidth: 0.008,
  displacementLength: 0.028,
  reflectionOpacity: 0.3,
  scene: 3,
};

const cube = regl({
  frag: `
    precision mediump float;
    #define GLSLIFY 1
    
    uniform vec2 u_resolution;
    uniform int u_face;
    uniform int u_typeId;
    uniform sampler2D u_texture;
    uniform samplerCube u_reflection;
    uniform float u_tick;
    uniform float u_borderWidth;
    uniform float u_displacementLength;
    uniform float u_reflectionOpacity;
    uniform int u_scene;
    
    varying vec3 v_normal;
    varying vec3 v_center;
    varying vec3 v_point;
    varying vec2 v_uv;
    varying vec3 v_color;
    varying float v_depth;
    
    const float PI2 = 6.283185307179586;
    
    float borders(vec2 uv, float strokeWidth) {
      vec2 borderBottomLeft = smoothstep(vec2(0.0), vec2(strokeWidth), uv);

      vec2 borderTopRight = smoothstep(vec2(0.0), vec2(strokeWidth), 1.0 - uv);
    
      return 1.0 - borderBottomLeft.x * borderBottomLeft.y * borderTopRight.x * borderTopRight.y;
    }
    
    const float PI2_0 = 6.28318530718;
    
    vec4 radialRainbow(vec2 st, float tick) {
      vec2 toCenter = vec2(0.5) - st;
      float angle = mod((atan(toCenter.y, toCenter.x) / PI2_0) + 0.5 + sin(tick * 0.002), 1.0);
    
      // colors
      vec4 c1 = vec4(229.0/255.0, 255.0/255.0, 196.0/255.0, 1.0);
      vec4 c2 = vec4(200.0/255.0, 255.0/255.0, 224.0/255.0, 1.0);
      vec4 c3 = vec4(180.0/255.0, 255.0/255.0, 245.0/255.0, 1.0);
      vec4 c4 = vec4(203.0/255.0, 223.0/255.0, 255.0/255.0, 1.0);
      vec4 c5 = vec4(233.0/255.0, 201.0/255.0, 255.0/255.0, 1.0);
      // vec4 a = vec4(0.43, 0.48, 0.95, 1.0);
      // vec4 b = vec4(0.94, 0.79, 0.41, 1.0);
      // // vec4 b = vec4(0.49, 0.88, 1.00, 1.0);
      // vec4 c = vec4(0.68, 0.29, 0.68, 1.0);
      // vec4 d = vec4(0.94, 0.79, 0.41, 1.0);
      // vec4 e = vec4(0.43, 0.48, 0.95, 1.0);
    
      float step = 1.0 / 10.0;
    
      vec4 color = c1;
    
      color = mix(color, c2, smoothstep(step * 1.0, step * 2.0, angle));
      color = mix(color, c1, smoothstep(step * 2.0, step * 3.0, angle));
      color = mix(color, c2, smoothstep(step * 3.0, step * 4.0, angle));
      color = mix(color, c3, smoothstep(step * 4.0, step * 5.0, angle));
      color = mix(color, c4, smoothstep(step * 5.0, step * 6.0, angle));
      color = mix(color, c3, smoothstep(step * 6.0, step * 7.0, angle));
      color = mix(color, c4, smoothstep(step * 7.0, step * 8.0, angle));
      color = mix(color, c5, smoothstep(step * 8.0, step * 9.0, angle));
      color = mix(color, c1, smoothstep(step * 9.0, step * 10.0, angle));
    
      return color;
    }
    
    mat2 scale(vec2 value){
      return mat2(value.x, 0.0, 0.0, value.y);
    }
    
    mat2 rotate2d(float value){
      return mat2(cos(value), -sin(value), sin(value), cos(value));
    }
    
    vec2 rotateUV(vec2 uv, float rotation) {
      float mid = 0.5;
      return vec2(
        cos(rotation) * (uv.x - mid) + sin(rotation) * (uv.y - mid) + mid,
        cos(rotation) * (uv.y - mid) - sin(rotation) * (uv.x - mid) + mid
      );
    }
    
    vec4 type1() {
      vec2 toCenter = v_center.xy - v_point.xy;
      float angle = (atan(toCenter.y, toCenter.x) / PI2) + 0.5;
      float displacement = borders(v_uv, u_displacementLength) + borders(v_uv, u_displacementLength * 2.143) * 0.3;
    
      return vec4(angle, displacement, 0.0, 1.0);
    }
    
    vec4 type2() {
      return vec4(v_color, 1.0);
    }
    
    vec4 type3() {
      vec2 st = gl_FragCoord.xy / u_resolution;
    
      vec4 strokeColor = radialRainbow(st, u_tick);
      float depth = clamp(smoothstep(-1.0, 1.0, v_depth), 0.6, 0.9);
      vec4 stroke = strokeColor * vec4(borders(v_uv, u_borderWidth)) * depth;
    
      vec4 texture;
    
      if (u_face == -1) {
        vec3 normal = normalize(v_normal);
        texture = textureCube(u_reflection, normalize(v_normal));
    
        texture.a *= u_reflectionOpacity * depth;
      }  else {
        texture = texture2D(u_texture, st);
      }
    
      if (stroke.a > 0.0) {
        return stroke - texture.a;
      } else {
        return texture;
      }
    }
    
    vec4 switchScene(int id) {
      if (id == 1) {
        return type1();
      } else if (id == 2) {
        return type2();
      } else if (id == 3) {
        return type3();
      }
    }
    
    void main() {
      if (u_scene == 3) {
        gl_FragColor = switchScene(u_typeId);
      } else {
        gl_FragColor = switchScene(u_scene);
      }
    }
  `,
  vert: `
    precision mediump float;
    #define GLSLIFY 1
    
    attribute vec3 a_position;
    attribute vec3 a_center;
    attribute vec2 a_uv;
    attribute vec3 a_color;
    
    uniform mat4 u_projection;
    uniform mat4 u_view;
    uniform mat4 u_world;
    
    varying vec3 v_normal;
    varying vec3 v_center;
    varying vec3 v_point;
    varying vec2 v_uv;
    varying vec3 v_color;
    varying float v_depth;
    
    void main() {
      vec4 center = u_projection * u_view * u_world * vec4(a_center, 1.0);
      vec4 position = u_projection * u_view * u_world * vec4(a_position, 1.0);
    
      v_normal = normalize(a_position);
      v_center = center.xyz;
      v_point = position.xyz;
      v_uv = a_uv;
      v_color = a_color;
      v_depth = (mat3(u_view) * mat3(u_world) * a_position).z;
    
      gl_Position = position;
    }
  `,
  context: {
    world: (context, { matrix }) => {
      const {
        translateX,
        translateY,
        translateZ,
        rotation,
        rotateX,
        rotateY,
        rotateZ,
        scale,
      } = CUBE_CONFIG;

      const world = mat4.create();

      mat4.translate(world, world, [translateX, translateY, translateZ]);
      mat4.rotate(world, world, rotation, [rotateX, rotateY, rotateZ]);
      mat4.scale(world, world, [scale, scale, scale]);

      if (matrix) {
        mat4.multiply(world, world, matrix);
      }

      return world;
    },
    face: (context, { cullFace }) => {
      return cullFace === CubeFaces.FRONT ? -1 : 1;
    },
    texture: (context, { texture }) => {
      return texture || emptyTexture;
    },
    reflection: (context, { reflection }) => {
      return reflection || emptyCube;
    },
    textureMatrix: (context, { textureMatrix }) => {
      return textureMatrix;
    },
    borderWidth: () => {
      const { borderWidth } = CUBE_CONFIG;

      return borderWidth;
    },
    displacementLength: () => {
      const { displacementLength } = CUBE_CONFIG;

      return displacementLength;
    },
    reflectionOpacity: () => {
      const { reflectionOpacity } = CUBE_CONFIG;

      return reflectionOpacity;
    },
    scene: () => {
      const { scene } = CUBE_CONFIG;

      return parseFloat(scene);
    },
  },
  attributes: {
    a_position: [
      [-1, +1, +1],
      [+1, +1, +1],
      [+1, -1, +1],
      [-1, -1, +1], // front face
      [+1, +1, +1],
      [+1, +1, -1],
      [+1, -1, -1],
      [+1, -1, +1], // right face
      [+1, +1, -1],
      [-1, +1, -1],
      [-1, -1, -1],
      [+1, -1, -1], // back face
      [-1, +1, -1],
      [-1, +1, +1],
      [-1, -1, +1],
      [-1, -1, -1], // left face
      [-1, +1, -1],
      [+1, +1, -1],
      [+1, +1, +1],
      [-1, +1, +1], // top face
      [-1, -1, -1],
      [+1, -1, -1],
      [+1, -1, +1],
      [-1, -1, +1], // bottom face
    ],
    a_center: [
      [0, 0, 1], // front face
      [1, 0, 0], // right face
      [0, 0, -1], // back face
      [-1, 0, 0], // left face
      [0, 1, 0], // top face
      [0, -1, 0], // bottom face
    ].map((c) => {
      return [c, c, c, c];
    }),
    a_uv: [
      [0, 0],
      [1, 0],
      [1, 1],
      [0, 1], // front face
      [0, 0],
      [1, 0],
      [1, 1],
      [0, 1], // right face
      [0, 0],
      [1, 0],
      [1, 1],
      [0, 1], // back face
      [0, 0],
      [1, 0],
      [1, 1],
      [0, 1], // left face
      [0, 0],
      [1, 0],
      [1, 1],
      [0, 1], // top face
      [0, 0],
      [1, 0],
      [1, 1],
      [0, 1], // bottom face
    ],
    a_color: [
      [0, 1, 0], // front face => mask 2
      [0, 0, 1], // right face => mask 1
      [1, 0, 0], // back face => mask 4
      [1, 1, 0], // left face => mask 6
      [1, 0, 1], // top face => mask 5
      [0, 1, 1], // bottom face => mask 3
    ].map((c) => {
      return [c, c, c, c];
    }),
  },
  uniforms: {
    u_world: regl.context("world"),
    u_face: regl.context("face"),
    u_typeId: regl.prop("typeId"),
    u_texture: regl.context("texture"),
    u_reflection: regl.context("reflection"),
    u_tick: regl.context("tick"),
    u_borderWidth: regl.context("borderWidth"),
    u_displacementLength: regl.context("displacementLength"),
    u_reflectionOpacity: regl.context("reflectionOpacity"),
    u_scene: regl.context("scene"),
  },
  cull: {
    enable: true,
    face: regl.prop("cullFace"),
  },
  depth: {
    enable: true,
    mask: false,
    func: "less",
  },
  blend: {
    enable: true,
    func: {
      srcRGB: "src alpha",
      srcAlpha: 1,
      dstRGB: "one minus src alpha",
      dstAlpha: 1,
    },
    equation: {
      rgb: "add",
      alpha: "add",
    },
    color: [0, 0, 0, 0],
  },
  elements: [
    [2, 1, 0],
    [2, 0, 3], // front face
    [6, 5, 4],
    [6, 4, 7], // right face
    [10, 9, 8],
    [10, 8, 11], // back face
    [14, 13, 12],
    [14, 12, 15], // left face
    [18, 17, 16],
    [18, 16, 19], // top face
    [20, 21, 22],
    [23, 20, 22], // bottom face
  ],
  count: 36,
  framebuffer: regl.prop("fbo"),
});

const CubeTypes = {
  DISPLACEMENT: 1,
  MASK: 2,
  FINAL: 3,
};

const CubeFaces = {
  BACK: "back",
  FRONT: "front",
};

const CubeMasks = {
  M1: 1,
  M2: 2,
  M3: 3,
  M4: 4,
  M5: 5,
  M6: 6,
};

const CAMERA_CONFIG = {
  fov: 35,
  near: 0.01,
  far: 1000,
};

const cameraConfig = {
  eye: [0, 0, 6],
  target: [0, 0, 0],
  up: [0, 1, 0],
};

const camera = regl({
  context: {
    projection: ({ viewportWidth, viewportHeight }) => {
      const { fov, near, far } = CAMERA_CONFIG;
      const fovy = (fov * Math.PI) / 180;
      const aspect = viewportWidth / viewportHeight;

      return mat4.perspective([], fovy, aspect, near, far);
    },

    view: (context, props) => {
      const config = Object.assign({}, cameraConfig, props);

      const { eye, target, up } = config;

      return mat4.lookAt([], eye, target, up);
    },

    fov: () => {
      const { fov } = CAMERA_CONFIG;

      return fov;
    },
  },

  uniforms: {
    u_projection: regl.context("projection"),
    u_view: regl.context("view"),
    u_cameraPosition: regl.context("eye"),
    u_resolution: ({ viewportWidth, viewportHeight }) => {
      return [viewportWidth, viewportHeight];
    },
  },
});

const plane = regl({
  vert: `
    precision mediump float;
    #define GLSLIFY 1
    
    uniform sampler2D u_texture;
    
    varying vec4 vUv;
    
    void main() {
      gl_FragColor = texture2DProj(u_texture, vUv);
    }
  `,
  frag: `
    precision mediump float;
    #define GLSLIFY 1

    attribute vec3 a_position;
    
    uniform mat4 u_textureMatrix;
    uniform mat4 u_world;

    varying vec4 vUv;

    void main() {
      vUv = u_textureMatrix * vec4(a_position, 1.0);

      gl_Position = u_world * vec4(a_position, 1.0);
    }
  `,
  attributes: {
    a_position: [
      [-1, 1, 0],
      [1, -1, 0],
      [-1, -1, 0],
      [-1, 1, 0],
      [1, 1, 0],
      [1, -1, 0],
    ],
  },
  context: {
    world: (context, { uvRotation }) => {
      const world = mat4.create();

      mat4.rotate(world, world, uvRotation, [0, 0, 1]);

      return world;
    },
  },
  uniforms: {
    u_world: regl.context("world"),
    u_texture: regl.prop("texture"),
    u_textureMatrix: regl.prop("textureMatrix"),
  },
  count: 6,
});

const reflector = regl({
  frag: `
    precision mediump float;
    #define GLSLIFY 1
    
    uniform vec2 u_resolution;
    uniform sampler2D u_texture;
    uniform float u_depthOpacity;
    
    varying vec2 v_uv;
    varying float v_z;
    
    mat2 scale(vec2 scale){
      return mat2(scale.x, 0.0, 0.0, scale.y);
    }
    
    void main() {
      vec2 st = gl_FragCoord.xy / u_resolution;
    
      vec4 texture = texture2D(u_texture, v_uv);

      texture.a -= u_depthOpacity * v_z;
    
      gl_FragColor = texture;
    }
  `,
  vert: `
    precision mediump float;
    #define GLSLIFY 1
    
    attribute vec3 a_position;
    attribute vec2 a_uv;
    
    uniform mat4 u_projection;
    uniform mat4 u_view;
    uniform mat4 u_world;
    uniform vec2 u_viewport;
    
    varying vec2 v_uv;
    varying float v_z;
    
    void main() {
      v_uv = a_uv;
      v_z = 1.0 - (mat3(u_view) * mat3(u_world) * a_position).z;
    
      gl_Position = u_projection * u_view * u_world * vec4(a_position, 1);
    }
  `,
  context: {
    world: (
      { viewportWidth, viewportHeight },
      { cameraConfig: mainCameraConfig, fov }
    ) => {
      const fovy = (fov * Math.PI) / 180;
      const aspect = viewportWidth / viewportHeight;
      const cameraHeight = Math.tan(fovy / 2) * mainCameraConfig.eye[2];
      const cameraWidth = cameraHeight * aspect;

      const world = mat4.create();

      mat4.scale(world, world, [cameraWidth, cameraHeight, 1.0]);

      return world;
    },
    depthOpacity: () => {
      const depthOpacity = 0.75;

      return depthOpacity;
    },
  },
  attributes: {
    a_position: [
      [-1, -1, 0],
      [1, -1, 0],
      [1, 1, 0],
      [-1, 1, 0],
    ],
    a_uv: [
      [0, 0],
      [1, 0],
      [1, 1],
      [0, 1],
    ],
  },
  uniforms: {
    u_world: regl.context("world"),
    u_texture: regl.prop("texture"),
    u_depthOpacity: regl.context("depthOpacity"),
  },
  depth: {
    enable: true,
    mask: false,
    func: "less",
  },
  blend: {
    enable: true,
    func: {
      srcRGB: "src alpha",
      srcAlpha: 1,
      dstRGB: "one minus src alpha",
      dstAlpha: 1,
    },
    equation: {
      rgb: "add",
      alpha: "add",
    },
    color: [0, 0, 0, 0],
  },
  elements: [0, 1, 2, 0, 2, 3],
  count: 6,
});

const planes = [
  {
    position: [1, 0, 0],
    normal: [1, 0, 0],
    rotation: -Math.PI * 0.5,
    axis: [0, 1, 0],
    uvRotation: Math.PI,
  },
  {
    position: [-1, 0, 0],
    normal: [-1, 0, 0],
    rotation: Math.PI * 0.5,
    axis: [0, 1, 0],
    uvRotation: Math.PI,
  },
  {
    position: [0, 1, 0],
    normal: [0, 1, 0],
    rotation: Math.PI * 0.5,
    axis: [1, 0, 0],
    uvRotation: 0,
  },
  {
    position: [0, -1, 0],
    normal: [0, -1, 0],
    rotation: -Math.PI * 0.5,
    axis: [1, 0, 0],
    uvRotation: 0,
  },
  {
    position: [0, 0, 1],
    normal: [0, 0, 1],
    rotation: Math.PI,
    axis: [0, 1, 0],
    uvRotation: Math.PI,
  },
  {
    position: [0, 0, -1],
    normal: [0, 0, -1],
    rotation: 0,
    axis: [0, 1, 0],
    uvRotation: Math.PI,
  },
];

const renderTarget = regl.framebuffer();

const reflect = (a, b) => {
  const dot2 = new Array(3);

  dot2.fill(2 * vec3.dot(b, a));

  return vec3.sub([], a, vec3.mul([], dot2, b));
};

const reflectionSetup = regl({
  context: {
    config: (
      context,
      { cameraConfig: mainCameraConfig, rotationMatrix },
      batchId
    ) => {
      const { position, normal, rotation, axis } = planes[batchId];

      const planeMatrix = mat4.translate([], rotationMatrix, position);
      const normalMatrix = mat4.translate([], rotationMatrix, normal);

      mat4.rotate(planeMatrix, planeMatrix, rotation, axis);

      const planeWorldPosition = mat4.getTranslation([], planeMatrix);
      const planeWorldNormal = mat4.getTranslation([], normalMatrix);
      const cameraWorldPosition = mainCameraConfig.eye;

      let eye = [0, 0, 0];
      vec3.sub(eye, planeWorldPosition, cameraWorldPosition);
      eye = reflect(eye, planeWorldNormal);
      vec3.negate(eye, eye);
      vec3.add(eye, eye, planeWorldPosition);

      const lookAtPosition = [0, 0, -1];
      vec3.add(lookAtPosition, lookAtPosition, cameraWorldPosition);

      let target = [0, 0, 0];
      vec3.sub(target, planeWorldPosition, lookAtPosition);
      target = reflect(target, planeWorldNormal);
      vec3.negate(target, target);
      vec3.add(target, target, planeWorldPosition);

      let up = [0, 1, 0];
      up = reflect(up, planeWorldNormal);

      const cameraConfig = {
        eye,
        target,
        up,
      };

      return {
        cameraConfig,
        planeMatrix,
      };
    },
    uvRotation: (context, props, batchId) => {
      const { uvRotation } = planes[batchId];

      return uvRotation;
    },
    faceFbo: (context, { reflectionFbo }, batchId) => {
      return reflectionFbo.faces[batchId];
    },
  },
});

const reflection = ({
  reflectionFbo,
  cameraConfig,
  rotationMatrix,
  texture,
}) => {
  const props = new Array(6);

  props.fill({
    reflectionFbo,
    cameraConfig,
    rotationMatrix,
  });

  reflectionSetup(
    props,
    ({ viewportWidth, viewportHeight, config, uvRotation, faceFbo }) => {
      const textureMatrix = mat4.fromValues(
        0.5,
        0,
        0,
        0,
        0,
        0.5,
        0,
        0,
        0,
        0,
        0.5,
        0,
        0.5,
        0.5,
        0.5,
        1
      );

      renderTarget.resize(viewportWidth, viewportHeight);

      renderTarget.use(() => {
        regl.clear({
          color: [0, 0, 0, 0],
          depth: 1,
        });

        camera(config.cameraConfig, ({ projection, view, fov }) => {
          mat4.multiply(textureMatrix, textureMatrix, projection);
          mat4.mul(textureMatrix, textureMatrix, view);
          mat4.mul(textureMatrix, textureMatrix, config.planeMatrix);

          reflector({
            texture,
            cameraConfig,
            fov,
          });
        });
      });

      faceFbo.use(() => {
        regl.clear({
          color: [0, 0, 0, 0],
          depth: 1,
        });

        plane({
          texture: renderTarget,
          textureMatrix,
          uvRotation,
        });
      });
    }
  );
};

const CONFIG = {
  cameraX: 0,
  cameraY: 0,
  cameraZ: 5.7,
  rotation: 4.8,
  rotateX: 1,
  rotateY: 1,
  rotateZ: 1,
  velocity: 0.005,
};

/**
 * Fbos
 */
const displacementFbo = regl.framebuffer();
const maskFbo = regl.framebuffer();
const contentFbo = regl.framebuffer();
const reflectionFbo = regl.framebufferCube(1024);

/**
 * Textures
 */
const availableTextures = {
  ["slide1"]: Texture(
    regl,
    "data:image/png;base64,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.........完整代码请登录后点击上方下载按钮下载查看

网友评论0