Vertex Buffer Object

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

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

Спецификация Vertex Buffer Object была стандартизирована OpenGL Architecture Review Board как OpenGL версии 1.5 (в 2003). Схожая функциональность была доступна до стандартизации VBOs через расширения Nvidia "Vertex Array Range"[1] и ATI "Vertex Array Object"[2].

Основные функции VBO[править | править вики-текст]

Следующие функции составляют основу доступа и манипуляций к VBO:

В OpenGL 2.1:[3]
GenBuffersARB(sizei n, uint *buffers)
Создает n новых VBO и возвращает их ID номера как unsigned integer. Id 0 зарезервирован.
BindBufferARB(enum target, uint buffer)
Использует ранее созданный буфер как активный VBO.
BufferDataARB(enum target, sizeiptrARB size, const void *data, enum usage)
Выгружает данные в активный VBO.
DeleteBuffersARB(sizei n, const uint *buffers)
Удаляет указанные VBO из массива или VBO id.
В OpenGL 3.x[4] and OpenGL 4.x, приставку ARB у функций можно опустить:[5]
GenBuffers(sizei n, uint *buffers)
Создает n новых VBO и возвращает их ID номера как unsigned integer. Id 0 зарезервирован.
BindBuffer(enum target, uint buffer)
Использует ранее созданный буфер как активный VBO.
BufferData(enum target, sizeiptrARB size, const void *data, enum usage)
Выгружает данные в активный VBO.
DeleteBuffers(sizei n, const uint *buffers)
Удаляет указанные VBO из массива или VBO id.

Пример на Си и OpenGL 2.1[править | править вики-текст]

//Инициализация VBO - делается единожды, при старте программы
//Создание переменной для хранения идентификатора VBO
GLuint triangleVBO;
 
//Вершины треугольника (в обходе против часовой стрелки)
float data[] = {1.0, 0.0, 1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 1.0};
 
//Создание нового VBO и сохранение идентификатора VBO
glGenBuffers(1, &triangleVBO);
 
//Установка активности VBO
glBindBuffer(GL_ARRAY_BUFFER, triangleVBO);
 
//Выгрузка данных вершин в видеоустройство
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
 
 
//Рисование треугольника из VBO - происходит каждый раз, когда окно, точка обзора или данные изменяются
//Устанавливаем 3 координаты каждой вершины с 0 шагом в этом массиве; тут необходимо
glVertexPointer(3, GL_FLOAT, 0, NULL);   
 
//Сделать новую VBO активным. Повторите это, в случае изменения с инициализации
glBindBuffer(GL_ARRAY_BUFFER, triangleVBO);
 
//Данный массив содержит вершины(не нормалей, цвета, текстуры и т.д.)
glEnableClientState(GL_VERTEX_ARRAY);
 
//Рисование треугольника, указывая количества вершин
glDrawArrays(GL_TRIANGLES, 0, sizeof(data) / sizeof(float) / 3);
 
//Указание отобразить нарисованное немедленно
glFlush();

Пример на Си и OpenGL 3.x или OpenGL 4.x[править | править вики-текст]

Функция, которая может прочитать любой текстовый или двоичный файл в байтовый буфер:

/*       Function will read a text file into allocated char buffer       */
char* filetobuf(char *file)
{
    FILE *fptr;
    long length;
    char *buf;
 
    fptr = fopen(file, "rb"); /* Open file for reading */
    if (!fptr) /* Return NULL on failure */
        return NULL;
    fseek(fptr, 0, SEEK_END); /* Seek to the end of the file */
    length = ftell(fptr); /* Find out how many bytes into the file we are */
    buf = malloc(length+1); /* Allocate a buffer for the entire length of the file and a null terminator */
    fseek(fptr, 0, SEEK_SET); /* Go back to the beginning of the file */
    fread(buf, length, 1, fptr); /* Read the contents of the file in to the buffer */
    fclose(fptr); /* Close the file */
    buf[length] = 0; /* Null terminator */
 
    return buf; /* Return the buffer */
}


Вершинный шейдер:

/*----------------- "exampleVertexShader.vert" -----------------*/
 
#version 150 // Указываем версию GLSL, которую мы используем.
 
// in_Position была связана с атрибутом с индексом равным 0 ("shaderAttribute")
in  vec3 in_Position;
 
void main(void) 
{
    gl_Position = vec4(in_Position.x, in_Position.y, in_Position.z, 1.0);
}
/*--------------------------------------------------------------*/


Fragment Shader:

/*---------------- "exampleFragmentShader.frag" ----------------*/
 
#version 150 // Указываем версию GLSL, которую мы используем.
 
precision highp float; // Драйверы видеокарты требуют это для следующей строки чтобы функционировать должным образом
 
