【问题标题】:How do you render primitives as wireframes in OpenGL?如何在 OpenGL 中将基元渲染为线框?
【发布时间】:2010-09-13 08:25:16
【问题描述】:

如何在 OpenGL 中将图元渲染为线框?

【问题讨论】:

标签: opengl


【解决方案1】:
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

开启,

glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

恢复正常。

请注意,如果启用了纹理映射和光照等内容,它们仍将应用于线框线,这可能看起来很奇怪。

【讨论】:

  • 我喜欢你。还有 4 个。
【解决方案2】:

来自http://cone3d.gamedev.net/cgi-bin/index.pl?page=tutorials/ogladv/tut5

// Turn on wireframe mode
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);

// Draw the box
DrawBox();

// Turn off wireframe mode
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_FILL);

【讨论】:

  • 打两个电话是多余的。使用 GL_FRONT_AND_BACK
  • 作为@shoosh 评论的附录,红皮书指出 GL_FRONT 和 GL_BACK 已被弃用并从 OpenGL 3.1 及更高版本中删除。现在,您仍然可以通过兼容性扩展来使用它们,但是如果您可以在向前兼容和向后兼容之间进行选择,我建议您选择前者。
  • 此答案中的链接返回 404。
  • @OndrejSlinták 现在已修复。
【解决方案3】:

假设在 OpenGL 3 及更高版本中具有向前兼容的上下文,您可以使用前面提到的glPolygonMode,但请注意,现在不推荐使用粗细超过 1px 的线条。因此,虽然您可以将三角形绘制为线框,但它们需要非常薄。在 OpenGL ES 中,您可以使用 GL_LINES,但有同样的限制。

在 OpenGL 中,可以使用几何着色器来获取传入的三角形,将它们分解并将它们发送为模拟粗线的四边形(实际上是三角形对)进行光栅化。真的很简单,只是几何着色器因性能缩放而臭名昭著。

您可以做的,以及在 OpenGL ES 中也可以使用的方法是使用 fragment 着色器。考虑将线框三角形的纹理应用于三角形。除了不需要纹理外,它可以通过程序生成。但是说够了,让我们来编码吧。片段着色器:

in vec3 v_barycentric; // barycentric coordinate inside the triangle
uniform float f_thickness; // thickness of the rendered lines

void main()
{
    float f_closest_edge = min(v_barycentric.x,
        min(v_barycentric.y, v_barycentric.z)); // see to which edge this pixel is the closest
    float f_width = fwidth(f_closest_edge); // calculate derivative (divide f_thickness by this to have the line width constant in screen-space)
    float f_alpha = smoothstep(f_thickness, f_thickness + f_width, f_closest_edge); // calculate alpha
    gl_FragColor = vec4(vec3(.0), f_alpha);
}

和顶点着色器:

in vec4 v_pos; // position of the vertices
in vec3 v_bc; // barycentric coordinate inside the triangle

out vec3 v_barycentric; // barycentric coordinate inside the triangle

uniform mat4 t_mvp; // modeview-projection matrix

void main()
{
    gl_Position = t_mvp * v_pos;
    v_barycentric = v_bc; // just pass it on
}

在这里,三个三角形顶点的重心坐标只是(1, 0, 0)(0, 1, 0)(0, 0, 1)(顺序并不重要,这使得打包成三角形条可能更容易)。

这种方法的明显缺点是它会吃掉一些纹理坐标并且你需要修改你的顶点数组。可以用一个非常简单的几何着色器来解决,但我仍然怀疑它会比仅仅向 GPU 提供更多数据要慢。

【讨论】:

  • 我认为这看起来很有希望,但是这似乎不适用于 OpenGL 3.2(非 ES)。虽然我可能搞砸了一些东西,但我玩了很多次并且不确定它是如何使用的。有关您打算使用这些着色器实际渲染的任何更多信息会有所帮助;我看不出除了填充之外的任何东西会产生什么有用的东西,但考虑到 gl_FragColor 的 alpha 值在 OpenGL 3.2 中似乎完全被忽略了,这甚至不起作用......
  • 当然可以。你可以在stackoverflow.com/questions/7361582/…中参考某人对相同想法的实现。
  • 我在尝试使用您建议的实现时遇到的问题是,我认为着色器永远不会在要概述的对象之外绘制。因此,这将在被勾勒的对象上绘制轮廓?换句话说,轮廓将完全包含在要绘制的原始对象中?
  • @BrunoLevy 你可以在 webGL 中获得额外的协调,不是吗?如果你幸运的话,如果你有非常简单的模型,你也许可以从 texcoords 获得这些坐标,否则你只需要添加新坐标。如果没有它就太好了:)。您只需要为每个顶点传递一个标量(然后在顶点着色器中将其扩展为 3 向量)。
  • 啊,现在我明白了…… f_width() 在这方面是我的朋友。谢谢
