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 1.4:
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 2.1:[3], OpenGL 3.x[4] и 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

[править | править код]

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

/*       Функция для чтения текстового файла в выделенный буфер char       */
char* filetobuf(char *file)
{
    FILE *fptr;
    long length;
    char *buf;

    fptr = fopen(file, "rb"); /* Открываем файл для чтения */
    if (!fptr) /* Возвращаем NULL в случае ошибки */
        return NULL;
    fseek(fptr, 0, SEEK_END); /* Находим конец файла */
    length = ftell(fptr); /* Вычисляем размер файла в байтах */
    buf = malloc(length 1); /* Выделяем буфер на единицу больше для файла и нулевого указателя */
    fseek(fptr, 0, SEEK_SET); /* Переходим обратно на начало файла */
    fread(buf, length, 1, fptr); /* Считываем содержимое файла в буфер */
    fclose(fptr); /* Закрываем файл */
    buf[length] = 0; /* Ставим нулевой указатель в качестве метки конца буфера */

    return buf; /* Возвращаем полученный буфер */
}


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

/*----------------- "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);
}
/*--------------------------------------------------------------*/


Фрагментный шейдер:

/*---------------- "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);
/*---------------------------------------------------------------*/

Примечания

[править | править код]
  1. GL_NV_vertex_array_range Whitepaper. Архивировано 22 мая 2013 года.
  2. ATI_vertex_array_object. Архивировано 22 мая 2013 года.
  3. OpenGL 2.1 function reference. Архивировано 22 мая 2013 года.
  4. OpenGL 3.3 function reference. Архивировано 22 мая 2013 года.
  5. OpenGL 4.2 function reference. Дата обращения: 5 мая 2013. Архивировано из оригинала 22 мая 2013 года.