通过THREE.SpriteMaterial材质使用HTML5画布格式化粒子
1.SpriteMaterial材质介绍
SpriteMaterial类继承自Material基类,所有Material类的属性和方法SpriteMaterial类都可以使用。
SpriteMaterial类还有自己的一些属性,接下来主要介绍一下这些属性
属性 | 描述 |
---|---|
color | 该属性指定材质的颜色,默认值是0xFFFFFF |
map | 通过该属性可以指定颜色贴图。是一个THREE.Texture对象,默认为null |
rotation | 通过该属性指定sprite粒子的转动,以弧度为单位。默认值为0 |
sizeAnnutation | 该属性是一个布尔值,若为true表示粒子的大小由粒子到相机的距离决定,若为false表示无论粒子到相机的距离是多少,粒子都会有相同的尺寸 |
lights | 该属性是一个布尔值,指定材质是否受到光照的影响。默认值为false |
fog | 该属性是一个布尔值,指定材质是否受场景雾的影响。默认值为false |
2.使用HTML5画布格式化粒子
2.1创建Texture画布纹理
示例中粒子展示的是一群小怪兽,创建画布纹理就是获取小怪兽的样子,具体实现如下
// 绘制小怪兽纹理
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 创建SpriteMaterial材质
与使用THREE.PointsMaterial类创建粒子材质一样。将上面的创建纹理的函数赋值给创建SpriteMaterial材质的map参数,具体看示例代码
// 创建粒子材质
const material = new THREE.SpriteMaterial({
map: this.getTexture(),
color: 0xffffff
})
material.rotation = Math.PI
2.2 创建Sprite对象并添加到场景
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效果
4.demo代码
<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>