THREE.Points
是用来创建点的类,也用来批量管理粒子,这个类的构造函数可以接受两个参数,一个几何体和一个材质,几何体参数用来制定粒子的位置坐标,而材质参数用来格式化粒子。
可以基于简单几何体对象例如BoxGeometry
、SphereGeometry
等作为粒子系统的参数,但是一般来讲,都需要自己指定顶点来确定粒子的位置。
通过THREE.PointsMaterial
可以设置粒子的属性参数,示例中通过调试插件可以尝试着调整粒子的样式。
示例:PointsMaterial.html
点击map添加贴图的话,可以实现,下雨的效果
属性
名称 | 描述 |
---|---|
color | 点(粒子)的颜色,默认值为白色 |
map | 贴图 |
size | 点的大小,默认值为1 |
vertexColors | 若不设置此属性,则所有的带你具有相同的颜色,若设置此属性为true 或者THREE.VertexColors 并且,几何体的color 属性是一个颜色数组,那么就会应用颜色数组的值,默认值为THREE.NoColors |
sizeAttenuation | 设置点的大小是否随着距离的增大而变小,默认为true ,如果设置为false ,z则所有点的大小不随距离的增加而变化 |
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>粒子系统 Points</title>
<style>
body {
margin: 0;
overflow: hidden; /*溢出隐藏*/
}
</style>
<script src="../../libs/build/three-r93.min.js"></script>
<script src="../../libs/examples/js/controls/OrbitControls.js"></script>
<script src="../../libs/examples/js/libs/dat.gui.min.js"></script>
<script src="../../libs/examples/js/libs/stats.min.js"></script>
<script src="../../libs/examples/js/Detector.js"></script>
</head>
<body>
<script>
let stats = initStats();
let scene, camera, renderer, points, controls, guiControls;
/* 场景 */
function initScene() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0x050505);
scene.fog = new THREE.Fog(0x050505, 2000, 3500);
}
/* 相机 */
function initCamera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 5000);
camera.position.set(0, 1000, 2500);
camera.lookAt(new THREE.Vector3(0, 0, 0));
}
/* 渲染器 */
function initRenderer() {
renderer = new THREE.WebGLRenderer({antialias: true});
/* 渲染范围 */
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
/* 灯光 */
function initLight() {
}
/* 控制器 */
function initControls() {
controls = new THREE.OrbitControls(camera, renderer.domElement);
// 添加惯性
controls.enableDamping = true;
// 最大偏移角度
controls.maxPolarAngle = 0.49 * Math.PI;
// 旋转速度
controls.rotateSpeed = 0.05;
controls.enableRotate = false;
controls.enablePan = false;
}
/* 调试插件 */
function initGui() {
guiControls = new function () {
this.rotation = false;
this.sizeAttenuation = material.sizeAttenuation;
this.size = material.size;
this.map = false;
};
let gui = new dat.GUI();
gui.add(guiControls, 'rotation').onChange(function (e) {
if (e) {
step = 0;
} else {
step = 0.01;
}
});
gui.add(guiControls, 'sizeAttenuation').onChange(function (e) {
material.sizeAttenuation = e;
material.needsUpdate = true;
});
gui.add(guiControls, 'size', 1, 10).onChange(function (e) {
material.size = e;
material.needsUpdate = true;
});
gui.add(guiControls, 'map').onChange(function (e) {
if (e) {
material.map = texture;
material.sizeAttenuation = true;
controls.maxDistance = 100;
camera.far = 50;
controls.enabled = false;
}else {
material.map = null;
camera.position.set(0, 1000, 2500);
controls.maxDistance = 10000;
camera.far = 5000;
controls.enabled = true;
}
material.needsUpdate = true;
camera.updateProjectionMatrix();
});
}
/* 场景中的内容 */
let material;
let texture;
function initContent() {
/* 500000个点 */
let particles = 500000;
/* 存放粒子数据的网格 */
let geometry = new THREE.BufferGeometry();
let positions = [];
let colors = [];
texture = new THREE.TextureLoader().load('../../textures/particles/rn.png');
let color = new THREE.Color();
/* 使粒子在立方体范围内扩散 */
let n = 1000, n2 = n / 2;
for (let i = 0; i < particles; i++) {
// 点
let x = Math.random() * n - n2;
let y = Math.random() * n - n2;
let z = Math.random() * n - n2;
positions.push(x, y, z);
// 颜色
let vx = (x / n) + 0.5;
let vy = (y / n) + 0.5;
let vz = (z / n) + 0.5;
color.setRGB(vx, vy, vz);
colors.push(color.r, color.g, color.b);
}
// 添加点和颜色
geometry.addAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
geometry.addAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
material = new THREE.PointsMaterial({
size: 1,
sizeAttenuation: true,
vertexColors: THREE.VertexColors,
transparent: true,
opacity: 0.7
});
/* 批量管理点 */
points = new THREE.Points(geometry, material);
scene.add(points);
}
/* 性能插件 */
function initStats() {
let stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.body.appendChild(stats.domElement);
return stats;
}
/* 更新 */
let step = 0.01;
function update() {
stats.update();
controls.update();
points.rotation.x += step;
}
/* 初始化 */
function init() {
// 兼容性判断,若不兼容会提示信息
if (!Detector.webgl) Detector.addGetWebGLMessage();
initScene();
initCamera();
initRenderer();
initLight();
initControls();
initContent();
initGui();
window.addEventListener('resize', onWindowResize, false);
}
/* 窗口变动触发的方法 */
function onWindowResize() {
// 重新设置相机的宽高比
camera.aspect = window.innerWidth / window.innerHeight;
// 更新相机投影矩阵
camera.updateProjectionMatrix();
// 更新渲染器大小
renderer.setSize(window.innerWidth, window.innerHeight);
}
/* 循环渲染 */
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
update();
}
/* 页面绘制完后加载 */
window.onload = function () {
init();
animate();
};
</script>
</body>
</html>