在OpenGL中如何将原语渲染为线框?

在OpenGL中如何将原语渲染为线框?

153662 次浏览

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);
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

要打开电源,

glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

回归正常。

注意,如果启用了纹理映射和照明,它们仍然会应用到线框线上,这看起来可能很奇怪。

最简单的方法是将原语绘制为GL_LINE_STRIP

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

假设在OpenGL 3及以上版本中有一个向前兼容的上下文,你可以像前面提到的那样使用glPolygonMode,但请注意,粗细超过1px的行现在已弃用。所以当你可以画三角形作为线框时,它们需要非常细。在OpenGL ES中,你可以在同样的限制下使用GL_LINES

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

相反,你可以做的,也将在OpenGL ES中工作是使用片段 shader。考虑在三角形上应用线框三角形的纹理。除了不需要纹理之外,它可以通过程序生成。说够了,我们开始编码吧。片段着色器:

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提供更多数据要慢。

你可以这样使用供过于求的库:

  1. 为球体:

    glutWireSphere(radius,20,20);
    
  2. for a Cylinder:

    GLUquadric *quadratic = gluNewQuadric();
    gluQuadricDrawStyle(quadratic,GLU_LINE);
    gluCylinder(quadratic,1,1,1,12,1);
    
  3. for a Cube:

    glutWireCube(1.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();
}

通知:

  • 对于积分,将layout (line_strip, max_vertices=3) out;改为layout (points, max_vertices=3) out;
  • < a href = " https://open。gl/geometry" rel="noreferrer">阅读更多关于几何着色器

如果你处理的是OpenGL ES 2.0,你可以从中选择一个绘制模式常量

GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES,来画线,

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

GL_TRIANGLE_STRIPGL_TRIANGLE_FAN,和GL_TRIANGLES来绘制填充三角形

作为你的第一个论点

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

glDrawArrays(GLenum mode, GLint first, GLsizei count)调用。

如果您使用的是固定管道(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来改变行宽

否则,你需要在你的绘制方法(glDrawElements, glDrawArrays等)中改变多边形模式,你可能会得到一些粗略的结果,因为你的顶点数据是三角形的,你是输出线。为了获得最好的结果,可以考虑使用几何着色器或为线框创建新数据。

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

使用这个函数:

void glPolygonMode(GLenum face, GLenum mode);

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

mode:定义了三种模式。

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

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

  • GL_FILL:填充多边形的内部。

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

有关更多信息,请参阅khronos组中的OpenGL引用页