Vertex Buffer Object

Поделись знанием:
(перенаправлено с «VBO»)
Перейти к: навигация, поиск

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

Спецификация Vertex Buffer Object была стандартизирована [www.opengl.org/about/arb/ 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] и 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; /* Возвращаем полученный буфер */
}

</br> Вершинный шейдер:

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

</br> 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); //Устанавливаем цвет каждого фрагмента в белый
}
/*--------------------------------------------------------------*/

</br> Основная программа 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);
/*---------------------------------------------------------------*/

См. также

Напишите отзыв о статье "Vertex Buffer Object"

Примечания

  1. [developer.nvidia.com/object/Using_GL_NV_fence.html GL_NV_vertex_array_range Whitepaper]. [www.webcitation.org/6GnfetYhj Архивировано из первоисточника 22 мая 2013].
  2. [oss.sgi.com/projects/ogl-sample/registry/ATI/vertex_array_object.txt ATI_vertex_array_object]. [www.webcitation.org/6GnffbVde Архивировано из первоисточника 22 мая 2013].
  3. [www.opengl.org/sdk/docs/man2/ OpenGL 2.1 function reference]. [www.webcitation.org/6GnfgAXJq Архивировано из первоисточника 22 мая 2013].
  4. [www.opengl.org/sdk/docs/man3/ OpenGL 3.3 function reference]. [www.webcitation.org/6GnfgqE7p Архивировано из первоисточника 22 мая 2013].
  5. [www.opengl.org/wiki/Category:Core_API_Reference OpenGL 4.2 function reference]. [www.webcitation.org/6GnfhREmA Архивировано из первоисточника 22 мая 2013].

Ссылки

  • [www.opengl.org/registry/specs/ARB/vertex_buffer_object.txt Vertex Buffer Object Whitepaper]

Отрывок, характеризующий Vertex Buffer Object


Военный совет, на котором князю Андрею не удалось высказать свое мнение, как он надеялся, оставил в нем неясное и тревожное впечатление. Кто был прав: Долгоруков с Вейротером или Кутузов с Ланжероном и др., не одобрявшими план атаки, он не знал. «Но неужели нельзя было Кутузову прямо высказать государю свои мысли? Неужели это не может иначе делаться? Неужели из за придворных и личных соображений должно рисковать десятками тысяч и моей, моей жизнью?» думал он.
«Да, очень может быть, завтра убьют», подумал он. И вдруг, при этой мысли о смерти, целый ряд воспоминаний, самых далеких и самых задушевных, восстал в его воображении; он вспоминал последнее прощание с отцом и женою; он вспоминал первые времена своей любви к ней! Вспомнил о ее беременности, и ему стало жалко и ее и себя, и он в нервично размягченном и взволнованном состоянии вышел из избы, в которой он стоял с Несвицким, и стал ходить перед домом.
Ночь была туманная, и сквозь туман таинственно пробивался лунный свет. «Да, завтра, завтра! – думал он. – Завтра, может быть, всё будет кончено для меня, всех этих воспоминаний не будет более, все эти воспоминания не будут иметь для меня более никакого смысла. Завтра же, может быть, даже наверное, завтра, я это предчувствую, в первый раз мне придется, наконец, показать всё то, что я могу сделать». И ему представилось сражение, потеря его, сосредоточение боя на одном пункте и замешательство всех начальствующих лиц. И вот та счастливая минута, тот Тулон, которого так долго ждал он, наконец, представляется ему. Он твердо и ясно говорит свое мнение и Кутузову, и Вейротеру, и императорам. Все поражены верностью его соображения, но никто не берется исполнить его, и вот он берет полк, дивизию, выговаривает условие, чтобы уже никто не вмешивался в его распоряжения, и ведет свою дивизию к решительному пункту и один одерживает победу. А смерть и страдания? говорит другой голос. Но князь Андрей не отвечает этому голосу и продолжает свои успехи. Диспозиция следующего сражения делается им одним. Он носит звание дежурного по армии при Кутузове, но делает всё он один. Следующее сражение выиграно им одним. Кутузов сменяется, назначается он… Ну, а потом? говорит опять другой голос, а потом, ежели ты десять раз прежде этого не будешь ранен, убит или обманут; ну, а потом что ж? – «Ну, а потом, – отвечает сам себе князь Андрей, – я не знаю, что будет потом, не хочу и не могу знать: но ежели хочу этого, хочу славы, хочу быть известным людям, хочу быть любимым ими, то ведь я не виноват, что я хочу этого, что одного этого я хочу, для одного этого я живу. Да, для одного этого! Я никогда никому не скажу этого, но, Боже мой! что же мне делать, ежели я ничего не люблю, как только славу, любовь людскую. Смерть, раны, потеря семьи, ничто мне не страшно. И как ни дороги, ни милы мне многие люди – отец, сестра, жена, – самые дорогие мне люди, – но, как ни страшно и неестественно это кажется, я всех их отдам сейчас за минуту славы, торжества над людьми, за любовь к себе людей, которых я не знаю и не буду знать, за любовь вот этих людей», подумал он, прислушиваясь к говору на дворе Кутузова. На дворе Кутузова слышались голоса укладывавшихся денщиков; один голос, вероятно, кучера, дразнившего старого Кутузовского повара, которого знал князь Андрей, и которого звали Титом, говорил: «Тит, а Тит?»
– Ну, – отвечал старик.
– Тит, ступай молотить, – говорил шутник.
– Тьфу, ну те к чорту, – раздавался голос, покрываемый хохотом денщиков и слуг.
«И все таки я люблю и дорожу только торжеством над всеми ими, дорожу этой таинственной силой и славой, которая вот тут надо мной носится в этом тумане!»


