UV-координаты представляют собой способ отображения текстур на поверхности 3D-модели. В Babylon.js каждая вершина меша может иметь набор UV-координат, который определяет, какая часть текстуры будет отображена на этой вершине. UV-координаты обычно находятся в диапазоне от 0 до 1 по осям U (горизонталь) и V (вертикаль).
Для доступа к UV-координатам вершин используется массив
mesh.getVerticesData(BABYLON.VertexBuffer.UVKind). Этот
массив содержит пары чисел [u0, v0, u1, v1, ...],
соответствующие каждой вершине меша. Изменение этих данных позволяет
создавать эффекты смещения текстуры, анимации текстурных координат и
процедурную генерацию UV.
Пример изменения UV-координат:
const mesh = BABYLON.MeshBuilder.CreatePlane("plane", { size: 2 }, scene);
const uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
for (let i = 0; i < uvs.length; i += 2) {
uvs[i] += 0.1; // сдвиг по U
uvs[i + 1] += 0.1; // сдвиг по V
}
mesh.updateVerticesData(BABYLON.VertexBuffer.UVKind, uvs);
Нормали — это векторы, перпендикулярные поверхности модели в каждой
вершине. Они необходимы для корректного освещения и расчета отражений. В
Babylon.js нормали хранятся в массиве
mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind).
Нормали обычно нормализованы, то есть имеют длину 1.
Основные применения нормалей:
Пример вычисления нормали для пользовательского меша:
const positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
const indices = mesh.getIndices();
const normals = [];
BABYLON.VertexData.ComputeNormals(positions, indices, normals);
mesh.updateVerticesData(BABYLON.VertexBuffer.NormalKind, normals);
Тангенты — это векторы, лежащие в плоскости поверхности и направленные по оси U текстуры. Тангенты необходимы для корректного применения нормальных карт, чтобы преобразовать данные нормалей из текстурного пространства в мировое или локальное пространство шейдера.
Babylon.js автоматически генерирует тангенты через
BABYLON.VertexData.ComputeTangents, если меш содержит
UV-координаты и нормали:
const positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
const indices = mesh.getIndices();
const normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
const uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
const tangents = [];
BABYLON.VertexData.ComputeTangents(positions, indices, uvs, normals, tangents);
mesh.updateVerticesData(BABYLON.VertexBuffer.TangentKind, tangents);
Тангенты передаются в шейдер как vTangent для вершинного
или фрагментного шейдера и используются для построения
TBN-матрицы (Tangent-Bitangent-Normal), которая
позволяет корректно трансформировать нормали из текстурного
пространства:
TBN = [Tangent, Bitangent, Normal]
Где Bitangent вычисляется как перекрестное произведение нормали и тангента с учётом направления w-компоненты тангента.
В Babylon.js создание шейдера с поддержкой нормалей, тангентов и UV
осуществляется через ShaderMaterial. Пример передачи данных
в шейдер:
const shaderMaterial = new BABYLON.ShaderMaterial("shader", scene, {
vertex: "custom",
fragment: "custom",
}, {
attributes: ["position", "normal", "uv", "tangent"],
uniforms: ["worldViewProjection", "world"]
});
mesh.material = shaderMaterial;
В вершинном шейдере:
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
attribute vec4 tangent;
varying vec2 vUV;
varying vec3 vNormal;
varying vec3 vTangent;
varying vec3 vBitangent;
void main() {
vUV = uv;
vNormal = normalize(normalMatrix * normal);
vTangent = normalize(normalMatrix * tangent.xyz);
vBitangent = cross(vNormal, vTangent) * tangent.w;
gl_Position = worldViewProjection * vec4(position, 1.0);
}
Фрагментный шейдер может использовать TBN-матрицу для применения нормальных карт:
varying vec2 vUV;
varying vec3 vNormal;
varying vec3 vTangent;
varying vec3 vBitangent;
uniform sampler2D normalMap;
void main() {
vec3 N = texture2D(normalMap, vUV).rgb;
N = N * 2.0 - 1.0;
mat3 TBN = mat3(vTangent, vBitangent, vNormal);
vec3 finalNormal = normalize(TBN * N);
// расчет освещения с finalNormal
}
Эта архитектура работы с UV, нормалями и тангентами позволяет создавать реалистичное освещение, нормальные карты, а также любые сложные визуальные эффекты, требующие точного управления пространственными данными поверхности.