Отображение смещения тесселяции GLSL

в моем недавнем проекте я работаю с аппаратной тесселяцией. Конвейер, который я хочу реализовать, должен взять низкополигональную сетку, разбить ее на мозаику и применить карту смещения.

Тесселяция работает нормально, как я и ожидал. Однако, когда я применяю карту смещения в шейдере оценки тесселяции, я получаю несколько случайный вывод.

Это вывод без смещения (я использовал карту высот в качестве текстуры, чтобы проверить, точны ли мои texCoords)

введите здесь описание изображения

Вот что я получаю, когда включаю смещение (используя одну и ту же текстуру как для окраски, так и для смещения):

введите здесь описание изображения

Код шейдера выглядит следующим образом:

//ВЕРШИННЫЙ ШЕЙДЕР

#version 430

layout(location = 0) in vec4 vertex;
layout(location = 1) in vec4 normal;
layout(location = 2) in vec2 texCoord;

out vec3 vPosition;
out vec3 vNormal;
out vec2 vTexCoord;

void main() {
    vPosition = vertex.xyz;
    vNormal = normal.xyz;
    vTexCoord = texCoord;
}

//УПРАВЛЕНИЕ ТЭСС

#version 430

layout(vertices = 3) out;

in vec3 vPosition[];
in vec3 vNormal[];
in vec2 vTexCoord[];
out vec3 tcPosition[];
out vec3 tcNormal[];
out vec2 tcTexCoord[];

uniform float innerTessLevel;
uniform float outerTessLevel;

void main(){

    float inTess  = innerTessLevel;
    float outTess = outerTessLevel;

    tcPosition[gl_InvocationID] = vPosition[gl_InvocationID];
    tcNormal[gl_InvocationID]   = vNormal[gl_InvocationID];
    tcTexCoord[gl_InvocationID] = vTexCoord[gl_InvocationID];
    if(gl_InvocationID == 0) {
        gl_TessLevelInner[0] = inTess;
        gl_TessLevelInner[1] = inTess;
        gl_TessLevelOuter[0] = outTess;
        gl_TessLevelOuter[1] = outTess;
        gl_TessLevelOuter[2] = outTess;
        gl_TessLevelOuter[3] = outTess;
    }
}

//ТЕСС ОЦЕНКА

#version 430

layout(triangles, equal_spacing, ccw) in;

in vec3 tcPosition[];
in vec3 tcNormal[];
in vec2 tcTexCoord[];
out vec3 tePosition;
out vec2 teTexCoord;

uniform mat4 ModelViewProjection;
uniform mat4 ModelView;

uniform sampler2D texHeight;

void main(){
    vec3 p0 = gl_TessCoord.x * tcPosition[0];
    vec3 p1 = gl_TessCoord.y * tcPosition[1];
    vec3 p2 = gl_TessCoord.z * tcPosition[2];
    vec3 pos = p0 + p1 + p2;

    vec3 n0 = gl_TessCoord.x * tcNormal[0];
    vec3 n1 = gl_TessCoord.y * tcNormal[1];
    vec3 n2 = gl_TessCoord.z * tcNormal[2];
    vec3 normal = normalize(n0 + n1 + n2);

    vec2 tc0 = gl_TessCoord.x * tcTexCoord[0];
    vec2 tc1 = gl_TessCoord.y * tcTexCoord[1];
    vec2 tc2 = gl_TessCoord.z * tcTexCoord[2];  
    teTexCoord = tc0 + tc1 + tc2;

    float height = texture(texHeight, teTexCoord).x;
    pos += normal * (height * 0.2f);

    gl_Position = ModelViewProjection * vec4(pos, 1);
    tePosition = vec3(ModelView * vec4(pos,1.0)).xyz;
}

//ГЕОМЕТРИЯ

#version 430

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

uniform mat4 ModelView;

in vec3 tePosition[3];
in vec3 tePatchDistance[3];
in vec2 teTexCoord[3];
out vec3 gFacetNormal;
out vec2 gTexCoord;

void main() {
    vec3 A = tePosition[2] - tePosition[0];
    vec3 B = tePosition[1] - tePosition[0];
    vec4 N = vec4( normalize(cross(A, B)) , 0.0);
    gFacetNormal = N.xyz;

    gTexCoord = teTexCoord[0];
    gl_Position = gl_in[0].gl_Position; EmitVertex();

    gTexCoord = teTexCoord[1];
    gl_Position = gl_in[1].gl_Position; EmitVertex();

    gTexCoord = teTexCoord[2];
    gl_Position = gl_in[2].gl_Position; EmitVertex();

    EndPrimitive();
}

