GLSL: о причине, по которой glGetUniformLocation() может вернуть -1
Автор: romanshuvalov
Довольно много времени потратил на раскопки по данной проблеме и решил поделиться результатами.
Ситуация - разрабатываю шейдер. Экспериментирую. Исходный код шейдера пишу в текстовом редакторе, в фоне висит программа, которая по нажатию на горячую клавишу перезагружает шейдер и демонстрирует результат. Случайно замечаю, что в лог вываливается куча ошибок, источником которых, как выяснилось позже, является функция 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];
Она не окажет влияния на картинку, зато не даст компилятору съесть переменную. А ближе к финальной версии неиспользуемых переменных в шейдере само собой быть не должно .
9 декабря 2012