Use vue to learn the particles and particle system of three.js-use the HTML5 canvas to format the particles through the THREE.SpriteMaterial material

1. Introduction of Sprite Material

The SpriteMaterial class inherits from the Material base class, and all the properties and methods of the Material class can be used by the SpriteMaterial class.
The SpriteMaterial class also has some properties of its own. Next, I will mainly introduce these properties

Attributes description
color This attribute specifies the color of the material, the default value is 0xFFFFFF
map The color map can be specified by this attribute. Is a THREE.Texture object, the default is null
rotation Use this attribute to specify the rotation of the sprite particles in radians. The default value is 0
sizeAnnutation This attribute is a Boolean value. If true, the size of the particle is determined by the distance between the particle and the camera. If false, it means that the particle will have the same size regardless of the distance between the particle and the camera.
lights This attribute is a Boolean value that specifies whether the material is affected by light. The default value is false
fog This attribute is a Boolean value that specifies whether the material is affected by scene fog. The default value is false

2. Use HTML5 canvas to format particles

2.1 Create Texture Canvas Texture

The particles in the example show a group of small monsters. Creating a canvas texture is to get the appearance of the small monsters. The specific implementation is as follows

// 绘制小怪兽纹理
getTexture () {
    
    
  const canvas = document.createElement('canvas')
  canvas.width = 32
  canvas.height = 32
  const ctx = canvas.getContext('2d')
  
  // 身体
  ctx.translate(-81, -84)
  ctx.fillStyle = 'orange'
  ctx.beginPath()
  ctx.moveTo(83, 116)
  ctx.lineTo(83, 102)
  ctx.bezierCurveTo(83, 94, 89, 88, 97, 88)
  ctx.bezierCurveTo(105, 88, 111, 94, 111, 102)
  ctx.lineTo(111, 116)
  ctx.lineTo(106.333, 111.333)
  ctx.lineTo(101.666, 116)
  ctx.lineTo(97, 111.333)
  ctx.lineTo(92.333, 116)
  ctx.lineTo(87.666, 111.333)
  ctx.lineTo(83, 116)
  ctx.fill()

  // 眼睛
  ctx.fillStyle = 'white'
  ctx.beginPath()
  ctx.moveTo(91, 96)
  ctx.bezierCurveTo(88, 96, 87, 99, 87, 101)
  ctx.bezierCurveTo(87, 103, 88, 106, 91, 106)
  ctx.bezierCurveTo(94, 106, 95, 103, 95, 101)
  ctx.bezierCurveTo(95, 99, 94, 96, 91, 96)
  ctx.moveTo(103, 96)
  ctx.bezierCurveTo(100, 96, 99, 99, 99, 101)
  ctx.bezierCurveTo(99, 103, 100, 106, 103, 106)
  ctx.bezierCurveTo(106, 106, 107, 103, 107, 101)
  ctx.bezierCurveTo(107, 99, 106, 96, 103, 96)
  ctx.fill()

  // 眼球
  ctx.fillStyle = 'blue'
  ctx.beginPath()
  ctx.arc(101, 102, 2, 0, Math.PI * 2, true)
  ctx.fill()
  ctx.beginPath()
  ctx.arc(89, 102, 2, 0, Math.PI * 2, true)
  ctx.fill()

  const texture = new THREE.Texture(canvas)
  texture.needsUpdate = true
  return texture
}

2.2 Create SpriteMaterial material

It is the same as using the THREE.PointsMaterial class to create a particle material. Assign the above texture creation function to the map parameter that creates the SpriteMaterial material, see the sample code for details

// 创建粒子材质
const material = new THREE.SpriteMaterial({
    
    
  map: this.getTexture(),
  color: 0xffffff
})
material.rotation = Math.PI

2.2 Create a Sprite object and add it to the scene

const range = 500
for (let i = 0; i < 1500; i++) {
    
    
  const sprite = new THREE.Sprite(material)
  sprite.position.set(
    Math.random() * range - range / 2,
    Math.random() * range - range / 2,
    Math.random() * range - range / 2
  )
  sprite.scale.set(4, 4, 4)
  this.scene.add(sprite)
}

3.demo effect

Insert picture description here

4.demo code

<template>
  <div id="container"></div>
</template>

