2013-08-29 2 views
1

У меня есть vertex shaderGLSL Как показать нормали с помощью Geometry shader?

#version 330 core 

layout(location = 0) in vec3 VertexPosition; 
layout(location = 1) in vec2 VertexUV; 
layout(location = 2) in vec3 VertexNormal; 

out VS_GS_VERTEX 
{ 
    vec2 UV; 
    vec3 vs_worldpos; 
    vec3 vs_normal; 
} vertex_out; 

uniform mat4 proj_matrix; 
uniform mat4 model_matrix; 

void main(void) 
{ 
    gl_Normal = VertexNormal; 
    gl_Position = proj_matrix * vec4(VertexPosition, 1.0); 

    vertex_out.UV = VertexUV; //VertexPosition.xy; 
    vertex_out.vs_worldpos = gl_Position.xyz; 
    vertex_out.vs_normal = mat3(model_matrix) * gl_Normal; 
} 

и fragment shader

#version 330 core 

in GS_FS_VERTEX 
{ 
    vec2 UV; 
    vec3 vs_worldpos; 
    vec3 vs_normal; 
} vertex_in; 

// Values that stay constant for the whole mesh. 
uniform sampler2D sampler0; 
uniform sampler2D sampler1; 
uniform sampler2D sampler2; 
uniform sampler2D sampler3; 
//uniform sampler2D alphamap0; 
uniform sampler2D alphamap1; 
uniform sampler2D alphamap2; 
uniform sampler2D alphamap3; 
uniform int tex_count; 

uniform vec4 color_ambient = vec4(0.75, 0.75, 0.75, 1.0); 
uniform vec4 color_diffuse = vec4(0.25, 0.25, 0.25, 1.0); 
//uniform vec4 color_specular = vec4(1.0, 1.0, 1.0, 1.0); 
uniform vec4 color_specular = vec4(0.1, 0.1, 0.1, 0.25); 
uniform float shininess = 5.0f; 
uniform vec3 light_position = vec3(12.0f, 32.0f, 560.0f); 

void main(){ 
    vec3 light_direction = normalize(light_position - vertex_in.vs_worldpos); 
    vec3 normal = normalize(vertex_in.vs_normal); 
    vec3 half_vector = normalize(light_direction + normalize(vertex_in.vs_worldpos)); 
    float diffuse = max(0.0, dot(normal, light_direction)); 
    float specular = pow(max(0.0, dot(vertex_in.vs_normal, half_vector)), shininess); 
    gl_FragColor = texture(sampler0, vertex_in.UV) * color_ambient + diffuse * color_diffuse + specular * color_specular; 

    // http://www.opengl.org/wiki/Texture_Combiners 
    // GL_MODULATE = * 
    // GL_INTERPOLATE Blend tex0 and tex1 based on a blending factor = mix(texel0, texel1, BlendFactor) 
    // GL_INTERPOLATE Blend tex0 and tex1 based on alpha of tex0 = mix(texel0, texel1, texel0.a) 
    // GL_ADD = clamp(texel0 + texel1, 0.0, 1.0) 
    if (tex_count > 0){ 
     vec4 temp = texture(sampler1, vertex_in.UV); 
     vec4 amap = texture(alphamap1, vertex_in.UV); 
     gl_FragColor = mix(gl_FragColor, temp, amap.a); 
    } 
    if (tex_count > 1){ 
     vec4 temp = texture(sampler2, vertex_in.UV); 
     vec4 amap = texture(alphamap2, vertex_in.UV); 
     gl_FragColor = mix(gl_FragColor, temp, amap.a); 
    } 
    if (tex_count > 2){ 
     vec4 temp = texture(sampler3, vertex_in.UV); 
     vec4 amap = texture(alphamap3, vertex_in.UV); 
     gl_FragColor = mix(gl_FragColor, temp, amap.a); 
    } 
} 

Он принимает индексируется GL_TRIANGLE_STRIP в качестве входных данных

glBindBuffer(GL_ARRAY_BUFFER, tMt.vertex_buf_id[cx, cy]); 
glVertexAttribPointer(VERTEX_LAYOUT_POSITION, 3, GL_FLOAT, false, 0, pointer(0)); 
glEnableVertexAttribArray(0); 

