Чанкинг с использованием плоскостей в THREE.js

Вопрос или проблема

Я пытаюсь создать бесконечно генерируемый мир, так же как это делает Minecraft, используя чанки, которые исчезают и появляются в зависимости от того, где находится игрок. Я использую плоскость, которая генерирует точки из комбинации шумов Перлина и Симплекса.

В любом случае, когда я загружаю точки в мир, все чанки одинаковые. Это потому, что я использую одну и ту же геометрию для всех. Я пробовал использовать object.matrixAutoUpdate = false; и object.updateMatrix();, но это ничего не дает. Я пробовал сделать каждый чанк с разной геометрией, но производительность падает, когда загружается новый набор чанков.

Вот полный код:

function updateChunk() {
    // Очистка чанков
    while(ground.children.length > 0){ 
        ground.children[0].geometry.dispose()
        ground.remove(ground.children[0]); 
    }

    let size = (game.chunk.render * 2) + 1
    let sX = (Math.floor(plane.position.x / 1000) * 1000) - Math.floor((size / 2) * 1000)
    let sY = (Math.floor(plane.position.z / 1000) * 1000) - Math.floor((size / 2) * 1000)

    ground.position.set(sX, 0, sY)

    for(let y = 0; y < size; y++) {
        for(let x = 0; x < size; x++) {
            let g = new THREE.Mesh(geometry.clone(), material);
            let startX = ((sX / 1000) + x) * 100
            let startY = ((sY / 1000) + y) * 100
            let currentChunk = createChunk(startX, startY)

            // Настройка ландшафта
            for(let y2 = 0; y2 < 101;y2++) {
                for(let x2 = 0; x2 < 101; x2++) {
                    g.geometry.vertices[(y2 * 101) + x2].z = currentChunk[x2 + ',' + y2]
                }
            }

            g.rotation.x = Math.PI / -2
            g.position.set(x * 1000, 0, y * 1000)
            g.matrixAutoUpdate = false;
            g.updateMatrix();
            ground.add( g );
        }
    }
}
function createChunk(startX, startY) {
    let chunk = []
    for(let y = 0; y < 101; y++) {
        for(let x = 0; x < 101; x++) {
            chunk[x + ',' + y] = Math.abs(noise.perlin2((x + startX) / 100, (y + startY) / 100)) * 200;
        }
    }
    return chunk
}

Ответ или решение

Чанки и генерация безграничного мира в THREE.js

Создание безграничного мира с использованием чанков, аналогично тому, как это сделано в Minecraft, – интересная и сложная задача, требующая внимания к деталям оптимизации и правильной организации ресурсов. Давайте разберем вашу проблему и предложим возможные решения.

Анализ проблемы

Как я понимаю, ваша проблема заключается в том, что каждый новый чанк генерируется с использованием одной и той же геометрии, что приводит к тому, что все чанки выглядят одинаково. Поскольку вы используете geometry.clone(), это не создает уникальную геометрию для каждого чанка, а просто клонирует существующую геометрию, которая, в свою очередь, не обновляется, из-за чего все чанки выглядят идентично. Вы также отметили, что использование object.matrixAutoUpdate = false и object.updateMatrix() не решает проблему, так как сам метод клонирования не создает новомодную геометрию.

Решения

  1. Создание уникальной геометрии для каждого чанка: Вместо того чтобы клонировать одну и ту же геометрию, создавайте новую геометрию для каждого чанка. Это позволит вам изменять вершины отдельно для каждого чанка, сохраняя уникальные данные о высоте и генерации. Пример:

    function createGeometry(currentChunk) {
       const geometry = new THREE.PlaneGeometry(1000, 1000, 100, 100);
       for (let y = 0; y < 101; y++) {
           for (let x = 0; x < 101; x++) {
               geometry.vertices[y * 101 + x].z = currentChunk[x + ',' + y];
           }
       }
       geometry.needsUpdate = true; // Убедитесь, что геометрия обновляется
       return geometry;
    }
  2. Использование of BufferGeometry: Чтобы улучшить производительность, рассмотрите возможность использования BufferGeometry, который оптимизирован для работы с большим количеством вершин. Это может существенно уменьшить количество операций памяти при создании чанков.

    function createBufferGeometry(currentChunk) {
       const positionArray = new Float32Array(101 * 101 * 3); // x, y, z
       for (let y = 0; y < 101; y++) {
           for (let x = 0; x < 101; x++) {
               const index = (y * 101 + x) * 3;
               positionArray[index] = x * 10; // соответствие координате x
               positionArray[index + 1] = 0; // y всегда 0 для плоскости
               positionArray[index + 2] = currentChunk[x + ',' + y]; // высота
           }
       }
       const geometry = new THREE.BufferGeometry();
       geometry.setAttribute('position', new THREE.BufferAttribute(positionArray, 3));
       return geometry;
    }
  3. Оптимизация обновления чанков и их удаления: Подумайте о том, как именно вы очищаете и загружаете чанки. Возможно, стоит предварительно загружать новые чанки, основываясь на позиции игрока, и постепенно подгружать их вместо полного очищения каждого раза. Это также может помочь избегать падения производительности из-за быстрого создания и удаления объектов.

  4. Загрузка чанков по мере необходимости: Реализуйте механизм, который будет загружать чанки в зависимости от позиции игрока. Для этого можно использовать области видимости (frustum culling) и зоны, которые находятся внутри определенного радиуса от игрока.

Заключение

Создание бесконечного мира в THREE.js — это задача, требующая разумного подхода к управлению памятью и производительностью. Правильная генерация уникальной геометрии и тщательная оптимизация работы с чанками помогут вам создавать более совершенное приложение без значительных потерь в производительности. Если вы будете следовать вышеперечисленным советам, ваши чанки будут восприниматься как уникальные и разнообразные, что значительно улучшит общее впечатление от игры.

Оцените материал
Добавить комментарий

Капча загружается...