Значение для отключенных атрибутов в шейдере gsl

Я пытаюсь создать шейдер gsl, который может отключать текстурирование и/или окраску (я хочу иметь возможность окрашивать текстуру). Я могу отключить атрибут, выполнив glDisableVertexAttribArray(x), но мне интересно, как значения будут выглядеть в шейдере. они будут 0?

Кроме того, есть ли способ проверить, включен ли атрибут внутри кода шейдера? Я думал об униформе (вероятно, int) для хранения флагов и проверки их в шейдере, но для этого потребовались бы операторы if, и я думаю, что слышал, что это не рекомендуется.

Вот мои шейдеры на случай, если вы захотите на них сослаться. Сейчас я работаю над флагом int, о котором говорил.

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

#version 450

layout(location=0) uniform mat4 projection_matrix;
layout(location=1) uniform mat4 view_matrix;
layout(location=2) uniform mat4 model_matrix;

// 0b0000 0000 0000 0       unused
//                   0      textures
//                    0     colors
//                     0    2d/3d
layout(location=3) uniform uint mode;

layout(location=0) in vec4 vert_tex_coord;
layout(location=1) in vec4 vert_color;
layout(location=2) in vec3 vert_2_position;
layout(location=3) in vec3 vert_3_position;

out vec4 vert_frag_color;
out vec2 vert_frag_tex_coord;

vec4 transform(vec4 v)
{
    return projection_matrix * view_matrix * model_matrix * v;
}

void main()
{
    if ((mode & 1) > 0)
    {
        gl_Position = transform(vec4(vert_3_position, 1.0));
    }
    else
    {
        gl_Position = transform(vec4(vert_2_position, 0.0, 1.0));
    }

    if ((mode & 2) > 0)
    {
        vert_frag_color = vert_color;
    }

    if ((mode) & 4) > 0)
    {
        vert_frag_tex_coord = vert_tex_coord;
    }
}

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

#version 450

layout(location=3) uniform uint mode;

uniform sampler2D texture_0;

in vec4 vert_frag_color;
out vec2 vert_frag_tex_coord;

out vec4 frag_color;

void main()
{
    if ((mode & 2) > 1)
    {
        frag_color = vert_frag_color;
    }

    if ((mode) & 4) > 1)
    {
        frag_color = texture(texture_0, vert_frag_tex_coord);
    }
}

person Philippe Paré    schedule 15.11.2015    source источник


Ответы (1)


Я могу отключить атрибут, выполнив glDisableVertexAttribArray(x), но мне интересно, как значения будут выглядеть в шейдере. они будут 0?

Нет, на самом деле "текущее" значение каждого атрибута является частью глобального состояния GL. Вы можете установить значение для каждого атрибута, где массив отключен, через glVertexAttrib*()< /a> семейство функций. Есть только небольшой нюанс: всякий раз, когда вы рисуете что-то с включенным массивом атрибутов, а затем отключаете массив атрибутов, текущее значение этого атрибута будет неопределенным, поэтому вам нужно повторно указать его с помощью glVertexAttrib*() очередной раз.

Следующая конструкция в вашем коде вообще не имеет смысла:

if ((mode & 1) > 1)
{
    gl_Position = transform(vec4(vert_3_position, 1.0));
}
else
{
    gl_Position = transform(vec4(vert_2_position, 0.0, 1.0));
}

mode & 1 будет либо 1, либо 0, поэтому сравнение > 1 всегда будет ложным. Однако этот режим совершенно не нужен. GL автоматически расширит векторы входных атрибутов до формы (0, 0, 0, 1), если не все элементы указаны. Так что будет достаточно использовать

in vec4 vert_position;
// ...
gl_Position = transform (vert_position);

и вы можете просто указать 1, 2, 3 или 4 компонента в вызове glVertexAttribPointer() и он будет работать как положено. Идиома in vec3 position; /* ... */ matrix * vec4(position, 1.0); обычно используется в туториалах, но она совсем не нужна. Однако можно утверждать, что это делает более явным то, что на самом деле происходит.

Кроме того, есть ли способ проверить, включен ли атрибут внутри кода шейдера?

Нет, нет. Для каждого атрибута всегда существует некоторое текущее значение. Пришло ли это из массива или нет, совершенно не имеет значения для шейдера.

Я думал об униформе (вероятно, int) для хранения флагов и проверки их в шейдере, но для этого потребовались бы if операторов, и я думаю, что слышал, что это не рекомендуется.

Что ж, ветвь, основанная на юниформ-значении, все равно приведет к унифицированному потоку управления, так что это не самое худшее, что может случиться. Но это не будет бесплатно накладных расходов. Если это того стоит, то это зависит от реальных требований к вашей сцене. Возможно, было бы лучше использовать разные шейдеры и переключаться между ними. Но все зависит от того, сколько таких переключений состояния будет происходить, и сколько работы будет выполнять каждый шейдер между переключениями, а также от того, сколько комбинаций шейдеров вам потребуется. Это то, что вы должны тестировать/профилировать, предпочтительно в разных реализациях GL.

person derhass    schedule 15.11.2015
comment
Итак, если я правильно понимаю, я могу установить значение по умолчанию для своих атрибутов, когда они отключены с помощью glVertexAttrib2(,,) (для vec2), и использовать это в своем шейдере? Это на самом деле немного упростило бы мои шейдеры. Что бы я сказал, если бы у меня были vec2 pos2 и vec3 pos3, сложить их вместе, чтобы получить окончательное положение вершины? Я бы установил тот, который не используется, на 0, и это не повлияет на другой. - person Philippe Paré; 15.11.2015
comment
Я не понимаю, зачем вам вообще нужны pos2 и pos3. В вашем шейдере они никогда не нужны вам одновременно, поэтому вообще нет необходимости иметь два атрибута позиции. - person derhass; 15.11.2015
comment
Я хочу сделать шейдер, который может работать с 2D и 3D моделями! Смогу ли я использовать атрибут vec3 для моей модели vec2? - person Philippe Paré; 15.11.2015
comment
Хорошо, неважно, я просто понял, что вы объяснили о in vec4 vert_pos.. извините! Спасибо за вашу помощь, это очень ценно для меня. - person Philippe Paré; 15.11.2015