<script>
import * as THREE from 'three'
import {
    
     OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

export default {
    
    
  data () {
    
    
    return {
    
    
      camera: null,
      scene: null,
      renderer: null,
      controls: null
    }
  },
  mounted () {
    
    
    this.init()
  },
  methods: {
    
    
    // 初始化
    init () {
    
    
      this.createScene() // 创建场景
      this.createParticleSystem() // 创建粒子系统
      this.createCamera() // 创建相机
      this.createRender() // 创建渲染器
      this.createControls() // 创建控件对象
      this.render() // 渲染
    },
    // 创建场景
    createScene () {
    
    
      this.scene = new THREE.Scene()
    },
    // 创建粒子
    createParticleSystem () {
    
    
      // 创建粒子材质
      const material = new THREE.SpriteMaterial({
    
    
        map: this.getTexture(),
        color: 0xffffff
      })
      material.rotation = Math.PI

      const range = 500
      for (let i = 0; i < 1500; i++) {
    
    
        const sprite = new THREE.Sprite(material)
        sprite.position.set(
          Math.random() * range - range / 2,
          Math.random() * range - range / 2,
          Math.random() * range - range / 2
        )
        sprite.scale.set(4, 4, 4)
        this.scene.add(sprite)
      }
    },
    // 绘制小怪兽纹理
    getTexture () {
    
    
      const canvas = document.createElement('canvas')
      canvas.width = 32
      canvas.height = 32

      const ctx = canvas.getContext('2d')
      // 身体
      ctx.translate(-81, -84)

      ctx.fillStyle = 'orange'
      ctx.beginPath()
      ctx.moveTo(83, 116)
      ctx.lineTo(83, 102)
      ctx.bezierCurveTo(83, 94, 89, 88, 97, 88)
      ctx.bezierCurveTo(105, 88, 111, 94, 111, 102)
      ctx.lineTo(111, 116)
      ctx.lineTo(106.333, 111.333)
      ctx.lineTo(101.666, 116)
      ctx.lineTo(97, 111.333)
      ctx.lineTo(92.333, 116)
      ctx.lineTo(87.666, 111.333)
      ctx.lineTo(83, 116)
      ctx.fill()

      // 眼睛
      ctx.fillStyle = 'white'
      ctx.beginPath()
      ctx.moveTo(91, 96)
      ctx.bezierCurveTo(88, 96, 87, 99, 87, 101)
      ctx.bezierCurveTo(87, 103, 88, 106, 91, 106)
      ctx.bezierCurveTo(94, 106, 95, 103, 95, 101)
      ctx.bezierCurveTo(95, 99, 94, 96, 91, 96)
      ctx.moveTo(103, 96)
      ctx.bezierCurveTo(100, 96, 99, 99, 99, 101)
      ctx.bezierCurveTo(99, 103, 100, 106, 103, 106)
      ctx.bezierCurveTo(106, 106, 107, 103, 107, 101)
      ctx.bezierCurveTo(107, 99, 106, 96, 103, 96)
      ctx.fill()

      // 眼球
      ctx.fillStyle = 'blue'
      ctx.beginPath()
      ctx.arc(101, 102, 2, 0, Math.PI * 2, true)
      ctx.fill()
      ctx.beginPath()
      ctx.arc(89, 102, 2, 0, Math.PI * 2, true)
      ctx.fill()

      const texture = new THREE.Texture(canvas)
      texture.needsUpdate = true
      return texture
    },

    // 创建相机
    createCamera () {
    
    
      const element = document.getElementById('container')
      const width = element.clientWidth // 窗口宽度
      const height = element.clientHeight // 窗口高度
      const k = width / height // 窗口宽高比
      // PerspectiveCamera( fov, aspect, near, far )
      this.camera = new THREE.PerspectiveCamera(45, k, 0.1, 1000)
      this.camera.position.set(0, 0, 150) // 设置相机位置

      this.camera.lookAt(new THREE.Vector3(10, 0, 0)) // 设置相机方向
      this.scene.add(this.camera)
    },
    // 创建渲染器
    createRender () {
    
    
      const element = document.getElementById('container')
      this.renderer = new THREE.WebGLRenderer({
    
     antialias: true, alpha: true })
      this.renderer.setSize(element.clientWidth, element.clientHeight) // 设置渲染区域尺寸
      this.renderer.setClearColor(0x3f3f3f, 1) // 设置背景颜色
      element.appendChild(this.renderer.domElement)
    },

    render () {
    
    
      this.renderer.render(this.scene, this.camera)
      requestAnimationFrame(this.render)
    },
    // 创建控件对象
    createControls () {
    
    
      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
    }
  }
}
</script>
<style>
#container {
    
    
  position: absolute;
  width: 100%;
  height: 100%;
}
</style>

Guess you like

Origin blog.csdn.net/qw8704149/article/details/111242458