out vec4 fragColor;
 
void main(void) 
{
    fragColor = vec4(1.0,1.0,1.0,1.0); //Устанавливаем цвет каждого фрагмента в белый
}
/*--------------------------------------------------------------*/


Основная программа OpenGL:

/*--------------------- Основная программа OpenGL ---------------------*/
 
/* Создаем переменную для хранения VBO идентификатора */
GLuint triangleVBO;
 
/* Это имя программы шейдера */
GLuint shaderProgram;
 
/* Эти указатели будут получать адреса в памяти исходных кодов шейдера */
GLchar *vertexSource, *fragmentSource;
 
/* Эти переменные используются для шейдеров */
GLuint vertexShader, fragmentShader;
 
const unsigned int shaderAttribute = 0;
 
const float NUM_OF_VERTICES_IN_DATA=3;
 
/* Вершины треугольника (направление обхода: против часовой стрелки) */
float data[3][3] = {
                                           {  0.0, 1.0, 0.0   },
                                           { -1.0, -1.0, 0.0  },
                                           {  1.0, -1.0, 0.0  }
                                       };
 
/*---------------------- Инициализация VBO - (делается единожды, при запуске программы) ---------------------*/
/* Создание новго VBO и использование переменной "triangleVBO" для сохранения VBO id */
glGenBuffers(1, &triangleVBO);
 
/* Делаем новый VBO активным */
glBindBuffer(GL_ARRAY_BUFFER, triangleVBO);
 
/* Выгружаем данные в видеоустройство */
glBufferData(GL_ARRAY_BUFFER, NUM_OF_VERTICES_IN_DATA * 3 * sizeof(float), data, GL_STATIC_DRAW);
 
/* Указываем что наши данные координат в индексе атрибутов, равный 0 (shaderAttribute), и содержат 3 числа с плавающей точкой на вершину */
glVertexAttribPointer(shaderAttribute, 3, GL_FLOAT, GL_FALSE, 0, 0);  
 
/* Включаем индекс атрибутов, равный 0 (shaderAttribute), как используемый */
glEnableVertexAttribArray(shaderAttribute);
 
/* Делаем новый VBO активным */
glBindBuffer(GL_ARRAY_BUFFER, triangleVBO);
/*-------------------------------------------------------------------------------------------------------*/
 
/*--------------------- Загрузка Vertex и Fragment из файлов и их компиляция --------------------*/
/* Читаем код шейдеров в соответствующие выделенные динамически буферы */
vertexSource = filetobuf("exampleVertexShader.vert");
fragmentSource = filetobuf("exampleFragmentShader.frag");
 
/* Назначаем нашим обработчикам "имена" для новых объектов шейдера */
vertexShader = glCreateShader(GL_VERTEX_SHADER);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
 
/* Объединяем буферы исходных кодов шейдеров с соответствующими обработчиками */
glShaderSource(vertexShader, 1, (const GLchar**)&vertexSource, 0);
glShaderSource(fragmentShader, 1, (const GLchar**)&fragmentSource, 0);
 
/* Освобождаем ранее выделенную память */
free(vertexSource);
free(fragmentSource);
 
/* Компилируем наши коды шейдеров */
glCompileShader(vertexShader);
glCompileShader(fragmentShader);
/*-------------------------------------------------------------------------------------------------------*/
 
/*-------------------- Создание программы шейдера, присоединение шейдера к ней и линковка ---------------------*/
/* Назначим нашей программе обработчику имя */
shaderProgram = glCreateProgram();
 
/* Присоединяем наши шейдеры к программе шейдера */
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
 
/* Связываем индекс атрибута, равный 0, (shaderAttribute) с in_Position*/
/* "in_Position" будет представлять массив данных в вершинном шейдере*/
glBindAttribLocation(shaderProgram, shaderAttribute, "in_Position");
 
/* Линкуем программу шейдера */
glLinkProgram(shaderProgram);
/*-------------------------------------------------------------------------------------------------------*/
 
/* Установка нашей программы шейдера активной */
glUseProgram(shaderProgram);
 
/* Установка заднего фона черным */
glClearColor(0.0, 0.0, 0.0, 1.0);
 
/* Очистка цветом заднего фона */
glClear(GL_COLOR_BUFFER_BIT);
 
/* Рисование треугольника, передаются вызовом glDrawArrays номера вершин
   говоря, что наши данные треугольники и мы хотим нарисовать вершины 0-3
*/
glDrawArrays(GL_TRIANGLES, 0, 3);
/*---------------------------------------------------------------*/

См. также[править | править вики-текст]

Примечания[править | править вики-текст]

Ссылки[править | править вики-текст]