Войти
ПрограммированиеПодсказкиГрафика

GLSL: о причине, по которой glGetUniformLocation() может вернуть -1

Автор:

Довольно много времени потратил на раскопки по данной проблеме и решил поделиться результатами.

Ситуация - разрабатываю шейдер. Экспериментирую. Исходный код шейдера пишу в текстовом редакторе, в фоне висит программа, которая по нажатию на горячую клавишу перезагружает шейдер и демонстрирует результат. Случайно замечаю, что в лог вываливается куча ошибок, источником которых, как выяснилось позже, является функция glGetUniformLocation(), возвращающая -1. При этом программа успешно линкуется, валидация проходит без ошибок, шейдер корректно выполняется и я вижу правильную картинку. В чём же дело?

Всё очень просто. В процессе экспериментов с шейдерами возникла ситуация, когда одна или несколько uniform или attrib переменных оказались неиспользуемыми. В результате компилятор молча выкинул их, а при попытке получить их адрес функцией glGetUniformLocation() или glGetAttribLocation() честно выдавал -1, поскольку эти переменные отсутствуют. Пример:

Вершинный шейдер:

attribute vec2 a_uv;
varying vec2 v_uv;
// ...
void main() {
  // ...
  v_uv = a_uv;
}

Фрагментный шейдер:

varying vec2 v_uv;
uniform sampler2D s_tex;
// ...
void main() {
  // ...
  gl_FragColor = texture2D(s_tex, v_uv);
  gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}

Во фрагментном шейдере результат выборки из текстуры сразу же перезаписывается, поэтому varying-переменная v_uv будет признана бесполезной и будет выброшена. Вместе с ней будет выброшен атрибут a_uv, и при вызове glGetAttribLocation(sh, "a_uv") мы получим -1. Скорее всего та же участь постигнет uniform-переменную sampler2D s_tex.

Не знаю, должен ли компилятор скидывать в Info Log сообщения о таких оптимизациях, но в моём случае (Linux, nVidia, последний 310-й драйвер) Info Log пустой. Решить проблему на время разработки, когда шейдер ещё не дописан и подобная ситуация вполне уместна, можно, например, вписав вот такую строчку в конец фраргментного шейдера:

gl_FragColor.r += 0.000001*v_uv[0];

Она не окажет влияния на картинку, зато не даст компилятору съесть переменную. А ближе к финальной версии неиспользуемых переменных в шейдере само собой быть не должно .

#GLSL, #OpenGL, #шейдеры

9 декабря 2012

Комментарии [20]