Use the HTML5 canvas to format 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
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>