web-dev-qa-db-fra.com

Comment rendre les primitives sous forme d'images filaires dans OpenGL?

Comment rendre les primitives sous forme d'images filaires dans OpenGL?

194
Phineas
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

allumer,

glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

revenir à la normale.

Notez que des éléments tels que le mappage de texture et l'éclairage seront toujours appliqués aux lignes filaires si elles sont activées, ce qui peut paraître bizarre.

327
Mike F

De 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);
27
John Millikin

En supposant un contexte de compatibilité ascendante dans OpenGL 3 et versions ultérieures, vous pouvez utiliser glPolygonMode comme mentionné précédemment, mais notez que les lignes dont l'épaisseur est supérieure à 1px sont désormais obsolètes. Ainsi, bien que vous puissiez dessiner des triangles en tant que fil de fer, ils doivent être très minces. Dans OpenGL ES, vous pouvez utiliser GL_LINES avec la même limitation.

Dans OpenGL, il est possible d’utiliser des shaders de géométrie pour prendre les triangles entrants, les désassembler et les envoyer pour la rastérisation en tant que quads (vraiment des paires de triangles) émulant des lignes épaisses. Vraiment simple, si ce n’est que les shaders de géométrie sont connus pour leur faible mise à l’échelle des performances.

Ce que vous pouvez faire à la place, et ce qui fonctionnera également dans OpenGL ES, consiste à utiliser fragment shader. Pensez à appliquer une texture de triangle filaire au triangle. Sauf qu’aucune texture n’est nécessaire, elle peut être générée de manière procédurale. Mais assez parlé, codons. Fragment de 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);
}

Et le 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
}

Ici, les coordonnées barycentriques sont simplement (1, 0, 0), (0, 1, 0) et (0, 0, 1) pour les sommets des trois triangles (la commande importe peu, ce qui facilite l’emballage en bandes triangulaires).

L'inconvénient évident de cette approche est qu'il va manger des coordonnées de texture et que vous devez modifier votre tableau de sommets. Pourrait être résolu avec un shader de géométrie très simple, mais je pense quand même qu'il sera plus lent que de simplement alimenter le GPU avec plus de données.

18
the swine

Le moyen le plus simple consiste à dessiner les primitives sous la forme GL_LINE_STRIP.

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

Si vous utilisez le pipeline fixe (OpenGL <3.3) ou le profil de compatibilité, vous pouvez utiliser

//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);

Dans ce cas, vous pouvez modifier l’épaisseur du trait en appelant glLineWidth

Sinon, vous devez changer le mode de polygone dans votre méthode de dessin (glDrawElements, glDrawArrays, etc.) et vous obtiendrez peut-être des résultats approximatifs car vos données de sommet sont pour des triangles et vous produisez des lignes. Pour de meilleurs résultats, utilisez un Geometry shader ou créez de nouvelles données pour le fil de fer.

3
Zaphyk

Vous pouvez utiliser les bibliothèques glut comme ceci: 

  1. pour une sphère:

    glutWireSphere(radius,20,20);
    
  2. pour un cylindre: 

    GLUquadric *quadratic = gluNewQuadric();
    gluQuadricDrawStyle(quadratic,GLU_LINE);
    gluCylinder(quadratic,1,1,1,12,1);
    
  3. pour un cube:

    glutWireCube(1.5);
    
1
H.Mohcen

Dans Modern OpenGL (OpenGL 3.2 et versions ultérieures), vous pouvez utiliser un Shaometry Geder pour cela: 

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

Avis: 

1
LMD

S'il s'agit de OpenGL ES 2.0 vous traitez, vous pouvez choisir l'une des constantes en mode dessin de

GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, pour tracer des lignes,

GL_POINTS (si vous ne devez dessiner que des sommets), ou

GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN et GL_TRIANGLES pour dessiner des triangles remplis

comme premier argument à votre 

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

ou

glDrawArrays(GLenum mode, GLint first, GLsizei count) appelle. 

0
Victor