40 - three.js 笔记 - 粒子系统 Points 和 PointsMaterial

THREE.Points是用来创建点的类,也用来批量管理粒子,这个类的构造函数可以接受两个参数,一个几何体和一个材质,几何体参数用来制定粒子的位置坐标,而材质参数用来格式化粒子。
可以基于简单几何体对象例如BoxGeometrySphereGeometry等作为粒子系统的参数,但是一般来讲,都需要自己指定顶点来确定粒子的位置。
通过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>

猜你喜欢

转载自blog.csdn.net/ithanmang/article/details/81702561