【解决方案4】:

如果您使用的是固定管道 (OpenGL

//Turn on wireframe mode
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

//Draw the scene with polygons as lines (wireframe)
renderScene();

//Turn off wireframe mode
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

在这种情况下,您可以通过调用glLineWidth来更改线宽

否则,您需要在绘图方法(glDrawElements、glDrawArrays 等)中更改多边形模式,最终可能会得到一些粗略的结果,因为您的顶点数据是针对三角形的并且您正在输出线。为获得最佳效果,请考虑使用Geometry shader 或为线框创建新数据。

【讨论】:

    【解决方案5】:

    在现代 OpenGL(OpenGL 3.2 及更高版本)中,您可以为此使用几何着色器:

    #version 330
    
    layout (triangles) in;
    layout (line_strip /*for lines, use "points" for points*/, max_vertices=3) out;
    
    in vec2 texcoords_pass[]; //Texcoords from Vertex Shader
    in vec3 normals_pass[]; //Normals from Vertex Shader
    
    out vec3 normals; //Normals for Fragment Shader
    out vec2 texcoords; //Texcoords for Fragment Shader
    
    void main(void)
    {
        int i;
        for (i = 0; i < gl_in.length(); i++)
        {
            texcoords=texcoords_pass[i]; //Pass through
            normals=normals_pass[i]; //Pass through
            gl_Position = gl_in[i].gl_Position; //Pass through
            EmitVertex();
        }
        EndPrimitive();
    }
    

    注意事项:

    【讨论】:

      【解决方案6】:

      最简单的方法是将基元绘制为GL_LINE_STRIP

      glBegin(GL_LINE_STRIP);
      /* Draw vertices here */
      glEnd();
      

      【讨论】:

      • 如果它是一堆 GL_TRIANGLES:你会得到它们之间的线。在 OpenGL 1.x 或旧版中,您使用 glPolygonMode。在最近的 OpenGL 中,您使用几何着色器。
      • 这是一种古老的做事方式,需要被抛弃。
      【解决方案7】:

      你可以像这样使用 glut 库:

      1. 对于一个球体:

        glutWireSphere(radius,20,20);
        
      2. 对于圆柱体:

        GLUquadric *quadratic = gluNewQuadric();
        gluQuadricDrawStyle(quadratic,GLU_LINE);
        gluCylinder(quadratic,1,1,1,12,1);
        
      3. 对于多维数据集:

        glutWireCube(1.5);
        

      【讨论】:

        【解决方案8】:

        使用这个功能: void glPolygonMode(GLenum face, GLenum 模式);

        face :指定模式适用的多边形。多边形的正面可以是 GL_FRONT,他的背面可以是 GL_BACK,两者都可以是 GL_FRONT_AND_BACK。

        mode:定义了三种模式,可以在mode中指定:

        GL_POINT :标记为边界边缘起点的多边形顶点被绘制为点。

        GL_LINE :多边形的边界边缘被绘制为线段。 (你的目标)

        GL_FILL : 多边形内部被填充。

        P.S : glPolygonMode 控制图形管道中光栅化多边形的解释。

        有关更多信息,请查看 khronos 组中的 OpenGL 参考页面: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonMode.xhtml

        【讨论】:

          【解决方案9】:

          在非抗锯齿渲染目标上绘制抗锯齿线的一种简单而简单的方法是使用 1x4 纹理绘制 4 像素宽度的矩形,Alpha 通道值为 {0.,1.,1., 0.},并使用关闭 mip-mapping 的线性过滤。这将使线条厚 2 个像素,但您可以更改不同厚度的纹理。 这比气压计算更快更容易。

          【讨论】:

            【解决方案10】:

            如果您正在处理的是 OpenGL ES 2.0,您可以从中选择一种绘制模式常量

            GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES,画线,

            GL_POINTS(如果您只需要绘制顶点),或者

            GL_TRIANGLE_STRIPGL_TRIANGLE_FANGL_TRIANGLES 绘制实心三角形

            作为你的第一个参数

            glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)
            

            glDrawArrays(GLenum mode, GLint first, GLsizei count) 来电。

            【讨论】:

              猜你喜欢
              • 2010-12-01
              • 2013-12-11
              • 2015-05-01
              • 2013-11-25
              • 2011-11-13
              • 2021-05-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多