Униформа GLSL только обновляется несвязанными вызовами
У меня есть чрезвычайно простая программа GLSL, которая не может правильно обновить равномерное значение после первого вызова вызова. Ошибок не получено из glGetError
, в информационных журналах не сообщается об ошибках при компиляции и связывании шейдеров, и все одинаковые местоположения действительны.
Vertex shader:
#version 120
uniform mat4 mvp;
uniform mat3 nmv;
attribute vec3 position;
attribute vec3 normal;
varying vec3 v_normal;
void main()
{
v_normal = normalize(nmv * normal);
gl_Position = mvp * vec4(position, 1.0);
}
Фрагментный шейдер:
#version 120
uniform vec3 lightDir;
uniform vec3 lightColor;
uniform vec3 materialColor;
varying vec3 v_normal;
void main()
{
vec3 n = normalize(v_normal);
float nDotL = max(0.0, dot(n, lightDir));
gl_FragColor = vec4(materialColor * lightColor * nDotL, 1.0);
}
Код визуализации:
glUseProgram(program);
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, mvp);
glUniformMatrix3fv(nmvLoc, 1, GL_FALSE, nmv);
glUniform3fv(lightDirLoc, 1, lightDir);
glUniform3fv(lightColorLoc, 1, lightColor);
for (auto mesh: meshes)
{
glUniform3fv(materialColorLoc, 1, mesh.color);
mesh.draw();
}
Представленные сетки рисуются в цвете первой сетки, указывая, что после первоначальной установки равномерности materialColor
последующие вызовы для изменения униформы игнорируются. Однако здесь приведен список особых условий, которые независимо позволяют правильно обновлять форму:
- Вызов
glUseProgram(program)
внутри цикла.
- Настройка формы
mvp
или nmv
в цикле.
- Установка
lightDir
равномерности внутри цикла.
- Удаление одного из
uniform vec3
из программы шейдеров.
Обратите внимание, что установка lightColor
равномерности в цикле будет не обновлять униформа materialColor
. Я также проверил GL_CURRENT_PROGRAM
внутри цикла, и шейдер остается связанным во всем.
Я пытаюсь исправить это в течение нескольких часов и абсолютно не могу найти проблему. Эта настройка шейдера настолько проста, что я не считаю это ошибкой драйвера. Я использую OpenGL 2.1 в Mac OS X 10.8.3 с NVIDIA GeForce 9400M.
Вот трассировка вызова для одного кадра:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(1);
glUniformMatrix4fv(1, 1, 0, 0x7fff55512550); // mvp
glUniformMatrix3fv(5, 1, 0, 0x7fff55512528); // nmv
glUniform3fv(0, 1, 0x7fff55512670); // lightDir
glUniform3fv(9, 1, 0x7fff555124e8); // lightColor
// Mesh 0
glUniform3fv(8, 1, 0x7fab820cd7ec); // materialColor
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 1);
glEnableVertexAttribArray(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000);
glEnableVertexAttribArray(2);
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 21);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Mesh 1
glUniform3fv(8, 1, 0x7fab823000bc); // materialColor
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 2);
glEnableVertexAttribArray(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000);
glEnableVertexAttribArray(2);
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 24);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Mesh 2
glUniform3fv(8, 1, 0x7fab8231f8fc); // materialColor
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 3);
glEnableVertexAttribArray(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000);
glEnableVertexAttribArray(2);
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 21);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Mesh 3
glUniform3fv(8, 1, 0x7fab820cf41c); // materialColor
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 4);
glEnableVertexAttribArray(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000);
glEnableVertexAttribArray(2);
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 18);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
CGLFlushDrawable();
EDIT: Вот код, используемый для получения однородных местоположений. Он выполняется после того, как шейдеры были скомпилированы и связаны, и все мундиры проверяются как действительные.
GLint mvpLoc = glGetUniformLocation(program, "mvp");
GLint nmvLoc = glGetUniformLocation(program, "nmv");
GLint lightDirLoc = glGetUniformLocation(program, "lightDir");
GLint lightColorLoc = glGetUniformLocation(program, "lightColor");
GLint materialColorLoc = glGetUniformLocation(program, "materialColor");
Ответы
Ответ 1
-
Иногда драйвер оптимизирует некоторые из ваших мундиров (даже если он не должен отличаться со старыми драйверами). для тестирования, которые пытаются использовать цвет материала в вершинном шейдере (скопируйте его на переменную переменную, а в шейдере фрагмента используйте переменную, а не единую переменную, которая иногда работает для меня... конечно, она немного снижает производительность)
-
попробуйте использовать другую версию профиля. В некоторых случаях более новые драйверы не эмулируют старые версии должным образом. Пробовал ли вы основной профиль? (я знаю, что его очень сложно реализовать со старым кодом)
-
вы можете попробовать nvemulate для тестирования разных настроек драйвера.
иногда забывается glEnd(); делает много проблем, пытающихся добавить этот код перед кодом рендеринга фрейма:
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
... here comes your rendering code
если это поможет, если вы не захотите вызвать glEnd(); где-то или есть glEnd; вместо glEnd();
Ответ 2
Все еще не решено?
какой тип mesh.color
глядя на адреса, переданные в трассировку вызова, они кажутся довольно высокими, возможно, вам следует передать в адрес данные не фактические данные, 0x7fab823000bc
glUniform3fv (materialColorLoc, 1, & mesh.color);
возможно, попробуйте жесткое кодирование и используйте glUniform3f()
Ответ 3
Из всех адресов в трассе я предполагаю, что любой vec3, который вы отправляете в GL, имеет тип float name[3]
, не так ли? Предполагая это, я не могу обнаружить ошибку в вашем коде. Поскольку вы заявили, что не существует состояния ошибки, возвращаемого glGetError, оно ДОЛЖНО быть ошибкой драйвера.
Я видел в трассировке, что вы запускаете каждую сетку, выполняющую glBindBuffer (GL_ARRAY_BUFFER, 0) - это действительно не нужно. Но во всяком случае, я не могу представить, что это тоже источник.
К сожалению, вы не можете тестировать такие вещи, как glBindUniformLocation, перед связыванием, поскольку это не является частью OpenGL.
Мой опыт показывает: если вы выдаете glUniform3fv, и все параметры верны, то униформа обновляется и это изменение сразу видно. Поскольку это не так, здесь это ошибка драйвера, поэтому единственное, что вы могли бы сделать: добавить другие ненужные вызовы в цикл рендеринга, чтобы сделать видимым изменение (которое вы уже сделали, если я правильно прочитал это).