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


Answers:


367
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

开启

glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

恢复正常。

请注意,如果启用了诸如纹理贴图和光照之类的功能,它们仍将应用于线框线,这看起来很奇怪。


2
我喜欢你。还有4个。
因此

37

来自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);

75
拨打两个电话是多余的。使用GL_FRONT_AND_BACK
shoosh

6
作为@shoosh评论的附录,红皮书指出GL_FRONT和GL_BACK已被弃用,并已从OpenGL 3.1及更高版本中删除。现在,您仍然可以通过兼容性扩展来使用它们,但是如果您在向前兼容和向后兼容之间进行选择,我建议您选择前者。
Fouric 2013年

1
在这个答案的链接返回404
的OndrejSlinták

1
@OndrejSlinták现在固定。
MaxiMouse

24

假设在OpenGL 3及更高版本中具有前向兼容的上下文,则可以glPolygonMode按照前面提到的方式使用,但是请注意,现在已弃用了厚度大于1px的行。因此,尽管您可以将三角形绘制为线框,但它们必须非常细。在OpenGL ES中,可以使用GL_LINES相同的限制。

在OpenGL中,可以使用几何着色器来处理传入的三角形,对其进行分解,然后将其发送为栅格(实际上是成对的三角形)以模拟粗线,以进行栅格化。确实非常简单,只是几何着色器因性能缩放不佳而臭名昭著。

您可以改而做的,并且在OpenGL ES中也可以使用片段着色器。考虑将线框三角形的纹理应用于该三角形。除了不需要纹理外,可以按程序生成它。但是足够多的谈话,让我们编码。片段着色器:

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中似乎被完全忽略了,这甚至都不起作用
。–

2
当然可以。您可以在stackoverflow.com/questions/7361582/…中参考某人对相同想法的实现。

1
我认为,尝试使用建议的实现会遇到的问题是,着色器永远不会在要概述的对象之外进行绘制。因此,这将在被勾画的对象上绘制轮廓吗?换句话说,轮廓将完全包含在要绘制的原始对象中吗?
user1167662

1
@BrunoLevy您可以在webGL中获得更多协调,不是吗?如果幸运的话,如果您有非常简单的模型,则可以从texcoords获取这些坐标,否则,您只需添加新坐标即可。如果没有它,那就太好了:)。您需要做的就是为每个顶点传递一个标量(然后在顶点着色器中将其扩展为3个向量)。

2
啊,在这方面,我现在... f_width()是我的朋友。谢谢
Neil Gatenby

5

如果您使用的是固定管线(OpenGL <3.3)或兼容性配置文件,则可以使用

//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更改线宽

否则,您需要在draw方法内更改多边形模式(glDrawElements,glDrawArrays等),并且由于顶点数据用于三角形并且正在输出线,因此可能会得到一些粗略的结果。为了获得最佳结果,请考虑使用“ 几何”着色器或为线框创建新数据。


3

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

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

如果是一堆GL_TRIANGLES,则不会这样:您会在它们之间得到界限。在OpenGL 1.x或旧版中,您可以使用glPolygonMode。在最近的OpenGL中,您可以使用几何着色器。
Fabrice NEYRET

这是一种古老的做事方式,需要被抛在后面。
Benny Mackney

2

在现代OpenGL(OpenGL 3.2及更高版本)中,您可以为此使用Geometry Shader:

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

注意事项:


1

您可以使用如下的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);
    

0

在非抗锯齿渲染目标上绘制抗锯齿线的一种好简单方法是绘制具有1x4纹理,alpha通道值为{0.,1.,1.,0。}的4像素宽度的矩形。 ,并在关闭mip映射的情况下使用线性过滤。这将使线条2像素粗,但是您可以更改纹理的厚度。这比重量计算更快,更容易。


0

使用此函数:void glPolygonMode(GLenum face,GLenum mode);

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

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

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

GL_LINE:将多边形的边界线绘制为线段。(您的目标)

GL_FILL:填充多边形的内部。

PS:glPolygonMode控制图形管线中栅格化的多边形解释。

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


-1

如果您使用的是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) 电话。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.