精灵例子是面向屏幕的半透明对象,通常含有半透明的纹理,而且始终面向屏幕,基于这个特性,我们可以实现简单的小功能
首先是下雨的小示例
具体代码如下
import React, { Component } from 'react'
import grass from './grass.png'
import rain from './rain.png'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
export default class indexTwo extends Component {
componentDidMount () {
const scene = new THREE.Scene();
/**
* 创建一个地面
*/
const geometry = new THREE.PlaneGeometry(1000, 1000);
//加载草地纹理
const texture = new THREE.TextureLoader().load(grass);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
//uv两个方向纹理重复数量
texture.repeat.set(10, 10);
const material = new THREE.MeshLambertMaterial({
map: texture,
side: THREE.DoubleSide
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
mesh.rotateX(-Math.PI / 2);
/**
* 精灵模型创建下雨效果
*/
//加载雨滴纹理贴图
const textureTree = new THREE.TextureLoader().load(rain);
//创建一个组表示所有的雨滴
const group = new THREE.Group();
const spriteMaterial = new THREE.SpriteMaterial({
map: textureTree
});
//批量创建雨滴的精灵模型
for (let i = 0; i < 2000; i++) {
//创建精灵模型对象
const sprite = new THREE.Sprite(spriteMaterial);
group.add(sprite);
//控制精灵大小
sprite.scale.set(8, 10, 1);//只需要设置x,y,两个变量
const k1 = Math.random() - 0.5;
const k2 = Math.random() - 0.5;
//设置精灵模型位置
sprite.position.set(1000 * k1, 300 * Math.random(), 1000 * k2);
}
scene.add(group);
/**
* 光源设置
*/
//点光源
const point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300);
scene.add(point);
const ambient = new THREE.AmbientLight(0x888888);
scene.add(ambient);
/**
* 透视投影相机设置
*/
const width = window.innerWidth;
const height = window.innerHeight;
const camera = new THREE.PerspectiveCamera(60, width / height, 1, 2000);
camera.position.set(292, 109, 268);
camera.lookAt(scene.position);
/**
* 创建渲染器对象
*/
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
document.getElementById("rain").appendChild(renderer.domElement);
function render () {
//每次雨滴的y坐标减去2,模拟不断落地的效果
//当group里面的某个雨滴落地时,立刻将其y坐标设置为300
group.children.forEach(sprite => {
sprite.position.y -= 2;
if (sprite.position.y < 0) {
sprite.position.y = 300;
}
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
new OrbitControls(camera, renderer.domElement);
}
render () {
return (
<div>
<div id="rain" />
</div>
)
}
}
代码并不复杂,创建好精灵材质,然后循环创建多个精灵粒子,这里的精灵材质我只创建了一个对象,可以让所有的粒子共用一个材质,这样做的好处是避免创建过多的材质对象,减少内存消耗,此外,当你尝试交互改变某个材质的时候,所有的使用这个材质的对象都会受到影响。
沿着这样的思路,我们还可以创建别的效果,例如树林效果
思路同上。
最后,和图表结合,一般来讲,精灵例子很多时候在三维场景里面是作为标签使用的,我们可以将其与Echarts结合,Echarts有个getDataURL方法,可以获取图表的图片,我们可以将其作为精灵粒子的纹理贴图,然后和三维模型结合展示在一起。
效果如下,这个学习笔记所有的代码可以去 https://gitee.com/feng-pan/threejs-demo 获取。