//ФРАГМЕНТ

#version 430

layout(location = 0) out vec4 fragColor;

in vec3 gFacetNormal;
in vec2 gTexCoord;

uniform float lit;
uniform vec3 light;
uniform sampler2D texHeight;

void main() {
    #ifndef ORANGE_PURPLE
        vec3 color = gl_FrontFacing ? vec3(1.0,0.0,0.0) : vec3(0.0,0.0,1.0);
    #else
        vec3 color = gl_FrontFacing ? vec3(1.0,0.6,0.0) : vec3(0.6,0.0,1.0);
    #endif
    if (lit > 0.5) {
        color = texture(texHeight, gTexCoord).xyz; 
        vec3 N = normalize(gFacetNormal);
        vec3 L = light;
        float df = abs(dot(N,L));
        color = df * color;

        fragColor = vec4(color,1.0);
    }
    else {
        fragColor = vec4(color,1.0);
    }
}

Было бы неплохо, если бы кто-нибудь помог мне в этом.


person Basti Vagabond    schedule 11.06.2014    source источник
comment
Не должно ли смещение всегда быть обращено наружу от поверхности, учитывая нестандартную текстуру (прямо сейчас у вас есть некоторые области, где смещение перемещает вершины внутри цилиндра)? Я сильно подозреваю, что что-то не так с вашим обычным расчетом в TES. Возможно, вы могли бы передать нормаль, вычисленную в TES, геометрии/фрагменту и визуализировать ее, чтобы увидеть, правильно ли она выглядит?   -  person Andon M. Coleman    schedule 11.06.2014
comment
На самом деле: выход gFacetNormal определен только для вашей первой вершины в шейдере геометрии. Выходы должны быть установлены после каждого EmitVertex (...) в соответствии со спецификацией GLSL, иначе они будут неопределенными. Многие реализации повторно используют последний набор значений, но вы не можете полагаться на это поведение, если хотите, чтобы это работало переносимо. Вам нужно установить gFacetNormal один раз перед каждым EmitVertex. void EmitVertex () - Выдает текущие значения выходных переменных в текущий выходной примитив. При возврате из этого вызова значения выходных переменных не определены.   -  person Andon M. Coleman    schedule 11.06.2014
comment
Спасибо за совет!!! Я бы не подумал, что это сработает, но на самом деле это был «gFacetNormal», который все испортил. Я отредактирую код для всех, кто заинтересован в реализации процедуры.   -  person Basti Vagabond    schedule 12.06.2014


Ответы (1)


Благодаря @AndonM.Coleman я решил проблему

Фактически: вывод gFacetNormal определен только для вашей первой вершины в шейдере геометрии. Выходы должны быть установлены после каждого EmitVertex (...) в соответствии со спецификацией GLSL, иначе они будут неопределенными. Многие реализации повторно используют последний набор значений, но вы не можете полагаться на это поведение, если хотите, чтобы это работало переносимо. Вам нужно установить gFacetNormal один раз перед каждым EmitVertex. void EmitVertex() - "Выдает текущие значения выходных переменных в текущий выходной примитив. При возврате из этого вызова значения выходных переменных не определены."

Глупо с моей стороны этого не замечать, но вот рабочий код:

//ВЕРШИНА

#version 430

layout(location = 0) in vec4 vertex;
layout(location = 1) in vec4 normal;
layout(location = 2) in vec2 texCoord;

out vec3 vPosition;
out vec3 vNormal;
out vec2 vTexCoord;

void main() {
    vPosition = vertex.xyz;
    vNormal = normal.xyz;
    vTexCoord = texCoord;
}

//УПРАВЛЕНИЕ МОССЕЛЯЦИЕЙ

#version 430

layout(vertices = 3) out;

in vec3 vPosition[];
in vec3 vNormal[];
in vec2 vTexCoord[];
out vec3 tcPosition[];
out vec3 tcNormal[];
out vec2 tcTexCoord[];

uniform float innerTessLevel;
uniform float outerTessLevel;

