Передача значений из моей Java-программы в GLSL с использованием lwjgl

Допустим, у меня есть довольно сложный фрагментный шейдер для определения того, сколько света попадает на каждый пиксель:

//shaders/screen.frag
varying vec4 vertColor; //unlit color
float intensity = 1.0; //lighting intensity.

//parameters vary from material to material:
float roughness_rms; //root-mean-square roughness (um).
float peak_angle; //how steep peaks are on average.
/* more parameters */

void main(){
    /* complex shader code to calculate intensity */
    gl_FragColor = intensity*vertColor; //set the light strength
}

Вот как я инициализирую шейдеры:

//something.java
import <needed crap>
int shader, fragShader;
shader=ARBShaderObjects.glCreateProgramObjectARB();
fragShader=createFragShader("shaders/screen.frag");
ARBShaderObjects.glAttachObjectARB(shader, fragShader);
ARBShaderObjects.glLinkProgramARB(shader);
ARBShaderObjects.glValidateProgramARB(shader);

И как я их использую:

//something.java
ARBShaderObjects.glUseProgramObjectARB(shader);
GL11.glBegin(GL11.GL_QUADS);
//etc.

Мой Java-код вычисляет roughness_rms и другие параметры из различных материалов. Кроме того, эти параметры меняются при ударах пулями и т. д. Мой вопрос: как я могу передать переменные из моей java в язык шейдеров, не регенерируя весь шейдер и не перекомпилируя его (это было бы медленно). В идеале, для каждого четырехугольника, который я рисую, я хотел бы обновлять параметры шейдера.


person Kevin Kostlan    schedule 15.05.2011    source источник


Ответы (1)


Вам нужно взглянуть на «Униформы» в спецификациях GLSL< /а>.

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

Эта переменная существует в рамках всей программы (т. е. вершинного шейдера + фрагментного шейдера + дополнительных геометрических шейдеров и шейдеров тесселяции); если вы хотите использовать его, скажем, в вершинном шейдере И фрагментном шейдере, вам нужно будет объявить его в обоих, но вам нужно будет установить его только один раз в коде на стороне клиента.

Чтобы фактически установить переменную, вам нужно запросить местоположение униформы (по имени), пока ваша программа активна. Это расположение стабильно, пока программа не перекомпилируется, поэтому вы можете кэшировать ее и повторно использовать, если хотите. Установленное вами значение также будет сохраняться до тех пор, пока программа не будет перекомпилирована.

Например, чтобы установить одно число с плавающей запятой (это OpenGL 3+; я не уверен, что синтаксис точно такой же ниже этого уровня).

В вашем шейдере:

uniform float my_value;

В вашем клиентском коде:

glUseProgram(program_id);
GLint my_value_loc = glGetUniformLocation(program_id, "my_value");
glUniform1f(my_value_loc, 1.0);
glUseProgram(0);

Вот ссылка на glGetUniformLocation (которая проста в использовании) и glUniformXX, который немного сложнее (множество вариантов для установить целые числа, числа с плавающей запятой, массивы, матрицы и т. д.).

person Nicolas Lefebvre    schedule 15.05.2011
comment
У меня не работают эти функции. Я пытаюсь использовать «ARBShaderObjects.glUseProgram», но это не работает. Если их нет в классе ARbShaderObjects lwjgl, то где они? - person Kevin Kostlan; 16.05.2011
comment
О, я заработал. Вы используете класс GL20 и применяете команды к шейдеру, а не к фрагментарному шейдеру. - person Kevin Kostlan; 16.05.2011
comment
Я не могу говорить о специфике lwjgl (в основном я использую OpenGL с python), но я исправляю свой пост, чтобы уточнить, что униформы применяются ко всей программе, а не к отдельному шейдеру. - person Nicolas Lefebvre; 16.05.2011