三维立体波纹效果

代码语言:html

所属分类:三维

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">

<style>
html, body {
  margin: 0;
}

canvas {
  display: block;
}
</style>

</head>
<body translate="no">
<canvas id="canvas"></canvas>

<script type="text/javascript" src="http://repo.bfw.wiki/bfwrepo/js/three.109.js"></script>
<script type="text/javascript" src="http://repo.bfw.wiki/bfwrepo/js/OrbitControls.min.js"></script>
<script>
function App() {
  const conf = {
    el: 'canvas',
    fov: 75,
    cameraZ: 100,
    background: 0xffffff };


  let renderer, scene, camera, cameraCtrl;
  let width, height, cx, cy, wWidth, wHeight;
  const { randFloat: rnd, randFloatSpread: rndFS } = THREE.Math;

  let ripple;
  let gridWWidth, gridWHeight, gridWidth, gridHeight;

  const mouse = new THREE.Vector2();
  const mousePlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
  const mousePosition = new THREE.Vector3();
  const raycaster = new THREE.Raycaster();
  let mouseOver = false;

  init();

  function init() {
    renderer = new THREE.WebGLRenderer({ canvas: document.getElementById(conf.el), antialias: true });
    // if (!renderer.extensions.get('OES_texture_float')) {
    //   alert('no floating point texture support');
    //   return;
    // }

    camera = new THREE.PerspectiveCamera(conf.fov);
    camera.position.z = conf.cameraZ;

    updateSize();
    window.addEventListener('resize', updateSize, false);

    gridWWidth = wWidth;
    gridWHeight = wHeight;
    gridWidth = gridWWidth * width / wWidth;
    gridHeight = gridWHeight * height / wHeight;
    ripple = new RippleEffect(renderer, gridWidth, gridHeight, 1 / 5);

    const getGridMP = function (e) {
      const v = new THREE.Vector3();
      camera.getWorldDirection(v);
      v.normalize();
      mouse.x = e.clientX / width * 2 - 1;
      mouse.y = -(e.clientY / height) * 2 + 1;
      raycaster.setFromCamera(mouse, camera);
      raycaster.ray.intersectPlane(mousePlane, mousePosition);
      return { x: 2 * mousePosition.x / gridWWidth, y: 2 * mousePosition.y / gridWHeight };
    };

    renderer.domElement.addEventListener('mouseleave', e => {mouseOver = false;});
    renderer.domElement.addEventListener('mousemove', e => {
      mouseOver = true;
      const gp = getGridMP(e);
      ripple.addDrop(gp.x, gp.y, 0.05, 0.1);
    });

    renderer.domElement.addEventListener('mouseup', e => {
      const gp = getGridMP(e);
      ripple.addDrop(gp.x, gp.y, 0.1, -1.5);
    });

    initScene();
    animate();
  }

  function initScene() {
    scene = new THREE.Scene();
    if (conf.background) scene.background = new THREE.Color(conf.background);

    const material = new THREE.MeshBasicMaterial({
      color: 0x0, side: THREE.DoubleSide, onBeforeCompile: shader => {
        shader.uniforms.hmap = { value: ripple.hMap.texture };
        shader.vertexShader = "uniform sampler2D hmap;\n" + shader.vertexShader;
        const token = '#include <begin_vertex>';
        const customTransform = `
          vec3 transformed = vec3(position);
          vec4 info = texture2D(hmap, uv);
          transformed.z = 20. * info.r;
        `;
        shader.vertexShader = shader.vertexShader.replace(token, customTransform);
      } });


    const pSize = 1;
    let nx = Math.round(gridWidth / 5),ny = Math.round(gridHeight / 50);
    let dy = gridWHeight / ny;
    for (let j = 0; j <= ny; j++) {
      const geometry = new THREE.PlaneBufferGeometry(gridWWidth, pSize, nx, 1);
      geometry.translate(0, -gridWHeight / 2 + j * dy, 0);
      const uvH = pSize / gridWHeight;
      const uvY = j / ny;
      const uvs = geometry.attributes.uv.array;
      for (let i = 0; i < uvs.length; i += 2) {
        uvs[i + 1] = uvs[i + 1] == 0 ? uvY - uvH : uvY + uvH;
      }
      scene.add(new THREE.Mesh(geometry, material));
    }

    nx = Math.round(gridWidth / 50);ny = Math.round(gridHeight / 5);
    let dx = gridWWidth / nx;
    for (let i = 0; i <= nx; i++) {
      const geometry = new THREE.PlaneBufferGeometry(pSize, gridWHeight, 1, ny);
      geometry.translate(-gridWWidth / 2 + i * dx, 0, 0);
      const uvW = pSize / gridWWidth;
      const uvX = i / nx;
      const uvs = geometry.attributes.uv.array;
      for (let i = 0; i < uvs.length; i += 2) {
        uvs[i] = uvs[i] == 0 ? uvX - uvW : uvX + uvW;
      }
      scene.add(new THREE.Mesh(geometry, material));
    }

    camera.position.set(0, -gridWHeight / 1.6, 40);
    camera.lookAt(new THREE.Vector3(0, -gridWHeight / 6, 0));

    cameraCtrl = new THREE.OrbitControls(camera, renderer.domElement);
    cameraCtrl.enableDamping = true;
    cameraCtrl.dampingFactor = 0.1;
    cameraCtrl.rotateSpeed = 0.5;
  }

  function animate() {
    if (!mouseOver) {
      const time = Date.now() * 0.001;
      const x = Math.cos(time) * 0.4;
      const y = Math.sin(time) * 0.4;
      ripple.addDrop(x, y, 0.05, -0.05);
    }

    ripple.update();
    renderer.render(scene, camera);
    requestAnimationFrame(animate);
  }

  function updateSize() {
    width = window.innerWidth;cx = width / 2;
    height = window.innerHeight;cy = height / 2;
    renderer.setSize(width, height);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
    const wsize = getRendere.........完整代码请登录后点击上方下载按钮下载查看

网友评论1

  1. # 61
    这个需要three支撑
    goodman 2020-02-03回复