void main(){

    float inTess  = innerTessLevel;
    float outTess = outerTessLevel;

    tcPosition[gl_InvocationID] = vPosition[gl_InvocationID];
    tcNormal[gl_InvocationID]   = vNormal[gl_InvocationID];
    tcTexCoord[gl_InvocationID] = vTexCoord[gl_InvocationID];
    if(gl_InvocationID == 0) {
        gl_TessLevelInner[0] = inTess;
        gl_TessLevelInner[1] = inTess;
        gl_TessLevelOuter[0] = outTess;
        gl_TessLevelOuter[1] = outTess;
        gl_TessLevelOuter[2] = outTess;
        gl_TessLevelOuter[3] = outTess;
    }
}

//ОЦЕНКА МОССЕЛЯЦИИ

#version 430

layout(triangles, equal_spacing, ccw) in;

in vec3 tcPosition[];
in vec3 tcNormal[];
in vec2 tcTexCoord[];
out vec3 tePosition;
out vec2 teTexCoord;
out vec3 teNormal;

uniform mat4 ModelViewProjection;
uniform mat4 ModelView;

uniform sampler2D texHeight;

void main(){
    vec3 p0 = gl_TessCoord.x * tcPosition[0];
    vec3 p1 = gl_TessCoord.y * tcPosition[1];
    vec3 p2 = gl_TessCoord.z * tcPosition[2];
    vec3 pos = p0 + p1 + p2;

    vec3 n0 = gl_TessCoord.x * tcNormal[0];
    vec3 n1 = gl_TessCoord.y * tcNormal[1];
    vec3 n2 = gl_TessCoord.z * tcNormal[2];
    vec3 normal = normalize(n0 + n1 + n2);

    vec2 tc0 = gl_TessCoord.x * tcTexCoord[0];
    vec2 tc1 = gl_TessCoord.y * tcTexCoord[1];
    vec2 tc2 = gl_TessCoord.z * tcTexCoord[2];  
    teTexCoord = tc0 + tc1 + tc2;

    float height = texture(texHeight, teTexCoord).x;
    pos += normal * (height * 0.5f);

    gl_Position = ModelViewProjection * vec4(pos, 1);
    teNormal    = vec3(ModelView * vec4(normal,0.0)).xyz;
    tePosition  = vec3(ModelView * vec4(pos,1.0)).xyz;
}

//ГЕОМЕТРИЯ

#version 430

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

uniform mat4 ModelView;

in vec3 tePosition[3];
in vec2 teTexCoord[3];
in vec3 teNormal[3];
out vec3 gFacetNormal;
out vec2 gTexCoord;

void main() {

    gFacetNormal = teNormal[0];
    gTexCoord = teTexCoord[0];
    gl_Position = gl_in[0].gl_Position; EmitVertex();

    gFacetNormal = teNormal[1];
    gTexCoord = teTexCoord[1];
    gl_Position = gl_in[1].gl_Position; EmitVertex();

    gFacetNormal = teNormal[2];
    gTexCoord = teTexCoord[2];
    gl_Position = gl_in[2].gl_Position; EmitVertex();

    EndPrimitive();
}

//ФРАГМЕНТ

#version 430

layout(location = 0) out vec4 fragColor;

in vec3 gFacetNormal;
in vec2 gTexCoord;

uniform float lit;
uniform vec3 light;
uniform sampler2D texHeight;

void main() {
    #ifndef ORANGE_PURPLE
    vec3 color = gl_FrontFacing ? vec3(1.0,0.0,0.0) : vec3(0.0,0.0,1.0);
    #else
        vec3 color = gl_FrontFacing ? vec3(1.0,0.6,0.0) : vec3(0.6,0.0,1.0);
    #endif
    if (lit > 0.5) {
        color = texture(texHeight, gTexCoord).xyz; 
        vec3 N = normalize(gFacetNormal);
        vec3 L = light;
        float df = abs(dot(N,L));
        color = df * color;
        fragColor = vec4(color,1.0);
    }
    else {
        fragColor = vec4(color,1.0);
    }
}
person Basti Vagabond    schedule 12.06.2014
comment
Честно говоря, я немного в замешательстве. Это единственное изменение? Геометрический шейдер запускается после тесселяции, поэтому действительно странное смещение не должно решаться модификацией GS. Что это может решить, так это проблемы с освещением. - person Andon M. Coleman; 12.06.2014
comment
Ну, как я прокомментировал ваш совет, я тоже был довольно сбит с толку. Но код шейдера — единственное, что я редактировал. Что касается этих изменений, я изменил только вывод для каждой вершины, и, поскольку я все равно прохожу нормали через ВСЕ этапы, я удалил расчет нормалей в геометрическом шейдере. - person Basti Vagabond; 13.06.2014