[OpenGL] Концепции и приложения VAO, VBO, EBO в OpenGL

1.VBO (объекты буфера вершин, VBO)

VBO: Объект буфера вершин — это область буфера памяти, созданная в области памяти графической карты, которая используется для хранения различных типов информации атрибутов вершин, таких как координаты вершин, векторы вершин и данные цвета вершин. Во время рендеринга различные атрибутные данные вершин могут быть взяты непосредственно из VBO. Поскольку VBO находится в видеопамяти, а не в памяти, ему не нужно передавать данные из CPU, и эффективность обработки выше.

Можно создать много VBO, и каждый VBO имеет свой уникальный идентификационный идентификатор в OpenGL. Этот идентификатор соответствует конкретному адресу видеопамяти VBO. Через этот идентификатор можно получить доступ к данным в конкретном VBO.

(1) Создать VBO, чтобы открыть пространство видеопамяти и назначить VBO ID

GLuint vboid; glGenBuffers(1,

Прототип: void glGenBuffers(GLsizei n​, GLuint * buffers​);

Что влияет на ФПС в Minecraft


n: Укажите количество имен объектов буфера для генерации
buffers: Укажите массив, в котором хранятся имена сгенерированных объектов буфера

(2) Созданный VBO можно использовать для хранения различных типов данных вершин. После создания указанные VBO должны быть связаны с назначенным идентификатором. Только один VBO может быть привязан к одному и тому же типу данных вершин одновременно. Операция привязки осуществляется через glBindBuffer;

glBindBuffer(GL_ARRAY_BUFFER, vboId);

Прототип: void glBindBuffer(GLenum target​, GLuint buffer​);
target: Указывает целевой тип буфера
buffer: Имя объекта буфера

целевая классификация: GL_ARRAY_BUFFER, GL_ATOMIC_COUNTER_BUFFER, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, GL_DRAW_INDIRECT_BUFFER, GL_DISPATCH_INDIRECT_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_QUERY_BUFFER, GL_SHADER_STORAGE_BUFFER, GL_TEXTURE_BUFFER, GL_TRANSFORM_FEEDBACK_BUFFER, GL_UNIFORM_BUFFER

Примечание: вышеуказанные типы используются в соответствии с различными версиями OpenGL. Сегодня мы используем GL_ARRAY_BUFFER, который используется для привязки массива вершин. Какие другие типы? Я не буду здесь много объяснять. Если вы хотите узнать больше, перейдите к OpenGL WIKI документ, там будет более подробное объяснение https://www.khronos.org/opengl/wiki/Main_Page

(3) Вызовите glBufferData для передачи пользовательских данных в текущий связанный буфер видеопамяти

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

Прототип: void glBufferData(GLenum target​, GLsizeiptr size​, const GLvoid * data​, GLenum usage​);
targe: Тип VBO такой же, как и выше
size: Размер VBO
data: Укажите данные для передачи, которые могут быть пустыми
usage: Разработать метод хранения VBO

Типы использования: GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, GL_DYNAMIC_COPY

STREAM: Содержимое хранилища данных будет изменено один раз и использовано несколько раз;

Оптимизация СОДИУМА — МИФ? Sodium vs Optifine


STATIC: Содержимое хранилища данных будет изменено один раз и использовано несколько раз;
DYNAMIC: Содержимое хранилища данных будет многократно изменяться и использоваться несколько раз;
DRAW: Приложение изменяет содержимое хранилища данных и использует его в качестве источника для команд рисования GL и спецификации изображения;
READ: Изменить содержимое хранилища данных, читая данные из GL, и возвращать эти данные при запросе приложения;
COPY: Изменить содержимое хранилища данных, читая данные из GL и использовать их в качестве источника для команд рисования GL и спецификации изображения;

Здесь мы используем GL_STATIC_DRAW. Для других случаев, пожалуйста, обратитесь к документации OpenGL WIKI.

(4) Вызовите glVertexAttribPointer, чтобы сообщить OpenGL, как интерпретировать эти данные вершин

glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
void glVertexAttribPointer(GLuint index​, GLint size​, GLenum type​, GLboolean normalized​, GLsizei stride​, const GLvoid * pointer​); void glVertexAttribIPointer(GLuint index​, GLint size​, GLenum type​, GLsizei stride​, const GLvoid * pointer​); void glVertexAttribLPointer(GLuint index​, GLint size​, GLenum type​, GLsizei stride​, const GLvoid * pointer​);

Читайте также:  Как увеличить контрастность в Майнкрафт

index: Укажите положение атрибута вершины, соответствующее макету (location = 0) в вершинном шейдере
size: Размер атрибута вершины
type: Тип данных, определенный параметром
stride: Размер шага, определяющий интервал между последовательными атрибутами вершин
pointer: Смещение наших данных о положении от начала буфера

2.VAO (объект Vertex Array, VAO)

VAO : Сохраняет комбинацию состояний всех атрибутов данных вершины, сохраняет формат данных вершины и ссылку на VBO, требуемую данными вершины.

(1) Создание и настройка VAO

GLuint vaoId; glGenVertexArrays(1, glBindVertexArray(vaoId);

После выполнения привязки VAO все ваши конфигурации VBO позже становятся частью этого объекта VAO.Можно сказать, что VBO — это привязка информации об атрибутах вершины, а VAO — это привязка нескольких VBO.

(2) Вся графика в OpenGL отрисовывается путем разложения на треугольники. Функция glDrawArrays рисует модель. Она использует текущий активированный шейдер, данные вершин VBO и конфигурацию атрибутов в текущем объекте VAO для рисования графики.

void glDrawArrays(GLenum mode​, GLint first​, GLsizei count​);

modeОсновные типы примитивов: GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_LINE_STRIP_ADJACENCY, GL_LINES_ADJACENCY, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES__L_TRIANGLR_GLTR

first: Укажите, какой бит в буфере начать рисование, обычно определяется как 0
count: Укажите количество вершин для рисования

3.EBO (Элемент Элемента Буфера, EBO)

EBO : Индексный буферный объект EBO эквивалентен концепции массива вершин в OpenGL,Чтобы решить проблему множественных повторных вызовов в одну и ту же вершину, можно уменьшить потери памяти и повысить эффективность., Когда нужны повторяющиеся вершины, эта вершина вызывается индексом позиции вершины.

Содержимое, хранящееся в EBO, является индексом местоположения. EBO аналогично VBO, а также является частью буфера памяти в видеопамяти.

(1) Создать EBO и связать его, использовать glBufferData, взять GL_ELEMENT_ARRAY_BUFFER в качестве параметра и сохранить индекс в EBO

GLuint EBO; glGenBuffers(1, glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

(2) При рисовании модели в виде индекса вершины, связанной с EBO, необходимо использовать glDrawElements

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

Прототип: void glDrawElements(GLenum mode​, GLsizei count​, GLenum type​, const GLvoid * indices​);
mode: Основные типы примитивов, GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_LINE_STRIP_ADJACENCY, GL_LINES_ADJACENCY, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN_GL_TRIANGLAD_TRIANGLAD_TRIANGLAD_TRIANGLAD_TRIANGLAD_TRIANGLAD_TRIANGLAD_TRIANGLAD_TRIANGLAD_TRIANGLAD_TRIANGLAD_TRIANGLAD_ GLIAN
count: Количество нарисованных вершин
type: Тип данных вершины, должен быть GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT ,, GL_UNSIGNED_INT
indices: Дополнительная настройка смещения в EBO

4. Применение:

1. Нарисуйте квадрат с VBO_VAO

#include #include void MyInit(); void reshape(int w, int h); void display(); GLuint vboId; GLuint vaoId; int main(int argc, char **argv) < glutInit( glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutInitWindowPosition(100, 100); glutInitWindowSize(512, 512); glutCreateWindow(«VBO_VAO_RECTANGLE»); glewInit(); MyInit(); glutReshapeFunc( glutDisplayFunc( glutMainLoop(); return 0; >void MyInit() < glClearColor(0.0,0.0, 0.0,0.0); const GLfloat vertices[] = < -0.5f,-0.5f,0.0f,1.0f, 0.5f,-0.5f,0.0f,1.0f, 0.5f,0.5f,0.0f,1.0f, -0.5f,0.5f,0.0f,1.0f, >; // Создаем объект VAO glGenVertexArrays(1, glBindVertexArray(vaoId); // Создаем объект VBO glGenBuffers(1, glBindBuffer(GL_ARRAY_BUFFER, vboId); // Входящие данные VBO glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // Unbind VBO glBindBuffer(GL_ARRAY_BUFFER, 0); > void reshape(int w, int h) < glViewport(0, 0,(GLsizei)w, (GLsizei)h); >void display() < glClear(GL_COLOR_BUFFER_BIT); // Связывание VBO glBindBuffer(GL_ARRAY_BUFFER, vboId); glEnableVertexAttribArray(0); // Интерпретировать режим вершинных данных glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); // Нарисовать модель glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableVertexAttribArray(0); glutSwapBuffers(); >

Читайте также:  Майнкрафт как сохранить игру

Посмотрим эффект

2.VEO рисовать квадрат

#include #include #include void MyInit(); void reshape(int w, int h); void display(); GLuint vboId; GLuint vaoId; GLuint eboId; int main(int argc, char **argv) < glutInit( glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutInitWindowPosition(100, 100); glutInitWindowSize(512, 512); glutCreateWindow(«EBO_VBO_VAO_RECTANGLE»); glewInit(); MyInit(); glutReshapeFunc( glutDisplayFunc( glutMainLoop(); return 0; >void MyInit() < glClearColor(0.0, 0.0, 0.0, 0.0); const GLfloat vertices[] = < -0.5f,-0.5f,0.0f,1.0f, 0.5f,-0.5f,0.0f,1.0f, 0.5f,0.5f,0.0f,1.0f, -0.5f,0.5f,0.0f,1.0f, >; GLshort indices[] = < 0, 1, 3, // первый треугольник 1, 2, 3 // второй треугольник >; // Создаем объект VAO glGenVertexArrays(1, glBindVertexArray(vaoId); // Создаем объект VBO glGenBuffers(1, glBindBuffer(GL_ARRAY_BUFFER, vboId); // Входящие данные VBO glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // Создать объект EBO glGenBuffers(1, glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId); // Входящий объект EBO glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // Интерпретировать режим вершинных данных glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); // Unbind VAO glBindVertexArray(0); // Unbind VBO glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind EBO glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); > void reshape(int w, int h) < glViewport(0, 0, (GLsizei)w, (GLsizei)h); >void display() < glClear(GL_COLOR_BUFFER_BIT); glBindVertexArray(vaoId); // Нарисовать модель glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL); glutSwapBuffers(); >

Посмотрите на эффект

Источник: russianblogs.com

Что такое параметр «Использовать VBO»?

В снимке 14w29b в меню «Настройки видео» появилась новая опция под названием «Использовать VBO»:

В обновлении снапшота говорится, что включение опции «Vertex Buffer Objects» должно увеличить ваш FPS в среднем на 5-10%.

Я ищу простое объяснение того, что VBO делают визуально и как они работают.

21 2014-07-18T08:43:20+00:00 3
Редактировал вопрос 18-го июля 2014 в 9:51
Решение / Ответ
18-го июля 2014 в 11:13
2014-07-18T11:13:44+00:00
Дополнительно

Ответ, данный Flaunting, правильный, но если кому-то интересно, почему это может быть более эффективно, вот объяснение.

В немедленном режиме (я думаю, это стандартный случай в minecraft), когда вы хотите отрисовать, скажем, квадрат:

Вы будете выдавать следующие команды каждый кадр (в псевдокоде)

begin drawing draw line from (0,0) to (1,0) draw line from (1,0) to (1,1) draw line from (1,1) to (0,1) draw line from (0,1) to (0,0) end drawing

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

Используя VBOS, вы загрузите все данные вершин в память GPU в самом начале. Псевдокод может выглядеть следующим образом:

create VBO load (0,0) into VBO load (1,0) into VBO load (1,1) into VBO load (0,1) into VBO load (0,0) into VBO

Код OpenGL вернет вам ‘имя’ для этого VBO (ненулевое беззнаковое целое число, насколько я помню). Затем вы сможете ссылаться на него, когда захотите нарисовать квадрат. Таким образом, каждый кадр вам нужно будет выдавать только одну команду рисования:

draw vertices in VBO

Читайте также:  Как оплатить донат в Майнкрафт

Возможно, вам придется настроить состояние рисования так, чтобы оно использовало пары вершин для линий, но для каждого дополнительного VBO вам потребуется только один дополнительный вызов рисования. Фактически, для статической геометрии уровня (вероятно, не применимо в случае minecraft) вы можете объединить все эти вершины в один массивный VBO, если у вас достаточно памяти GPU.

Я удивлен, что ускорение составляет всего 5-10%. Возможно, это связано с динамической геометрией уровня.

Комментарии к ответу ( 6 )
Ответ на вопрос
18-го июля 2014 в 9:34
2014-07-18T09:34:31+00:00
Дополнительно

VBO означает Vertex Buffer Object (объект буфера вершин)

Vertex Buffer Object (VBO) — это функция OpenGL, которая предоставляет методы для загрузки вершинных данных (позиция, вектор нормали, цвет, и т.д.) на видеоустройство для рендеринга в неопосредованном режиме. VBO обеспечивают существенный прирост производительности по сравнению с рендерингом в немедленном режиме, прежде всего, > потому что данные сохраняются в видеоустройстве. потому что данные находятся в памяти видеоустройства, а не в системной памяти, и поэтому они могут быть отображены непосредственно видеоустройством.

Простыми словами

В minecraft, если установить значение ON, производительность увеличивается на ~10%.

Это происходит за счет снижения нагрузки на процессор и оперативную память и переназначения ее на память графического процессора. Это рекомендуется только в том случае, если у вас хорошая или приличная видеокарта.

Источник: kzen.dev

VBO: Vertex Buffer Object (Объект буфера вершин)

VBO: Vertex Buffer Object — это расширение OpenGL (ARB_vertex_buffer_object), позволяющее работать с видеопамятью в части чтения/записи/рендеринга массивов вертексов (вершин) и индексов. Поддерживается практически на всех 3D-ускорителях (все GeForce, Radeon, Quadro, FireGL, Riva TNT, большая часть интегрированных чипсетов Intel, часть карт S3 и 3DLabs), кроме самых старых (таких, как 3dfx Voodoo).

Расширение Vertex Buffer Object позволяет, в частности, размещать геометрию в видеопамяти для последующего (многократного) рендеринга или же организовывать потоковую передачу данных видеокарте (пересылка данных + рендеринг их в каждом кадре).

VBO позволяет избежать передачи больших массивов данных через шину видеокарты в каждом кадре, так как данные хранятся локально на видеокарте. Кроме того, видеопамять на современных видеокартах обычно быстрее системной (system) памяти.

На современных видеокартах VBO обеспечивает очень большое увеличение производительности (наблюдалось, например, ускорение в 1000 раз на GeForce 6800, на статической геометрии). Использовать VBO рекомендуется практически всегда, проще назвать причины, когда не следует его использовать: это либо очень маленькие массивы данных (неэффективно), либо очень большие (когда они не помещаются в свободную видеопамять).

Документация на русском по функциям буферных объектов:

glGenBuffers, glDeleteBuffers — создание/удаление буфера
glBindBuffer — переключение текущего буфера
glBufferData — выделение видеопамяти и/или запись данных
glBufferSubData, glGetBufferSubData — чтение/запись части данных буфера
glMapBuffer, glUnmapBuffer — отображение буфера в оперативную память (аналогично функциям Lock() в DirectX)
glIsBuffer — задаёт ли данный идентикатор вершинный буфер OpenGL
glGetBufferPointerv — запрос указателя на данные уже отображённого буфера
glGetBufferParameteriv — запрос параметров буфера (размер и пр.)

Что такое VBO: Vertex Buffer Object (Объект буфера вершин)?

27 июля 2005 (Обновление: 29 мар 2011)

Источник: gamedev.ru