Три JS: Можем ли мы использовать InstancedMe sh в чередовании - PullRequest
0 голосов
/ 24 марта 2020

Я знаю базовую c концепцию Interleaved и InstanceBuffer, но когда я загружаю огромное количество моделей в InterLeaved, такие функции, как увеличение / уменьшение, панорамирование и поворот, отстают. Реакция функциональности очень медленная. Итак, есть ли возможный способ загрузки InstancedMe sh в Interleaved. Я понятия не имею с этим, но мне нужны некоторые предложения относительно этого. Вот код, который я попробовал.

<!DOCTYPE html>
<html lang="en">

<head>
    <title>three.js webgl - buffergeometry - particles</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">

    <link type="text/css" rel="stylesheet" href="main.css">
</head>

<body>

    <div id="container"></div>


    <script type="module">
        import * as THREE from '../build/three.module.js';

        import Stats from './jsm/libs/stats.module.js';
        import { OrbitControls } from './jsm/controls/OrbitControls.js';

        var container, stats;
        var camera, scene, renderer, mesh;

        var instances = 5000;
        var lastTime = 0;

        var controls;
        var moveQ = new THREE.Quaternion(0.5, 0.5, 0.5, 0.0).normalize();
        var tmpQ = new THREE.Quaternion();
        var tmpM = new THREE.Matrix4();
        var currentM = new THREE.Matrix4();

        init();
        animate();

        function init() {

            container = document.getElementById('container');

            camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 1000);
            camera.position.z = 190;
            scene = new THREE.Scene();
            scene.background = new THREE.Color('white');


            // geometry

            // var geometry = new THREE.InstancedBufferGeometry();
            var geometry = new THREE.InstancedBufferGeometry();


            // per mesh data x,y,z,w,u,v,s,t for 4-element alignment
            // only use x,y,z and u,v; but x, y, z, nx, ny, nz, u, v would be a good layout
            var vertexBuffer = new THREE.InterleavedBuffer(new Float32Array([
                // Front
                - 1, 1, 1, 0, 0, 0, 0, 0,
                1, 1, 1, 0, 1, 0, 0, 0,
                - 1, - 1, 1, 0, 0, 1, 0, 0,
                1, - 1, 1, 0, 1, 1, 0, 0,
                // Back
                1, 1, - 1, 0, 1, 0, 0, 0,
                - 1, 1, - 1, 0, 0, 0, 0, 0,
                1, - 1, - 1, 0, 1, 1, 0, 0,
                - 1, - 1, - 1, 0, 0, 1, 0, 0,
                // Left
                - 1, 1, - 1, 0, 1, 1, 0, 0,
                - 1, 1, 1, 0, 1, 0, 0, 0,
                - 1, - 1, - 1, 0, 0, 1, 0, 0,
                - 1, - 1, 1, 0, 0, 0, 0, 0,
                // Right
                1, 1, 1, 0, 1, 0, 0, 0,
                1, 1, - 1, 0, 1, 1, 0, 0,
                1, - 1, 1, 0, 0, 0, 0, 0,
                1, - 1, - 1, 0, 0, 1, 0, 0,
                // Top
                - 1, 1, 1, 0, 0, 0, 0, 0,
                1, 1, 1, 0, 1, 0, 0, 0,
                - 1, 1, - 1, 0, 0, 1, 0, 0,
                1, 1, - 1, 0, 1, 1, 0, 0,
                // Bottom
                1, - 1, 1, 0, 1, 0, 0, 0,
                - 1, - 1, 1, 0, 0, 0, 0, 0,
                1, - 1, - 1, 0, 1, 1, 0, 0,
                - 1, - 1, - 1, 0, 0, 1, 0, 0
            ]), 8);

            // Use vertexBuffer, starting at offset 0, 3 items in position attribute
            var positions = new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0);
            geometry.setAttribute('position', positions);
            // Use vertexBuffer, starting at offset 4, 2 items in uv attribute
            var uvs = new THREE.InterleavedBufferAttribute(vertexBuffer, 2, 4);
            geometry.setAttribute('uv', uvs);

            var indices = new Uint16Array([
                0, 1, 2,
                2, 1, 3,
                4, 5, 6,
                6, 5, 7,
                8, 9, 10,
                10, 9, 11,
                12, 13, 14,
                14, 13, 15,
                16, 17, 18,
                18, 17, 19,
                20, 21, 22,
                22, 21, 23
            ]);

            geometry.setIndex(new THREE.BufferAttribute(indices, 1));

            // material

            var material = new THREE.MeshBasicMaterial();
            material.map = new THREE.TextureLoader().load('textures/crate.gif');
            material.side = THREE.DoubleSide;

            // per instance data

            var matrix = new THREE.Matrix4();
            var offset = new THREE.Vector3();
            var orientation = new THREE.Quaternion();
            var scale = new THREE.Vector3(1, 1, 1);
            var x, y, z, w;

            mesh = new THREE.InstancedMesh(geometry, material, instances);

            for (var i = 0; i < instances; i++) {

                // offsets

                x = Math.random() * 100 - 50;
                y = Math.random() * 100 - 50;
                z = Math.random() * 100 - 50;

                offset.set(x, y, z).normalize();
                offset.multiplyScalar(5); // move out at least 5 units from center in current direction
                offset.set(x + offset.x, y + offset.y, z + offset.z);

                // orientations

                x = Math.random() * 2 - 1;
                y = Math.random() * 2 - 1;
                z = Math.random() * 2 - 1;
                w = Math.random() * 2 - 1;

                orientation.set(x, y, z, w).normalize();

                matrix.compose(offset, orientation, scale);

                mesh.setMatrixAt(i, matrix);

            }

            scene.add(mesh);

            renderer = new THREE.WebGLRenderer();
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.setSize(window.innerWidth, window.innerHeight);

            // //
            controls = new OrbitControls(camera, renderer.domElement);

            controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
            controls.dampingFactor = 0.05;

            controls.screenSpacePanning = false;

            controls.minDistance = 0.1;
            controls.maxDistance = 5000000;

            controls.maxPolarAngle = Math.PI / 2;
            //

            container.appendChild(renderer.domElement);

            if (renderer.extensions.get('ANGLE_instanced_arrays') === null) {

                document.getElementById('notSupported').style.display = '';
                return;

            }

            stats = new Stats();
            // container.appendChild(stats.dom);

            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);
            controls.update(); // required if controls.enableDamping = true, or if controls.autoRotate = true

            render();

            stats.update();

        }

        function render() {

            // var time = performance.now();

            // mesh.rotation.y   = time * 0.00005;

            // var delta = (time - lastTime) / 5000;
            // tmpQ.set(moveQ.x * delta, moveQ.y * delta, moveQ.z * delta, 1).normalize();
            // tmpM.makeRotationFromQuaternion(tmpQ);

            for (var i = 0, il = instances; i < il; i++) {

                mesh.getMatrixAt(i, currentM);
                currentM.multiply(tmpM);
                mesh.setMatrixAt(i, currentM);

            }

            mesh.instanceMatrix.needsUpdate = true;

            // lastTime = time;

            renderer.render(scene, camera);

        }

    </script>

</body>

</html>
...