Генерация меша из кода

PlayCanvas предоставляет мощные инструменты для создания 3D-контента в реальном времени, включая возможность генерации объектов с помощью кода. Генерация мешей (или сеток) — важная часть этого процесса, поскольку она позволяет создавать объекты на лету, динамически изменяя их форму и структуру в зависимости от логики игры или приложения.

Основы генерации мешей

Меш в PlayCanvas — это совокупность вершин, граней и нормалей, которые описывают форму объекта. В PlayCanvas меши создаются через объект pc.Mesh, который является контейнером для данных о вершинах, гранях и других характеристиках. Генерация меша из кода обычно включает создание массива вершин и индексов, которые описывают геометрию объекта.

Для создания простого объекта, например, куба, можно использовать следующие шаги:

  1. Создание массива вершин — массив точек в 3D пространстве, которые определяют форму объекта.
  2. Создание массива индексов — массив чисел, который определяет, какие вершины соединяются для формирования граней объекта.
  3. Создание материалов — объекты, которые будут наложены на поверхности объекта для задания текстур и других визуальных характеристик.

Создание меша

Для создания меша из кода необходимо использовать класс pc.Mesh, который позволяет работать с вершинами и индексами, а также связывать их с материалами. Пример базовой генерации куба:

var vertices = [
    // Передняя грань
    -1, -1,  1,  1, -1,  1,  1,  1,  1, -1,  1,  1,  // (x, y, z)
    // Задняя грань
    -1, -1, -1,  1, -1, -1,  1,  1, -1, -1,  1, -1,
    // Левые, правые и другие грани
    // ...
];

var indices = [
    0, 1, 2,  0, 2, 3, // Передняя грань
    4, 5, 6,  4, 6, 7, // Задняя грань
    // ...
];

var mesh = new pc.Mesh();
mesh.setPositions(vertices);
mesh.setIndices(indices);

// Создание материала
var material = new pc.Material();
material.diffuse = new pc.Color(1, 0, 0);  // Красный цвет

// Применение материала к мешу
mesh.material = material;

Детали работы с вершинами

Каждая вершина в PlayCanvas имеет несколько атрибутов, таких как позиция, нормали, текстурные координаты и т. д. Вершины описываются в виде массива, где каждая вершина состоит из набора значений, определяющих её положение в 3D-пространстве. Например, для простого куба в пространстве, вершины могут быть заданы как 3D-координаты: (x, y, z).

С помощью этих данных PlayCanvas строит объект, соединяя вершины в треугольники с помощью индексов. Это позволяет минимизировать количество данных, необходимых для описания сложных объектов, и ускоряет рендеринг.

Использование нормалей

Нормали необходимы для освещения объектов в 3D-сценах. Нормаль — это вектор, который перпендикулярен поверхности объекта в каждой точке. Для правильного отображения освещения нужно учитывать нормали, которые могут быть вычислены для каждой вершины. Для генерации нормалей вручную для простых объектов можно воспользоваться следующим подходом:

function calculateNormals(vertices, indices) {
    var normals = [];
    
    for (var i = 0; i < indices.length; i += 3) {
        var i1 = indices[i];
        var i2 = indices[i + 1];
        var i3 = indices[i + 2];

        var v1 = new pc.Vec3(vertices[i1 * 3], vertices[i1 * 3 + 1], vertices[i1 * 3 + 2]);
        var v2 = new pc.Vec3(vertices[i2 * 3], vertices[i2 * 3 + 1], vertices[i2 * 3 + 2]);
        var v3 = new pc.Vec3(vertices[i3 * 3], vertices[i3 * 3 + 1], vertices[i3 * 3 + 2]);

        var edge1 = v2.sub(v1);
        var edge2 = v3.sub(v1);
        
        var normal = edge1.cross(edge2).normalize();
        
        normals.push(normal.x, normal.y, normal.z);
        normals.push(normal.x, normal.y, normal.z);
        normals.push(normal.x, normal.y, normal.z);
    }
    return normals;
}

var normals = calculateNormals(vertices, indices);
mesh.setNormals(normals);

Текстуры и материалы

Генерация текстур и материалов — важная часть создания 3D-объектов. В PlayCanvas материалы содержат все визуальные атрибуты, такие как цвет, текстуры, освещение и прочее. Текстуры можно наложить на объект с использованием UV-координат, которые определяют, как 2D-изображение накладывается на 3D-объект.

Пример генерации материала с текстурой:

var texture = new pc.Texture(app.graphicsDevice, {
    width: 256,
    height: 256,
    format: pc.PIXELFORMAT_R8_G8_B8_A8
});
texture.setSource(image);  // Загружаем изображение для текстуры

var material = new pc.Material();
material.diffuseMap = texture;
material.diffuse = new pc.Color(1, 1, 1);  // Белый цвет в качестве базового
material.update();

Текстуры могут быть применены к мешу с помощью материалов, и это может существенно улучшить визуальное восприятие объектов.

Пример динамической генерации

Для создания динамически генерируемых объектов, таких как коллизии или элементы ландшафта, можно комбинировать генерацию мешей с анимацией и физикой. Например, для генерации террейна можно использовать массивы высот и значения, полученные от различных алгоритмов генерации ландшафта.

function generateTerrain(width, height, scale) {
    var vertices = [];
    var indices = [];
    
    // Генерация высот
    for (var z = 0; z < height; z++) {
        for (var x = 0; x < width; x++) {
            var y = Math.sin(x / scale) * Math.cos(z / scale);
            vertices.push(x, y, z);
        }
    }

    // Генерация индексов
    for (var z = 0; z < height - 1; z++) {
        for (var x = 0; x < width - 1; x++) {
            var i1 = z * width + x;
            var i2 = i1 + 1;
            var i3 = (z + 1) * width + x;
            var i4 = i3 + 1;

            indices.push(i1, i2, i3, i2, i4, i3);
        }
    }

    var mesh = new pc.Mesh();
    mesh.setPositions(vertices);
    mesh.setIndices(indices);
    return mesh;
}

var terrainMesh = generateTerrain(256, 256, 10);

Оптимизация и производительность

Для эффективной работы с большими объемами данных важно учитывать оптимизацию мешей. Один из способов улучшить производительность — это использование индексированных массивов, где повторяющиеся вершины в разных гранях объекта не дублируются. Это уменьшает количество данных, которые нужно передавать графическому процессору, и ускоряет рендеринг.

Другой важный аспект — использование уровней детализации (LOD). Для сложных объектов или больших сцен можно генерировать различные уровни детализации объекта в зависимости от его расстояния от камеры. Это позволяет экономить ресурсы, когда объект находится далеко от камеры, и использовать более сложные модели, когда объект приближается.

Заключение

Генерация мешей из кода в PlayCanvas предоставляет широкие возможности для создания динамических и адаптивных 3D-объектов, которые могут быть использованы в интерактивных приложениях и играх. Правильное использование вершин, индексов, нормалей и материалов позволяет создать производительные и визуально привлекательные объекты.