Wie rendern Sie Grundelemente in OpenGL als Drahtmodelle?
Wie rendern Sie Grundelemente in OpenGL als Drahtmodelle?
Antworten:
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
einschalten,
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
wieder normal werden.
Beachten Sie, dass Dinge wie Textur-Mapping und Beleuchtung weiterhin auf die Drahtgitterlinien angewendet werden, wenn sie aktiviert sind, was seltsam aussehen kann.
Von 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);
Unter der Annahme eines vorwärtskompatiblen Kontexts in OpenGL 3 und glPolygonMode
höher können Sie entweder wie zuvor erwähnt verwenden. Beachten Sie jedoch, dass Linien mit einer Dicke von mehr als 1 Pixel jetzt veraltet sind. Während Sie also Dreiecke als Drahtrahmen zeichnen können, müssen sie sehr dünn sein. In OpenGL ES können Sie GL_LINES
mit derselben Einschränkung verwenden.
In OpenGL ist es möglich, Geometrie-Shader zu verwenden, um eingehende Dreiecke aufzunehmen, zu zerlegen und als Quads (wirklich Dreieckspaare) zur Rasterung zu senden, die dicke Linien emulieren. Eigentlich ziemlich einfach, außer dass Geometrie-Shader für schlechte Leistungsskalierung berüchtigt sind.
Stattdessen können Sie Fragment Shader verwenden, was auch in OpenGL ES funktioniert . Denken Sie daran, eine Textur eines Drahtrahmen-Dreiecks auf das Dreieck anzuwenden. Außer dass keine Textur benötigt wird, kann sie prozedural generiert werden. Aber genug geredet, lasst uns codieren. Fragment 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);
}
Und Vertex Shader:
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
}
Hier sind die Schwerpunktkoordinaten einfach (1, 0, 0)
, (0, 1, 0)
und (0, 0, 1)
für die drei Dreiecksspitzen (die Reihenfolge spielt keine Rolle, die in Dreiecksstreifen möglicherweise einfacher macht Verpackung).
Der offensichtliche Nachteil dieses Ansatzes besteht darin, dass einige Texturkoordinaten verbraucht werden und Sie Ihr Scheitelpunktarray ändern müssen. Könnte mit einem sehr einfachen Geometrie-Shader gelöst werden, aber ich würde immer noch vermuten, dass er langsamer ist, als nur die GPU mit mehr Daten zu versorgen.
Wenn Sie die feste Pipeline (OpenGL <3.3) oder das Kompatibilitätsprofil verwenden, das Sie verwenden können
//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);
In diesem Fall können Sie die Linienbreite ändern, indem Sie glLineWidth aufrufen
Andernfalls müssen Sie den Polygonmodus in Ihrer Zeichenmethode (glDrawElements, glDrawArrays usw.) ändern, und es kann zu groben Ergebnissen kommen, da Ihre Scheitelpunktdaten für Dreiecke gelten und Sie Linien ausgeben. Für beste Ergebnisse sollten Sie einen Geometrie-Shader verwenden oder neue Daten für das Drahtmodell erstellen.
Am einfachsten ist es, die Grundelemente als zu zeichnen GL_LINE_STRIP
.
glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();
In Modern OpenGL (OpenGL 3.2 und höher) können Sie hierfür einen Geometry Shader verwenden:
#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();
}
Hinweise:
layout (line_strip, max_vertices=3) out;
zulayout (points, max_vertices=3) out;
Eine gute und einfache Möglichkeit zum Zeichnen von Anti-Alias-Linien auf einem nicht-Anti-Alias-Rendering-Ziel besteht darin, Rechtecke mit einer Breite von 4 Pixel und einer 1x4-Textur mit Alphakanalwerten von {0., 1., 1., 0.} Zu zeichnen. und verwenden Sie die lineare Filterung mit ausgeschaltetem Mip-Mapping. Dadurch werden die Linien 2 Pixel dick, Sie können jedoch die Textur für verschiedene Dicken ändern. Dies ist schneller und einfacher als barymetrische Berechnungen.
Verwenden Sie diese Funktion: void glPolygonMode (GLenum face, GLenum mode);
face: Gibt die Polygone an, für die der Modus gilt. kann GL_FRONT für die Vorderseite des Polygons und GL_BACK für seinen Rücken und GL_FRONT_AND_BACK für beide sein.
Modus: Drei Modi sind definiert und können im Modus angegeben werden:
GL_POINT: Polygonscheitelpunkte, die als Beginn einer Grenzkante markiert sind, werden als Punkte gezeichnet.
GL_LINE: Grenzkanten des Polygons werden als Liniensegmente gezeichnet. (dein Ziel)
GL_FILL: Das Innere des Polygons ist gefüllt.
PS: glPolygonMode steuert die Interpretation von Polygonen für die Rasterung in der Grafikpipeline.
Weitere Informationen finden Sie auf den OpenGL-Referenzseiten in der khronos-Gruppe: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonMode.xhtml
Wenn es sich um OpenGL ES 2.0 handelt , können Sie eine der Konstanten für den Zeichenmodus auswählen
GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES,
Linien ziehen,
GL_POINTS
(wenn Sie nur Eckpunkte zeichnen müssen) oder
GL_TRIANGLE_STRIP
, GL_TRIANGLE_FAN
Und GL_TRIANGLES
ausgefüllte Dreiecke zeichnen
als erstes Argument an Ihre
glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)
oder
glDrawArrays(GLenum mode, GLint first, GLsizei count)
Anrufe.