基于three.js生成动态波浪背景效果


前言

基于three.js生成动态波浪背景效果
在这里插入图片描述


一、安装three

npm i three -S

二、新建waves.js文件

注意geometry.setAttributegeometry.addAttribute和在不同版本会报错,切换其他一个即可兼容

import * as THREE from 'three';

var SEPARATION = 100,
  AMOUNTX = 50,
  AMOUNTY = 50;
var container;
var camera, scene, renderer;
var particles,
  count = 0;
var mouseX = 0,
  mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

function init(id) {
  container = document.querySelector('#' + id) || document.createElement('div');
  camera = new THREE.PerspectiveCamera(100, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.y = 600;
  camera.position.z = 1200;
  scene = new THREE.Scene();
  //
  var numParticles = AMOUNTX * AMOUNTY;
  var positions = new Float32Array(numParticles * 3);
  var scales = new Float32Array(numParticles);
  var i = 0,
    j = 0;
  for (var ix = 0; ix < AMOUNTX; ix++) {
    for (var iy = 0; iy < AMOUNTY; iy++) {
      positions[i] = ix * SEPARATION - (AMOUNTX * SEPARATION) / 2; // x
      positions[i + 1] = 0; // y
      positions[i + 2] = iy * SEPARATION - (AMOUNTY * SEPARATION) / 2; // z
      scales[j] = 1;
      i += 3;
      j++;
    }
  }
  var geometry = new THREE.BufferGeometry();
  console.log('geometry_geometry', geometry)
  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute('scale', new THREE.BufferAttribute(scales, 1));
  var material = new THREE.ShaderMaterial({
    uniforms: {
      color: { value: new THREE.Color('rgb(182, 232, 255)') },
    },
    // vertexShader: document.getElementById('vertexshader').textContent,
    // fragmentShader: document.getElementById('fragmentshader').textContent,
    vertexShader: `
    attribute float scale;
      void main() {
        vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
        gl_PointSize = scale * ( 300.0 / - mvPosition.z );
        gl_Position = projectionMatrix * mvPosition;
      }`,
    fragmentShader: `
    uniform vec3 color;
      void main() {
        if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard;
        gl_FragColor = vec4( color, 1.0 );
      }`,
    alphaTest: 0.5,
  });
  //
  particles = new THREE.Points(geometry, material);
  scene.add(particles);
  //
  renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight >> 1);
  container.appendChild(renderer.domElement);

  document.addEventListener('mousemove', onDocumentMouseMove, false);
  document.addEventListener('touchstart', onDocumentTouchStart, false);
  document.addEventListener('touchmove', onDocumentTouchMove, false);
  //
  window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight >> 1);
}
//
function onDocumentMouseMove(event) {
  mouseX = event.clientX - windowHalfX;
  mouseY = event.clientY - windowHalfY;
}
function onDocumentTouchStart(event) {
  if (event.touches.length === 1) {
    event.preventDefault();
    mouseX = event.touches[0].pageX - windowHalfX;
    mouseY = event.touches[0].pageY - windowHalfY;
  }
}
function onDocumentTouchMove(event) {
  if (event.touches.length === 1) {
    event.preventDefault();
    mouseX = event.touches[0].pageX - windowHalfX;
    mouseY = event.touches[0].pageY - windowHalfY;
  }
}
//
function animate() {
  requestAnimationFrame(animate);
  render();
}
function render() {
  var cy = (-mouseY - camera.position.y) * 0.01;
  camera.position.x += (mouseX - camera.position.x) * 0.02;
  // camera.position.y += (-mouseY - camera.position.y) * 0.01;
  // camera.position.y += cy < -1 ? -1 : cy;
  camera.lookAt(scene.position);
  var positions = particles.geometry.attributes.position.array;
  var scales = particles.geometry.attributes.scale.array;
  var i = 0,
    j = 0;
  for (var ix = 0; ix < AMOUNTX; ix++) {
    for (var iy = 0; iy < AMOUNTY; iy++) {
      positions[i + 1] = Math.sin((ix + count) * 0.3) * 100 + Math.sin((iy + count) * 0.5) * 100;
      scales[j] = (Math.sin((ix + count) * 0.3) + 1) * 5 + (Math.sin((iy + count) * 0.5) + 1) * 5;
      i += 3;
      j++;
    }
  }
  particles.geometry.attributes.position.needsUpdate = true;
  particles.geometry.attributes.scale.needsUpdate = true;
  renderer.render(scene, camera);
  count += 0.1;
}

export default function threeWaves(id) {
  init(id);
  animate();
}

三、引入waves.js文件比查看效果

  • components/waves/index.vue
<script lang="ts" src="./index.ts" />

<template>
  <div class="login flex-align-center">
    
    <div class="brand-info waves" id="waves-js"></div>
    
    <!-- <script type="x-shader/x-vertex" id="vertexshader">
      attribute float scale;
      void main() {
        vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
        gl_PointSize = scale * ( 300.0 / - mvPosition.z );
        gl_Position = projectionMatrix * mvPosition;
      }
    </script>
    <script type="x-shader/x-fragment" id="fragmentshader">
      uniform vec3 color;
      void main() {
        if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard;
        gl_FragColor = vec4( color, 1.0 );
      }
    </script> -->
    
  </div>
</template>

<style scoped lang="less">
.login {
  width: 100%;
  height: 100%;
  background: @273b84;
  
}
.brand-info {
  color: #fff;
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  background: none;
  background-color: transparent;

  &.particles {
    top: 0;
    z-index: 6
  }

  &.waves {
    height: 50%;
    bottom: 0;
    z-index: 5;
  }
}
</style>

  • components/waves/index.js
import { defineComponent, onMounted } from 'vue'
import threeWaves from '@/assets/libs/waves';

export default defineComponent({
  setup() {
    onMounted(() => {
      threeWaves('waves-js');
    })
    return {
    };
  },
});

效果
在这里插入图片描述


如有启发,可点赞收藏哟~

  • 26
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值