Буферы вершин

GLVertexBuffer — вершинный буфер

Управляет хранением и обновлением данных вершин на GPU.

Создание буфера

// Буфер для вершин
var vbo = context.CreateVertexBuffer<Vertex>(BufferTargetARB.ArrayBuffer);

// Буфер для индексов
var ebo = context.CreateVertexBuffer<uint>(BufferTargetARB.ElementArrayBuffer);

Загрузка данных

Статическая загрузка (один раз)

var vertices = new[]
{
    new Vertex { Position = new FVector3(0, 1, 0) },
    new Vertex { Position = new FVector3(-1, -1, 0) },
    new Vertex { Position = new FVector3(1, -1, 0) }
};

var vbo = context.CreateVertexBuffer<Vertex>(BufferTargetARB.ArrayBuffer);
vbo.Load(vertices, BufferUsageARB.StaticDraw);

Динамическая загрузка (обновление)

// Начальная загрузка
vbo.Load(initialVertices, BufferUsageARB.DynamicDraw);

// Обновление части буфера
var newVertices = GetUpdatedVertices();
vbo.Update(0, newVertices);

Добавление данных (append)

var vbo = context.CreateVertexBuffer<Vertex>(BufferTargetARB.ArrayBuffer);
vbo.Load(vertices1, BufferUsageARB.DynamicDraw);

// Добавляем в конец
var vertices2 = GetMoreVertices();
vbo.Update(vertices2); // обновляет с текущей позиции

// Индекс теперь указывает на конец
uint newIndex = vbo.Index;

Управление позицией

var vbo = context.CreateVertexBuffer<Vertex>(BufferTargetARB.ArrayBuffer);

// Текущая позиция (в вершинах, не байтах)
uint pos = vbo.Index;

// Установить позицию
vbo.Index = 100;

// Вернуть в начало
vbo.ResetIndex();
vbo.Index = 0;

GLVertexAttributes (VAO)

Описывает формат данных вершин.

Создание и конфигурация

var vao = context.CreateVertexAttributes();
vao.Bind();

// Добавить описание атрибута
// AddAttribute(индекс, компоненты, тип, нормализовано, stride, offset)
vao.AddAttribute(
    index: 0,                               // location = 0 в шейдере
    size: 3,                                // vec3
    type: VertexAttribPointerType.Float,
    normalized: false,
    stride: 32,                             // размер структуры Vertex
    offset: 0                               // смещение от начала структуры
);

// Текстурные координаты (обычно в offset 12 для 3 флоатов позиции)
vao.AddAttribute(1, 2, VertexAttribPointerType.Float, false, 32, 12);

// Нормали (обычно в offset 20)
vao.AddAttribute(2, 3, VertexAttribPointerType.Float, false, 32, 20);

Включение/отключение

vao.Bind();

// Включить атрибут
if (vao.EnableAttribute(0))  // успешно если атрибут был добавлен
{
    // атрибут включен
}

// Отключить
vao.DisableAttribute(0);

Структура вершины

[StructLayout(LayoutKind.Sequential)]
public struct Vertex
{
    // Позиция (offset 0, размер 12 байт)
    public FVector3 Position;
    
    // Текстурные координаты (offset 12, размер 8 байт)
    public FVector2 TexCoord;
    
    // Нормаль (offset 20, размер 12 байт)
    public FVector3 Normal;
    
    // Итого: 32 байта (stride)
}

Убедитесь что структура unmanaged:

Типовый цикл отрисовки

// Инициализация (один раз)
var vertices = new[]
{
    new Vertex { Position = new FVector3(0, 1, 0), TexCoord = new FVector2(0.5f, 1f) },
    new Vertex { Position = new FVector3(-1, -1, 0), TexCoord = new FVector2(0f, 0f) },
    new Vertex { Position = new FVector3(1, -1, 0), TexCoord = new FVector2(1f, 0f) }
};

var indices = new uint[] { 0, 1, 2 };

var vbo = context.CreateVertexBuffer<Vertex>(BufferTargetARB.ArrayBuffer);
vbo.Load(vertices, BufferUsageARB.StaticDraw);

var ebo = context.CreateVertexBuffer<uint>(BufferTargetARB.ElementArrayBuffer);
ebo.Load(indices, BufferUsageARB.StaticDraw);

var vao = context.CreateVertexAttributes();
vao.Bind();
vbo.Bind();
vao.AddAttribute(0, 3, VertexAttribPointerType.Float, false, 32, 0);
vao.AddAttribute(1, 2, VertexAttribPointerType.Float, false, 32, 12);
vao.EnableAttribute(0);
vao.EnableAttribute(1);

// Отрисовка (каждый кадр)
Igdrasil.OnRender += (ctx, dt) =>
{
    shader.Apply();
    
    vao.Bind();
    ebo.Bind();
    
    ctx.DrawElements(
        PrimitiveType.Triangles,
        0,
        (uint)indices.Length,
        DrawElementsType.UnsignedInt
    );
};

Обновление вершин

// Если данные меняются каждый кадр
var vbo = context.CreateVertexBuffer<Vertex>(BufferTargetARB.ArrayBuffer);
vbo.Load(vertices, BufferUsageARB.DynamicDraw);

Igdrasil.OnUpdate += dt =>
{
    // Обновляем все вершины
    var newVertices = CalculateNewVertices(dt);
    vbo.Update(0, newVertices);
};

// Отрисовка
Igdrasil.OnRender += (ctx, dt) =>
{
    vao.Bind();
    ctx.DrawArrays(PrimitiveType.Triangles, 0, vertexCount);
};

Очистка

vbo.Dispose();     // освобождает GPU память
ebo.Dispose();
vao.Dispose();

Версия: 1.0