{ chunk tex position } 
glBindBuffer(GL_ARRAY_BUFFER, chunkTexPositionBO); 
glVertexAttribPointer(VERTEX_LAYOUT_TEX_UV, 2, GL_FLOAT, false, 0, pointer(0)); 
glEnableVertexAttribArray(1); 

glBindBuffer(GL_ARRAY_BUFFER, tMt.normal_buf_id[cx, cy]); 
glVertexAttribPointer(VERTEX_LAYOUT_NORMAL, 3, GL_FLOAT, true, 0, pointer(0)); 
glEnableVertexAttribArray(2); 

{ index buffer } 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunkIndexBO); 

for i := 0 to tMt.texCount - 1 do begin 
    bt := tMt.texture_buf_id[cx, cy][i]; 
    if bt = nil then 
    break; 
    glUniform1i(proj_tex_count_loc, i); 
    glActiveTexture(GL_TEXTURE0 + i); 
    glBindTexture(GL_TEXTURE_2D, bt.id); 

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

    if i > 0 then begin 
    // this time, use blending: 
    glActiveTexture(GL_TEXTURE4 + 1); 
    glBindTexture(GL_TEXTURE_2D, tMt.alphamaps[cx, cy][i - 1]); 

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    end; 
end; 

glDrawElements(GL_TRIANGLE_STRIP, length(chunkIndexArr), GL_UNSIGNED_SHORT, nil); 

код работает как задумано, за исключением я не уверен, что это мои нормалей организованы должным образом: они были сохранены как байты (преобразованные в GLfloat как b/FF), координаты xyz изменены, а некоторые, возможно, нуждаются в nega Тион.

Может ли кто-нибудь показать мне geometry shader, чтобы показать нормали как линии, как показано на http://blogs.agi.com/insight3d/index.php/2008/10/23/geometry-shader-for-debugging-normals/ (эти шейдеры вообще не работают, и они выглядят вне/в данных, расположенных между вершинами и фрагментами шейдеров).

P.S. Я не уверен, что сделал все правильно (начиная с OpenGL и GLSL), поэтому любые предложения также были оценены.

Edit: Я сделал простой geometry shader примерами

// This is a very simple pass-through geometry shader 
#version 330 core 

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

in VS_GS_VERTEX 
{ 
    vec2 UV; 
    vec3 vs_worldpos; 
    vec3 vs_normal; 
} vertex_in[]; 

out GS_FS_VERTEX 
{ 
    vec2 UV; 
    vec3 vs_worldpos; 
    vec3 vs_normal; 
} vertex_out; 

uniform float uNormalsLength = 0.5; 

void main() 
{ 
    int i; 
    // Loop over the input vertices 
    for (i = 0; i < gl_in.length(); i++) 
    { 
     vertex_out.UV = vertex_in[i].UV; 
     vertex_out.vs_worldpos = vertex_in[i].vs_worldpos; 
     vertex_out.vs_normal = vertex_in[i].vs_normal; 

     // Copy the input position to the output 
     gl_Position = gl_PositionIn[i]; 
     EmitVertex(); 

     gl_Position = gl_ModelViewProjectionMatrix * (gl_PositionIn[i] + (vec4(vertex_in[i].vs_normal, 0) * uNormalsLength)); 
     gl_FrontColor = vec4(0.0, 0.0, 0.0, 1.0); //gl_FrontColorIn[i]; 
     EmitVertex();  
    } 
    // End the primitive. This is not strictly necessary 
    // and is only here for illustrative purposes. 
    EndPrimitive(); 
} 

, но я не knwo, где она принимает gl_ModelViewProjectionMatrix (кажется устаревшей) и результат выглядит ужасно, кажется, все, включая нормали раздели. Изображение в режиме glPolygonMode (GL_FRONT, GL_LINE), текстуры также пытаются сопоставить их. enter image description here

+0

Почему этот код не работает? Это совершенно просто. Он передает нормали из приложения в вершинный шейдер и передает нормали через шейдер геомерти. В GS он просто генерирует сегмент линии, используя положение вершины и положение вершины смещения, т. Е. Положение вершин, переведенное на некоторое расстояние по нормальной вершине, оба преобразуются с помощью матрицы MVP. Вот и все. – thokra

