Вопрос или проблема
Я пытаюсь создать бесконечно генерируемый мир, так же как это делает 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()
не решает проблему, так как сам метод клонирования не создает новомодную геометрию.
Решения
-
Создание уникальной геометрии для каждого чанка: Вместо того чтобы клонировать одну и ту же геометрию, создавайте новую геометрию для каждого чанка. Это позволит вам изменять вершины отдельно для каждого чанка, сохраняя уникальные данные о высоте и генерации. Пример:
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; }
-
Использование 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; }
-
Оптимизация обновления чанков и их удаления: Подумайте о том, как именно вы очищаете и загружаете чанки. Возможно, стоит предварительно загружать новые чанки, основываясь на позиции игрока, и постепенно подгружать их вместо полного очищения каждого раза. Это также может помочь избегать падения производительности из-за быстрого создания и удаления объектов.
-
Загрузка чанков по мере необходимости: Реализуйте механизм, который будет загружать чанки в зависимости от позиции игрока. Для этого можно использовать области видимости (frustum culling) и зоны, которые находятся внутри определенного радиуса от игрока.
Заключение
Создание бесконечного мира в THREE.js — это задача, требующая разумного подхода к управлению памятью и производительностью. Правильная генерация уникальной геометрии и тщательная оптимизация работы с чанками помогут вам создавать более совершенное приложение без значительных потерь в производительности. Если вы будете следовать вышеперечисленным советам, ваши чанки будут восприниматься как уникальные и разнообразные, что значительно улучшит общее впечатление от игры.