ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

记录--vue+three,制作iview大波浪特效

2022-09-14 17:04:29  阅读:313  来源: 互联网

标签:vue const -- 大波浪 THREE window camera position new


这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

一、效果图

具体效果可参考iview官方界面iView - 一套高质量的UI组件库

 image.png

大波浪效果,使用的是three.js的官方例子,需要先安装three.js支持

npm install --save three

具体可以看 three.js examples (threejs.org)

二、代码

//添加容器
<div id="iviewUi" />

 

<script>
//引入three.js
import * as THREE from 'three'
 
export default {
  props: {
    amountX: {
      type: Number,
      default: 50
    },
    amountY: {
      type: Number,
      default: 50
    },
    //控制点颜色
    color: {
      type: Number,
      default: '#097bdb'
    },
    top: {
      type: Number,
      default: 350
    }
  },
  data() {
    return {
      count: 0,
      // 用来跟踪鼠标水平位置
      mouseX: 0,
      windowHalfX: null,
      // 相机
      camera: null,
      // 场景
      scene: null,
      // 批量管理粒子
      particles: null,
      // 渲染器
      renderer: null
    }
  },
  mounted() {
    this.init()
    this.animate()
  },
  methods: {
    init: function() {
      const SEPARATION = 100
      const SCREEN_WIDTH = window.innerWidth
      const SCREEN_HEIGHT = window.innerHeight
      const container = document.createElement('div')
      this.windowHalfX = window.innerWidth / 2
      container.style.position = 'relative'
      container.style.top = `${this.top}px`
      container.style.height = `${(SCREEN_HEIGHT - this.top)}px`
      document.getElementById('iviewUi').appendChild(container)
 
      this.camera = new THREE.PerspectiveCamera(75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000)
      this.camera.position.z = 1000
 
      this.scene = new THREE.Scene()
 
      const numParticles = this.amountX * this.amountY
      const positions = new Float32Array(numParticles * 3)
      const scales = new Float32Array(numParticles)
      // 初始化粒子位置和大小
      let i = 0
      let j = 0
      for (let ix = 0; ix < this.amountX; ix++) {
        for (let iy = 0; iy < this.amountY; iy++) {
          positions[i] = ix * SEPARATION - ((this.amountX * SEPARATION) / 2)
          positions[i + 1] = 0
          positions[i + 2] = iy * SEPARATION - ((this.amountY * SEPARATION) / 2)
          scales[j] = 1
          i += 3
          j++
        }
      }
 
      const geometry = new THREE.BufferGeometry()
      geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3))
      geometry.addAttribute('scale', new THREE.BufferAttribute(scales, 1))
      // 初始化粒子材质
      const material = new THREE.ShaderMaterial({
        uniforms: {
          color: { value: new THREE.Color(this.color) }
        },
        vertexShader: `
          attribute float scale;
          void main() {
            vec4 mvPosition = modelViewMatrix * vec4( position, 2.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 );
          }
        `
      })
 
      this.particles = new THREE.Points(geometry, material)
      this.scene.add(this.particles)
 
      this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
      this.renderer.setSize(container.clientWidth, container.clientHeight)
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.setClearAlpha(0)
      container.appendChild(this.renderer.domElement)
 
      window.addEventListener('resize', this.onWindowResize, { passive: false })
      document.addEventListener('mousemove', this.onDocumentMouseMove, { passive: false })
      document.addEventListener('touchstart', this.onDocumentTouchStart, { passive: false })
      document.addEventListener('touchmove', this.onDocumentTouchMove, { passive: false })
    },
    render: function() {
      this.camera.position.x += (this.mouseX - this.camera.position.x) * 0.05
      this.camera.position.y = 400
      this.camera.lookAt(this.scene.position)
      const positions = this.particles.geometry.attributes.position.array
      const scales = this.particles.geometry.attributes.scale.array
      // 计算粒子位置及大小
      let i = 0
      let j = 0
      for (let ix = 0; ix < this.amountX; ix++) {
        for (let iy = 0; iy < this.amountY; iy++) {
          positions[i + 1] = (Math.sin((ix + this.count) * 0.3) * 100) + (Math.sin((iy + this.count) * 0.5) * 100)
          scales[j] = (Math.sin((ix + this.count) * 0.3) + 1) * 8 + (Math.sin((iy + this.count) * 0.5) + 1) * 8
          i += 3
          j++
        }
      }
      // 重新渲染粒子
      this.particles.geometry.attributes.position.needsUpdate = true
      this.particles.geometry.attributes.scale.needsUpdate = true
      this.renderer.render(this.scene, this.camera)
      this.count += 0.1
    },
    animate: function() {
      requestAnimationFrame(this.animate)
      this.render()
    },
    onDocumentMouseMove: function(event) {
      this.mouseX = event.clientX - this.windowHalfX
    },
    onDocumentTouchStart: function(event) {
      if (event.touches.length === 1) {
        this.mouseX = event.touches[0].pageX - this.windowHalfX
      }
    },
    onDocumentTouchMove: function(event) {
      if (event.touches.length === 1) {
        event.preventDefault()
        this.mouseX = event.touches[0].pageX - this.windowHalfX
      }
    },
    onWindowResize: function() {
      this.windowHalfX = window.innerWidth / 2
      this.camera.aspect = window.innerWidth / window.innerHeight
      this.camera.updateProjectionMatrix()
      this.renderer.setSize(window.innerWidth, window.innerHeight)
    }
  }
}
</script>

三、背景素材

loginback.png

如果不清晰可以去官方界面拿,如下图所示

 image.png

本文转载于:

https://juejin.cn/post/7038372456519696421

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 

标签:vue,const,--,大波浪,THREE,window,camera,position,new
来源: https://www.cnblogs.com/smileZAZ/p/16693655.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有