+0

Я не могу понять, как сделать для этого «геометрический шейдер». Я сделал простую перестановку, где я выставляю params из vs как 'in' и помещаю их как« out », но ничего не отображается (скомпилировано без ошибок). – user2091150

+0

Что нужно выяснить? Геометрический шейдерный код находится прямо на странице, с которой вы связаны. Вы можете легко адаптировать это к GLSL 330 без проблем. Попробуйте это сначала, а затем вернитесь с более конкретными вопросами. Или вы не знаете, как работают геометрические шейдеры? – thokra

ответ

5

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

Либо сделайте это за два прохода, то есть один проход для сетки, другой для нормалей или попробуйте испустить исходный треугольник и вырожденный треугольник для нормали. Для простоты я бы для версии два прохода:

Внутри вашей визуализации цикла:

  • визуализация рельефа местности
  • тогда и только тогда, когда отладка геометрия должны быть воспроизведен
    • позволяет отладочному нормалей шейдерных
    • делают местность сетки во второй раз, проходя ТОЧЕК в вершинный шейдер

Для выполнения этой работы вам понадобится второй программный объект, который составлен, как и в предыдущем сообщении в блоге, состоящем из простого шейдера вершинного шейдера, следующего геометрического шейдера и фрагментарного шейдера для раскраски линии, представляющие нормали.

Шейдеры вершин и фрагментов не должны быть проблемой. Предполагая, что у вас есть сглаженная сетка, т. Е. У вас есть фактические, усредненные нормали вершин, вы можете просто передать точки и испустить линии.

#version 330 core 

// assuming you have vertex normals, you need to render a vertex 
// only a single time. with any other prim type, you may render 
// the same normal multiple times 
layout (points) in; 

// Geometry shaders can only output points, line strips or triangle 
// strips by definition. you output a single line per vertex. therefore, 
// the maximum number of vertices per line_strip is 2. This is effectively 
// the same as rendering distinct line segments. 
layout (line_strip, max_vertices = 2) out; 

in  vec3 vs_normal[]; 
uniform float normal_scale = 0.5; // don't forget: this is the default value! 

/* if you're never going to change the normal_scale, consider simply putting a 
    constant there instead: 
    const float normal_scale = 0.5; 
*/ 

void main() 
{ 
    // we simply transform and emit the incoming vertex - this is v0 of our 
    // line segment 
    vec4 v0  = gl_in[0].gl_Position; 
    gl_Position = gl_ModelViewProjectionMatrix * v0; 
    EmitVertex(); 

    // we calculate v1 of our line segment 
    vec4 v1  = v0 + vec4(vs_normal[0] * normal_scale, 0); 
    gl_Position = gl_ModelViewProjectionMatrix * v1; 
    EmitVertex(); 

    EndPrimitive(); 
} 

Предупреждение: Непроверенные код!

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

Примечание: Этот код по-прежнему использует gl_ModevelViewProjectionMatrix. Если вы пишете основной код GL, подумайте о замене устаревших конструкций GL, таких как матричный стек, своими собственными вещами!

Примечание 2: Ваша геометрия затенения не то, что обычно называют проход через шейдер. Во-первых, вы обрабатываете входящие данные, а не просто присваиваете входящие значения исходящим значениям. Во-вторых, как это может быть проходной шейдер, если вы создаете геометрию? Проходные средства, вы не делаете ничего, кроме , переходите входящие значения на следующий этап шейдера.

+0

Спасибо за подробный ответ! – user2091150

+0

Итак, я предполагаю, что это работает? :) – thokra

+0

Чтение еще. Еще не уверен, что такое «Если вы пишете основной код GL, подумайте о замене устаревших конструкций GL» и где из «gl_ModevelViewProjectionMatrix» и т. Д. Я изучаю «Addison Wesley - OpenGL Programming Guide 8th Edition» и там «core» в примерах. Но, похоже, я понимаю идею и то, как она работает сейчас намного лучше. – user2091150