Значение переменных Uniform может изменятся только примитивами, то есть не могут быть изменены между glBegin() & glEnd(). Это значит, что этот тип переменных не может быть использован, например, для хранения аттрибутов вершин. Эти переменные подходят для хранения констант, относящихся к примитиву, кадру, даже ко всей сцене. Uniform-переменные могут быть прочитаны (но не перезаписаны) обоими шейдерами, вершинным и пикселным.

Первое, что вы должны сделать — это получить адрес переменной в памяти. Учтите, что эта информация доступна только после прилинковки шейдера, то есть сначала нужен вызов (для OpenGL 2.0) glUSeProgram, или (для расширений ARB) glUSeProgramObjectARB.

Синтаксис и OpenGL 2.0 и расширений ARB при работе с переменными очень прост.
Для перехода от ARB к OGL 2.0 просто отбросьте префикс ARB от функции.

Функция получения адреса переменной в памяти в синтаксисе OpenGL 2.0:

GLint glGetUniformLocation(GLuint program, const char *name);

// Параметры:

// program — дескриптор программы
// name — имя переменной

 

И используя ARB

GLint glGetUniformLocationARB(GLhandleARB program, const char *name);

// Параметры:

// program — дескриптор программы
// name — имя переменной

 

Возвращаемое значение — адрес в памяти искомой переменной, которой затем можно присваивать значения. Существует семейство функций для установки переменных, их применение зависит от типа данных переменной. Функции для OpenGL 2.0:

void glUniform1f(GLint location, GLfloat v0);
void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);// илиGLint glUniform{1,2,3,4}fv(GLint location, GLsizei count, GLfloat *v);// Параметры:

// location — предварительно найденный адрес памяти
// v0,v1,v2,v3 — float-значения.
// count — число элементов в массиве
// v — массив float-ов.

 

Используя шейдерные расширения ARB:

void glUniform1fARB(GLint location, GLfloat v0);
void glUniform2fARB(GLint location, GLfloat v0, GLfloat v1);
void glUniform3fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
void glUniform4fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);// илиGLint glUniform{1,2,3,4}fvARB(GLint location, GLsizei count, GLfloat *v);// Параметры:

// location — предварительно найденный адрес памяти
// v0,v1,v2,v3 — float-значения.
// count — число элементов в массиве
// v — массив float-ов.

 

Подобный же список функций доступен и для целых чисел, int, при этом «f» заменяется на «i».
Функций для передачи bool не существует. Используйте 0 вместо false и что угодно вместо true.

Матрицы — тоже доступный тип данных.

OpenGL 2.0:

GLint glUniformMatrix{2,3,4}fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *v);

// Параметры:

// location — предварительно найденный адрес памяти
// count — количество матриц в массиве.
// transpose — Определяет тип матрицы. 0/1 для горизонтальной/вертикальной
// v — массив float-ов.

 

Расширения ARB:

GLint glUniformMatrix{2,3,4}fvARB(GLint location, GLsizei count, GLboolean transpose, GLfloat *v);

// Параметры:

// location — предварительно найденный адрес памяти
// count — количество матриц в массиве.
// transpose — Определяет тип матрицы. 0/1 для горизонтальной/вертикальной
// v — массив float-ов.

 

Важное замечание до какого-либо исходного кода: значения, присвоенные этими функциями, будут неизменны до следующей линковки программы. При следующей линковке значения будут сброшены до нуля.

А теперь немного кода. Предположим, будет использоватся шейдер со следующими переменными:

uniform float specIntensity;
uniform vec4 specColor;
uniform float t[2];
uniform vec4 colors[3];

 

В приложении OpenGL 2.0 присвоение им кода будет выглядеть так:

GLint loc1,loc2,loc3,loc4;
float specIntensity = 0.98;
float sc[4] = {0.8,0.8,0.8,1.0};
float threshold[2] = {0.5,0.25};
float colors[12] = {0.4,0.4,0.8,1.0,
0.2,0.2,0.4,1.0,
0.1,0.1,0.1,1.0};loc1 = glGetUniformLocation(p,«specIntensity»);
glUniform1f(loc1,specIntensity);loc2 = glGetUniformLocation(p,«specColor»);
glUniform4fv(loc2,1,sc);loc3 = glGetUniformLocation(p,«t»);
glUniform1fv(loc3,2,threshold);

loc4 = glGetUniformLocation(p,«colors»);
glUniform4fv(loc4,3,colors);

 

В приложении с шейдерными расширениями ARB это будет выглядеть так:

GLint loc1,loc2,loc3,loc4;
float specIntensity = 0.98;
float sc[4] = {0.8,0.8,0.8,1.0};
float threshold[2] = {0.5,0.25};
float colors[12] = {0.4,0.4,0.8,1.0,
0.2,0.2,0.4,1.0,
0.1,0.1,0.1,1.0};loc1 = glGetUniformLocationARB(p,«specIntensity»);
glUniform1fARB(loc1,specIntensity);loc2 = glGetUniformLocationARB(p,«specColor»);
glUniform4fvARB(loc2,1,sc);loc3 = glGetUniformLocationARB(p,«t»);
glUniform1fvARB(loc3,2,threshold);

loc4 = glGetUniformLocationARB(p,«colors»);
glUniform4fvARB(loc4,3,colors);

 

Исходные коды работающих примеров:
OpenGL 2.0
Расширения ARB

Ещё одна интересная возможность GLSL — передача адреса переменной, находящейся внутри массива.
Например, возможно получить адрес переменной t[1]. Следующий пример это продемонстрирует:

loct0 = glGetUniformLocation(p,«t[0]»);
glUniform1f(loct0,threshold[0]);loct1 = glGetUniformLocation(p,«t[1]»);
glUniform1f(loct1,threshold[1]);

 

Функция для расширения ARB точно такая же — просто добавьте префикс ARB в имя функции.