Ростов в эту ночь был со взводом во фланкёрской цепи, впереди отряда Багратиона. Гусары его попарно были рассыпаны в цепи; сам он ездил верхом по этой линии цепи, стараясь преодолеть сон, непреодолимо клонивший его. Назади его видно было огромное пространство неясно горевших в тумане костров нашей армии; впереди его была туманная темнота. Сколько ни вглядывался Ростов в эту туманную даль, он ничего не видел: то серелось, то как будто чернелось что то; то мелькали как будто огоньки, там, где должен быть неприятель; то ему думалось, что это только в глазах блестит у него. Глаза его закрывались, и в воображении представлялся то государь, то Денисов, то московские воспоминания, и он опять поспешно открывал глаза и близко перед собой он видел голову и уши лошади, на которой он сидел, иногда черные фигуры гусар, когда он в шести шагах наезжал на них, а вдали всё ту же туманную темноту. «Отчего же? очень может быть, – думал Ростов, – что государь, встретив меня, даст поручение, как и всякому офицеру: скажет: „Поезжай, узнай, что там“. Много рассказывали же, как совершенно случайно он узнал так какого то офицера и приблизил к себе. Что, ежели бы он приблизил меня к себе! О, как бы я охранял его, как бы я говорил ему всю правду, как бы я изобличал его обманщиков», и Ростов, для того чтобы живо представить себе свою любовь и преданность государю, представлял себе врага или обманщика немца, которого он с наслаждением не только убивал, но по щекам бил в глазах государя. Вдруг дальний крик разбудил Ростова. Он вздрогнул и открыл глаза.
«Где я? Да, в цепи: лозунг и пароль – дышло, Ольмюц. Экая досада, что эскадрон наш завтра будет в резервах… – подумал он. – Попрошусь в дело. Это, может быть, единственный случай увидеть государя. Да, теперь недолго до смены. Объеду еще раз и, как вернусь, пойду к генералу и попрошу его». Он поправился на седле и тронул лошадь, чтобы еще раз объехать своих гусар. Ему показалось, что было светлей. В левой стороне виднелся пологий освещенный скат и противоположный, черный бугор, казавшийся крутым, как стена. На бугре этом было белое пятно, которого никак не мог понять Ростов: поляна ли это в лесу, освещенная месяцем, или оставшийся снег, или белые дома? Ему показалось даже, что по этому белому пятну зашевелилось что то. «Должно быть, снег – это пятно; пятно – une tache», думал Ростов. «Вот тебе и не таш…»
«Наташа, сестра, черные глаза. На… ташка (Вот удивится, когда я ей скажу, как я увидал государя!) Наташку… ташку возьми…» – «Поправей то, ваше благородие, а то тут кусты», сказал голос гусара, мимо которого, засыпая, проезжал Ростов. Ростов поднял голову, которая опустилась уже до гривы лошади, и остановился подле гусара. Молодой детский сон непреодолимо клонил его. «Да, бишь, что я думал? – не забыть. Как с государем говорить буду? Нет, не то – это завтра. Да, да! На ташку, наступить… тупить нас – кого? Гусаров. А гусары в усы… По Тверской ехал этот гусар с усами, еще я подумал о нем, против самого Гурьева дома… Старик Гурьев… Эх, славный малый Денисов! Да, всё это пустяки. Главное теперь – государь тут. Как он на меня смотрел, и хотелось ему что то сказать, да он не смел… Нет, это я не смел. Да это пустяки, а главное – не забывать, что я нужное то думал, да. На – ташку, нас – тупить, да, да, да. Это хорошо». – И он опять упал головой на шею лошади. Вдруг ему показалось, что в него стреляют. «Что? Что? Что!… Руби! Что?…» заговорил, очнувшись, Ростов. В то мгновение, как он открыл глаза, Ростов услыхал перед собою там, где был неприятель, протяжные крики тысячи голосов. Лошади его и гусара, стоявшего подле него, насторожили уши на эти крики. На том месте, с которого слышались крики, зажегся и потух один огонек, потом другой, и по всей линии французских войск на горе зажглись огни, и крики всё более и более усиливались. Ростов слышал звуки французских слов, но не мог их разобрать. Слишком много гудело голосов. Только слышно было: аааа! и рррр!