Как указано в предыдущем разделе, 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 glVertexAttrib1f(GLint location, GLfloat v0);
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 glVertexAttrib1fARB(GLint location, GLfloat v0);
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».
Фаза установки после линковки программы:

loc = glGetAttribLocation(p,«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 vertices[8] = {1,1, 1,1, 1,-1, 1,-1};
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