GLSL/C : поведение пользовательского шейдера по умолчанию

#c #opengl #glsl #shader

#c #opengl #glsl #шейдер

Вопрос:

У меня есть несколько GLSL-шейдеров, которые корректно компилируются и успешно подключаются к программе, которая правильно связывается. Я подтвердил, что другие шейдеры в моей программе работают должным образом. Странно то, что результат, который я вижу, похоже, соответствует поведению, которое я получил бы при использовании шейдеров по умолчанию (цвет, отсутствие освещения).

Я вставлю исходный код как вершинного, так и фрагментарного шейдеров, а также все выдержки из моего исходного кода на C , относящиеся к шейдерам. В комментариях я объясню любые функции или классы, уникальные для моей программы.

Мой вершинный шейдер (содержится в «dirlight.vs»)

 uniform int lightcount;
uniform vec4 lightdirs[];
uniform vec4 lightdifs[];
uniform vec4 lightambs[];
uniform vec4 lightposs[];

void main()
{
    vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
    vec4 diffuse = vec4(0.0, 0.0, 0.0, 0.0);
    for(int i = 0; i < lightcount; i  )
    {
        //Adding the diffuse term multiplied by gl_Color for each light.
        //There should be no color (0,0,0,0) if the lights are null
        diffuse  = lightdifs[i] * max(dot(normal, normalize(lightdirs[i])), 0.0) * gl_Color;
    }

    gl_FrontColor = diffuse;
    gl_Position = ftransform();
}
  

Мой фрагмент шейдера (содержится в «dirlight.fs»)

 void main()
{
    gl_FragColor = gl_Color;
}
  

Выдержка из инициализации в C main…

 //class program manages shaders
Program shaders = Program();
//attach a vertex shader, compiled from source in dirlight.vs
shaders.addShaderFile(GL_VERTEX_SHADER, "dirlight.vs");
//attach a fragment shader compiled from source in dirlight.fs
shaders.addShaderFile(GL_FRAGMENT_SHADER, "dirlight.fs");
//link program
shaders.link();
//use program
shaders.use();

//Program::getUniformLoc(const char* name) grabs the location
//of the uniform specified
GLint sTime = shaders.getUniformLoc("time");
GLint lightcount = shaders.getUniformLoc("lightcount");
GLint lightdir = shaders.getUniformLoc("lightdirs");
GLint lightdif = shaders.getUniformLoc("lightdifs");
GLint lightamb = shaders.getUniformLoc("lightambs");

glUniform1i(lightcount, 2);
GLfloat lightdirs[] = {-1.f, 1.f, 1.f, 1.f,
                       1.f, 1.f, -1.f, 1.f};
glUniform4fv(lightdir, 2, lightdirs);
GLfloat lightdifs[] = {1.f, 1.f, 1.f, 1.f,
                       1.f, 1.f, 1.f, 1.f};
glUniform4fv(lightdif, 2, lightdifs);
glUniform4f(lightamb, 0.4f, 0.4f, 0.4f, 1.f);
  

Выдержка из основного цикла в C main…

 glUniform1f(sTime, newTime);
//This should cause the light directions to rotate around the origin
GLfloat lightdirs[] = {sinf(newTime * 2.f), 1.f, cosf(newTime * 2.0f), 1.f,
                       cosf(newTime * 2.f), 1.f, sinf(newTime * 2.0f), 1.f};
glUniform4fv(lightdir, 2, lightdirs);
  

Комментарии:

1. Я так понимаю, вы создаете программный объект после того, как вы создали и сделали текущим контекст рендеринга OpenGL, и впоследствии инициализировали расширения? Пока Programm::addShaderFile непрозрачен, поскольку имеет исходный код этого, и Program::getUniformLoc может помочь.

2. В следующий раз, когда вы будете задавать вопрос GLSL, укажите версию OpenGL и версию GLSL. Вы не предоставили исходный код для процедур компиляции / загрузки шейдеров, поэтому по закону Мерфи я предполагаю, что проверка ошибок вообще не выполняется. Вы должны проверить статус компиляции шейдера и статус ссылки на программу, используя соответствующие функции API — glGetProgramiv и glGetShaderiv. Также извлеките и прочитайте информационный журнал для шейдера и программы после ссылки / компиляции. В целях отладки вы могли бы добавлять glGetError после каждого вызова OpenGL — связанного с шейдером или нет.

3. Как указано в моем вопросе, я уже подтвердил, что нет проблем с тем, как я загружаю шейдеры, загружая другие пользовательские шейдеры. Проблема либо в самом шейдере, либо в том, как я обрабатываю униформы / атрибуты.

Ответ №1:

 uniform vec4 lightdirs[];
  

Это недопустимый GLSL. Я не могу объяснить, почему ваш компилятор разрешает компиляцию (я предполагаю, что это компилятор NVIDIA, верно? Это, конечно, предполагает, что вы проверяете состояние компиляции / ссылки), но однородные массивы должны иметь длину, явно определенную в шейдере. Если вы хотите иметь массивы переменной длины, вам нужно выбрать максимальную длину и встроить ее в шейдер. Шейдер может считывать меньшее количество значений (длина зависит от введенной вами формы), но не более того.

Комментарии:

1. Спасибо! Установка максимальной длины сработала! Потрясающе. Странно, что это не дало мне никаких ошибок компиляции. Я не знаю, является ли это компилятором NVIDIA, но у меня есть видеокарта NVIDIA, если это то, что ее компилирует…

2. @MilesRufat-Latre Да, компилятор GLSL является частью графического драйвера.

3. Поскольку вы работаете на NVidia, взгляните на NVEmulate . Среди прочего, это позволяет вам установить компилятору GLSL значение «строгий», чтобы он перестал принимать конструкции CUDA. Там есть и другие интересные функции.