【Three.js】七、three.js粒子、精靈、點雲
- 一、粒子(Sprite)
- 二、點雲(Points)
粒子(也叫精靈),可用來建立非常細小的物體,可以用來模拟雨、雪、煙等其他有趣的效果。
一、粒子(Sprite)
使用Three.Sprite()可以用來建立一個粒子,該構造函數接受一個材質參數。下面是一個利用Three.Sprite()建立的一個粒子矩陣。
let createSprites = function () {
let texture = new THREE.TextureLoader().load(sprite);
let spriteMaterial = new THREE.SpriteMaterial({map: texture, color: 0xff0000});
for (let x = -5; x < 5; x++) {
for (let y = -5; y < 5; y++) {
let sprite = new THREE.Sprite(spriteMaterial);
sprite.position.set(x*10, y*10, 0);
scene.add(sprite);
}
}
};
Three.Sprite()繼承自Object3D,是以其可以調用position、scale、rotation等方法。注意粒子不會投射任何陰影。
上述例子建立了一百個粒子,并将這一百個粒子添加到了場景中,看起來并沒什麼不好,但如果要添加大量的粒子的話,顯然這種方式不太合适。下面介紹一種向場景中添加大量粒子的方法。
二、點雲(Points)
建立Points與建立Mesh一樣,都需要一個Geometry和一個Material,繼承自Object3D。下面利用Points将上面例子實作:
let createSprites = function () {
let texture = new THREE.TextureLoader().load(sprite);
let pointsMaterial = new THREE.PointsMaterial({map: texture, color: 0xffffff, size: 10});
let pointsGeometry = new THREE.Geometry();
for (let x = -5; x < 5; x++) {
for (let y = -5; y < 5; y++) {
pointsGeometry.vertices.push(new THREE.Vector3(x*10, y*10, 0));
}
}
let points = new THREE.Points(pointsGeometry, pointsMaterial);
scene.add(points);
};
将上面例子改為一個20*20*20的立體矩陣,效果依然流暢:
let createSprites = function () {
let texture = new THREE.TextureLoader().load(sprite);
let pointsMaterial = new THREE.PointsMaterial({map: texture, color: 0xffffff, size: 10});
let pointsGeometry = new THREE.Geometry();
for (let x = -10; x < 10; x++) {
for (let y = -10; y < 10; y++) {
for (let z = -10; z < 10; z++) {
pointsGeometry.vertices.push(new THREE.Vector3(x*5, y*5, z*5));
}
}
}
let points = new THREE.Points(pointsGeometry, pointsMaterial);
scene.add(points);
};
下面利用Points完成一個下雪場景:
import '../../stylus/index.styl'
import * as THREE from 'three'
import snow1 from '../../assets/images/snowflake1.png'
import snow2 from '../../assets/images/snowflake2.png'
import snow3 from '../../assets/images/snowflake3.png'
import snow4 from '../../assets/images/snowflake4.png'
import snow5 from '../../assets/images/snowflake5.png'
import {initTrackballControls, initThree, initStats} from "../../util/util";
function init(){
let stats = initStats();
let {scene, camera, renderer} = initThree();
scene.fog = new THREE.FogExp2( 0x000000, 0.0008 );
camera.position.set(0,0, 1000);
camera.far = 20000;
let geometry = new THREE.BufferGeometry();
let textureLoader = new THREE.TextureLoader();
let snowTexture1 = textureLoader.load(snow1);
let snowTexture2 = textureLoader.load(snow2);
let snowTexture3 = textureLoader.load(snow3);
let snowTexture4 = textureLoader.load(snow4);
let snowTexture5 = textureLoader.load(snow5);
let parameters = [
[[ 1.0, 0.2, 0.5 ], snowTexture2, 20 ],
[[ 0.95, 0.1, 0.5 ], snowTexture3, 15 ],
[[ 0.90, 0.05, 0.5 ], snowTexture1, 10 ],
[[ 0.85, 0, 0.5 ], snowTexture5, 8 ],
[[ 0.80, 0, 0.5 ], snowTexture4, 5 ]
];
let vertices = [], materials = [];
for(let i = 0; i < 10000; i++) {
let x = Math.random() * 2000 - 1000;
let y = Math.random() * 2000 - 1000;
let z = Math.random() * 2000 - 1000;
vertices.push(x, y, z);
}
geometry.addAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
for (let i = 0; i < parameters.length; i++) {
let color = parameters[i][0];
let sprite = parameters[i][1];
let size = parameters[i][2];
materials[i] = new THREE.PointsMaterial({
color,
map: sprite,
size,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true
});
materials[i].color.setHSL(...color);
let points = new THREE.Points(geometry, materials[i]);
points.rotation.x = Math.random() * 6;
points.rotation.y = Math.random() * 6;
points.rotation.z = Math.random() * 6
scene.add(points);
}
let trackball = initTrackballControls(camera, renderer);
trackball.maxDistance = 1500;
function render(){
let time = Date.now() * 0.00005;
stats.update();
trackball.update();
camera.position.x += 0.05;
camera.position.y += 0.05;
camera.lookAt(scene.position);
for (let i = 0; i < scene.children.length; i++) {
if (scene.children[i] instanceof THREE.Points) {
scene.children[i].rotation.y = time * ( i < 4 ? i + 1 : - ( i + 1 ) );
}
}
// 顔色随時間變化
for ( let i = 0; i < materials.length; i ++ ) {
let color = parameters[ i ][ 0 ];
let h = ( 360 * ( color[ 0 ] + time ) % 360 ) / 360;
materials[ i ].color.setHSL( h, color[ 1 ], color[ 2 ] );
}
requestAnimationFrame(render);
renderer.render(scene, camera);
}
render();
}
init();
完整示例(src/pages/three_sprite_demo1、src/pages/three_sprite_demo2):https://github.com/MAXLZ1/threejs_demo