2013-08-29 198 views
1

vertex shaderGLSL如何使用幾何着色器顯示法線?

#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); 

代碼工作打算,除了我不知道是妥善安排我的法線:它們被存儲爲字節(作爲b/FF轉換爲GLfloat),座標xyz改變了,有些可能需要nega灰。

有人可以告訴我geometry shaderhttp://blogs.agi.com/insight3d/index.php/2008/10/23/geometry-shader-for-debugging-normals/(這些着色器根本不起作用,並且在頂點和片段着色器之間丟失的數據中看起來/在數據中)顯示的線條顯示法線。

P.S.我不確定我是否正確地做了一切(啓動OpenGL和GLSL),所以還有任何建議。

編輯: 我的例子

// 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(); 
} 

變得簡單geometry shader,但我不knwo它需要gl_ModelViewProjectionMatrix(似乎不建議使用)和結果看起來可怕,似乎一切,包括剝離法線。圖片在glPolygonMode(GL_FRONT,GL_LINE)模式下,紋理也試圖映射到那些。 enter image description here

+0

爲什麼不能使用該代碼?這非常簡單。它將來自應用程序的法線傳遞給頂點着色器,並將法線傳遞給幾何着色器。在GS中,它簡單地使用頂點位置和偏移頂點位置來產生線段,即頂點位置沿着頂點法線翻譯了一些距離,兩者都用MVP矩陣進行變換。而已。 – thokra

+0

我無法想象如何爲此製作幾何着色器。我做了簡單的傳遞,我把vs中的params放在'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編程指南第8版」學習,還有'core'在例子中。但是,我似乎理解了這個想法,並且現在它如何更好地發揮作用。 – user2091150