1

我有vertex 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 已更改,有些可能需要取反。

有人可以告诉我geometry shader将法线显示为线条,如http://blogs.agi.com/insight3d/index.php/2008/10/23/geometry-shader-for-debugging-normals/所示(那些着色器不适用于一切似乎在顶点和片段着色器之间丢失/输入数据)。

PS 我不确定我是否正确地完成了所有操作(启动 OpenGL 和 GLSL),所以任何建议也值得赞赏。

编辑:我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();
}

但我不知道它在哪里gl_ModelViewProjectionMatrix(似乎已弃用)并且结果看起来很糟糕,似乎包括法线在内的所有东西都被剥离了。在 glPolygonMode(GL_FRONT, GL_LINE) 模式下的图片,纹理也试图映射到那些。 在此处输入图像描述

4

1 回答 1

5

看起来,您一次完成所有操作,实际上每个传入三角形发出 6 个顶点。这不是你想要的。

要么分两次进行,即一次用于网格,另一次用于法线,或者尝试发出原始三角形和法线的退化三角形。为简单起见,我会选择两遍版本:

在您的渲染循环中:

  • 渲染地形
  • 当且仅当要渲染调试几何
    • 启用调试法线着色器
    • 第二次渲染地形网格,将 POINTS 传递给顶点着色器

要完成这项工作,您将需要第二个程序对象,该对象与您之前链接到的博客文章中的内容类似,包括一个简单的通槽顶点着色器、以下几何着色器和一个片段着色器,用于对表示法线。

顶点和片段着色器应该没问题。假设你有一个平滑的网格,即你有实际的平均顶点法线,你可以简单地传入点并发射线。

#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:您的几何着色器不是通常所说的通过着色器。首先,您对传入数据进行处理,而不仅仅是将传入值分配给传出值。其次,如果你生成几何图形,它怎么可能是一个直通着色器?传递意味着,除了将传入的值传递到下一个着色器阶段之外,您什么也不做。

于 2013-08-30T09:08:16.917 回答