单通线框问题

时间:2014-05-15 17:21:36

标签: opengl glsl shader geometry-shader

我正在尝试实现单通线框,但我在这个过程中遇到了几个问题。

问题#1

出于某些原因,在我的几何着色器工作之后,我只得到没有线框(比如glPolygoneMode - 线)填充几何体。

wireframe

但如果我禁用几何着色器,我会得到几何体:

filled polygons

  
    

我真正想要实现的是几何体及其线框。

  

问题#2

实际上,我的图元是三角形条。我使用它们来避免在四边形上使用以提高性能。如何在绘制时跳过线框的边缘? (我已经看到了post如何做到这一点,但我仍然不清楚。)

以下是我的着色器:

顶点着色器:

#version 330
//
// (C) Copyright 2010 Patrick Cozzi and Deron Ohlarik
//
// Distributed under the MIT License.
// See License.txt or http://www.opensource.org/licenses/mit-license.php.
//

layout(location = 0) in vec3 in_Position;

uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform mat4 og_viewportTransformationMatrix;

out vec2 windowPosition;

vec4 og_ClipToWindowCoordinates(vec4 v, mat4 viewportTransformationMatrix);

void main()                     
{
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(in_Position, 1.0);

    windowPosition = og_ClipToWindowCoordinates(gl_Position, og_viewportTransformationMatrix).xy;
}

vec4 og_ClipToWindowCoordinates(vec4 v, mat4 viewportTransformationMatrix)
{
    v.xyz /= v.w;                                                  // normalized device coordinates
    v.xyz = (viewportTransformationMatrix * vec4(v.xyz, 1.0)).xyz; // window coordinates
    return v;
}

Geomerty着色器:

#version 330 
//
// (C) Copyright 2010 Patrick Cozzi and Deron Ohlarik
//
// Distributed under the MIT License.
// See License.txt or http://www.opensource.org/licenses/mit-license.php.
//

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

in vec2 windowPosition[];
noperspective out vec3 distanceToEdges;

float og_distanceToLine(vec2 f, vec2 p0, vec2 p1);

void main()
{
    vec2 p0 = windowPosition[0];
    vec2 p1 = windowPosition[1];
    vec2 p2 = windowPosition[2];

    gl_Position = gl_in[0].gl_Position;
    distanceToEdges = vec3(og_distanceToLine(p0, p1, p2), 0.0, 0.0);
    EmitVertex();

    gl_Position = gl_in[1].gl_Position;
    distanceToEdges = vec3(0.0, og_distanceToLine(p1, p2, p0), 0.0);
    EmitVertex();

    gl_Position = gl_in[2].gl_Position;
    distanceToEdges = vec3(0.0, 0.0, og_distanceToLine(p2, p0, p1));
    EmitVertex();
}

float og_distanceToLine(vec2 f, vec2 p0, vec2 p1)
{
    vec2 l = f - p0;
    vec2 d = p1 - p0;

    //
    // Closed point on line to f
    //
    vec2 p = p0 + (d * (dot(l, d) / dot(d, d)));
    return distance(f, p);
}

片段着色器:

#version 330
//
// (C) Copyright 2010 Patrick Cozzi and Deron Ohlarik
//
// Distributed under the MIT License.
// See License.txt or http://www.opensource.org/licenses/mit-license.php.
//

uniform float u_halfLineWidth;
uniform vec3 u_color;

noperspective in vec3 distanceToEdges;
out vec4 fragmentColor;

void main()
{
    float d = min(distanceToEdges.x, min(distanceToEdges.y, distanceToEdges.z));

    if (d > u_halfLineWidth + 1.0)
    {
        discard;
    }

    d = clamp(d - (u_halfLineWidth - 1.0), 0.0, 2.0);
    fragmentColor = vec4(u_color, exp2(-2.0 * d * d));
}

帮我弄清楚我错在哪里。

更新

我已经更新Fragment shaderGeometry shader提及Andon M. Coleman的回答,但问题2 中描述的问题仍未解决。

