Как указано в предыдущем разделе, Uniform-переменные не могут использоватся в блоках glBegin/glEnd.
Если необходимо присваивать переменные каждой вершине, должны использоватся Attribute-переменные.
Фактически эти переменные могут быть обновлены в любое время. Attribute-переменные могут быть прочитаны (не перезаписаны) только вершинным шейдером, так как содержат данные вершин. Как и с Uniform-переменными, сначала необходимо получить адрес переменной в памяти. Учтите, что программа должна быть предварительно слинкована, и некоторые драйверы могут потребовать, чтобы программа уже использовалась.
В OpenGL 2.0 используйте следующие функции:
GLint glGetAttribLocation(GLuint program,char *name);
// Параметры:
// program — Дескриптор программы
// name — Имя переменной
Синтаксис шейдерных расширений ARB:
GLint glGetAttribLocationARB(GLhandleARB program,char *name);
// Параметры:
// program — Дескриптор программы
// name — Имя переменной
Эти функции вернут адрес памяти искомой переменной. Следующий шаг — указать для неё значение, потенциально — для каждой вершины.
Синтаксис OpenGL 2.0:
void glVertexAttrib2f(GLint location, GLfloat v0, GLfloat v1);
void glVertexAttrib3f(GLint location, GLfloat v0, GLfloat v1,GLfloat v2);
void glVertexAttrib4f(GLint location, GLfloat v0, GLfloat v1,,GLfloat v2, GLfloat v3);or
GLint glVertexAttrib{1,2,3,4}fv(GLint location, GLfloat *v);
// Параметры
// location — Вычисленный до этого адрес в памяти
// v0,v1,v2,v3 — float-значения.
// v — массив float-ов.
Синтаксис расширений ARB:
void glVertexAttrib2fARB(GLint location, GLfloat v0, GLfloat v1);
void glVertexAttrib3fARB(GLint location, GLfloat v0, GLfloat v1,GLfloat v2);
void glVertexAttrib4fARB(GLint location, GLfloat v0, GLfloat v1,,GLfloat v2, GLfloat v3);or
GLint glVertexAttrib{1,2,3,4}fvARB(GLint location, GLfloat *v);
// Параметры
// location — Вычисленный до этого адрес в памяти
// v0,v1,v2,v3 — float-значения.
// v — массив float-ов.
Такое же семейство функций назначено для типа данных int и других.
Теперь маленький пример. Вершинный шейдер обьявляет переменную float под названием «height».
Фаза установки после линковки программы:
В функции рендеринга код должен быть примерно таким:
glBegin(GL_TRIANGLE_STRIP);
glVertexAttrib1f(loc,2.0);
glVertex2f(—1,1);
glVertexAttrib1f(loc,2.0);
glVertex2f(1,1);
glVertexAttrib1f(loc,-2.0);
glVertex2f(—1,-1);
glVertexAttrib1f(loc,-2.0);
glVertex2f(1,-1);
glEnd();
Маленький рабочий пример:
Синтаксис расширений ARB
Синтексис OpenGL 2.0
Также возможно использовать Attribute-переменные с массивами вершин. Первое, что надо делать — включить массивы.
Синтаксис OpenGL 2.0:
void glEnableVertexAttribArray(GLint loc);
// Параметр:
// loc — адрес переменной
Синтаксис ARB:
void glEnableVertexAttribArrayARB(GLint loc);
// Параметр:
// loc — адрес переменной
Для передачи указателя на массив данных используются следующие функции.
OpenGL 2.0:
void glVertexAttribPointer(GLint loc, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
// Параметры:
// loc — Адрес переменной
// size — число компонентов на один элемент. Напр.: 1 для float, 2 для vector2, 3 для vector2 и т.п.
// type — ассоциированный тип данных: GL_FLOAT например.
// normalized — При установке в 1 данные будут нормализованы, преобразованы в от -1 до 1 для signed и
// от 0 до 1 — для unsigned
// stride — Шаг между элементами
// pointer — Указатель на массив данных
Синтаксис расширений ARB:
void glVertexAttribPointerARB(GLint loc, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
// loc — Адрес переменной
// size — число компонентов на один элемент. Напр.: 1 для float, 2 для vector2, 3 для vector2 и т.п.
// type — ассоциированный тип данных: GL_FLOAT например.
// normalized — При установке в 1 данные будут нормализованы, преобразованы в от -1 до 1 для signed и
// от 0 до 1 — для unsigned
// stride — Шаг между элементами
// pointer — Указатель на массив данных
А теперь немного кода. Сначала — инициализация. Представлено два массива, вершин и аттрибутов. Переменная heights обьявлена в глобальном пространстве, так что доступна и в этом куске кода, и в момент рендера.
float heights[4] = {2,2,-2,-2};…
loc = glGetAttribLocationARB(p,«height»);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableVertexAttribArrayARB(loc);
glVertexPointer(2,GL_FLOAT,0,vertices);
glVertexAttribPointerARB(loc,1,GL_FLOAT,0,0,heights);
Процесс рендера — точно такой же, как и без шейдеров: просто вызывайте, например, glDrawArrays().
Маленький демонстрационный исходный код:
Расширения ARB
OpenGL 2.0