enter image description here

更新2

我刚刚在fragmet着色器中做了一些小编辑,这解决了我的问题。

更新片段着色器

#version 330
//
// (C) Copyright 2010 Patrick Cozzi and Deron Ohlarik
//
// Distributed under the MIT License.
// See License.txt or http://www.opensource.org/licenses/mit-license.php.
//

uniform float u_halfLineWidth;
uniform vec3 u_color;

noperspective in vec3 distanceToEdges;
out vec4 fragmentColor;

void main()
{
    float d = min(distanceToEdges.y, max(distanceToEdges.x, distanceToEdges.z));

    if (d > u_halfLineWidth + 1.0)
    {
        fragmentColor =  vec4(u_color, 1);
        return;
    }

    fragmentColor = vec4(vec3(0,0,0), 1);
}

1 个答案:

答案 0 :(得分:3)

您的第一个问题与您使用discard

有关

目前, 丢弃 片段与片段着色器中线框的距离不合适。这是不正确的行为,这将 绘制线框。

您需要做的是用不同颜色替换discard

if (d > u_halfLineWidth + 1.0)
{
    //discard; // DO NOT DO THIS

    //
    // Instead, do this
    //
    fragmentColor = vec4 (0.0, 0.0, 0.0, 1.0);
    return;
}

当然,这将生成黑色填充网格,但如果使用颜色u_color,则网格的填充部分将与线框无法区分。最终你可能想要定义一个与线框颜色分开的每顶点颜色,但是由你来决定如何做到这一点。


对于问题#2,通过调整边距来解决:

您链接的文章中的想法是,对于几何着色器发出的每个三角形,它应该为每个顶点写入相对边缘的距离。如果您知道三角形中的一条边是 内部 边缘,因此不应包含在线框中,则应设置顶点的距离 与该边 相对,它从不插入 0 (或您为线框选择的任何宽度)。

以下对GS的修改将删除三角形条的内边缘:

void main()
{
    vec2 p0 = windowPosition[0];
    vec2 p1 = windowPosition[1];
    vec2 p2 = windowPosition[2];

    // Alternate between using the first and last vertex as the one opposite the
    // interior edge based on primitive ID.
    bool strip_flip = (bool (gl_PrimitiveIDIn & 1));

    gl_Position = gl_in[0].gl_Position;
    if (strip_flip)
      distanceToEdges = vec3(og_distanceToLine(p0, p1, p2), 0.0, 0.0);
    else
      distanceToEdges = vec3(og_distanceToLine(p0, p1, p2), 0.0, 99999.0);
    EmitVertex();

    gl_Position = gl_in[1].gl_Position;
    if (strip_flip)
      distanceToEdges = vec3(99999.0, og_distanceToLine(p1, p2, p0), 0.0);
    else
      distanceToEdges = vec3(0.0,     og_distanceToLine(p1, p2, p0), 99999.0);
    EmitVertex();

    gl_Position = gl_in[2].gl_Position;
    if (strip_flip)
      distanceToEdges = vec3(99999.0, 0.0, og_distanceToLine(p2, p0, p1));
    else
      distanceToEdges = vec3(    0.0, 0.0, og_distanceToLine(p2, p0, p1));
    EmitVertex();
}

这通过在第一个/最后一个顶点之间交替工作,该顶点用作与条带插入的内边缘相对的顶点。对于每个奇数三角形,内边缘与第一个顶点相对,对于每个偶数三角形,它与最后一个相对。这基本上是三角形条带的操作方式,每个连续的三角形上的绕组都是相反的,这使得识别哪个边缘变得容易。

为确保distanceToEdges永远不会在此边缘方向上插入小于或等于u_HalfLineWidth + 1.0的任何内容,所述坐标将从其正常的 0.0 值推送到<强> 99999.0

因此,如果您参考下图中的虚线边缘,则Q为99999.0:

Edge Diagram

想象一下,在虚线边缘反映出一个三角形,然后你应该对几何着色器的作用有了很好的了解。