Come si rendono le primitive come wireframe in OpenGL?


220

Come si rendono le primitive come wireframe in OpenGL?

opengl 

2
Sii più specifico sulla versione OpenGL che stai utilizzando.
Vertexwahn,

Con ModernGL puoi semplificare l'uso dell'attributo wireframe della classe Context
Szabolcs Dombi,

usa GL_LINES per disegnare wireframe
ossina il

Risposte:


367
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

accendere,

glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

per tornare alla normalità.

Si noti che cose come la mappatura delle trame e l'illuminazione verranno comunque applicate alle linee wireframe se sono abilitate, il che può sembrare strano.


2
Mi piaci. 4 in più per andare.
Jo So

37

Da 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
effettuare due chiamate è ridondante. usa GL_FRONT_AND_BACK
shoosh

6
Come aggiunta al commento di @ shoosh, il Red Book afferma che GL_FRONT e GL_BACK sono stati deprecati e rimossi da OpenGL 3.1 e versioni successive. Ora, puoi ancora usarli attraverso l'estensione di compatibilità, ma se hai una scelta tra compatibile con versioni precedenti e compatibili con le versioni precedenti, consiglierei di scegliere la prima.
Fouric

1
Il link in questa risposta restituisce 404.
Ondrej Slinták

1
@ OndrejSlinták Ora è stato risolto.
MaxiMouse,

24

Supponendo un contesto compatibile con il forward in OpenGL 3 e versioni successive, è possibile utilizzare glPolygonModecome indicato in precedenza, ma si noti che le linee con spessore superiore a 1 px sono ora obsolete. Quindi, mentre puoi disegnare triangoli come wireframe, devono essere molto sottili. In OpenGL ES, è possibile utilizzareGL_LINES con la stessa limitazione.

In OpenGL è possibile utilizzare gli shader della geometria per prendere triangoli in entrata, smontarli e inviarli per la rasterizzazione come quadratini (coppie di triangoli in realtà) che emulano linee spesse. Abbastanza semplice, davvero, tranne per il fatto che gli shader della geometria sono noti per il ridimensionamento delle prestazioni.

Quello che puoi fare invece e ciò che funzionerà anche in OpenGL ES è utilizzare lo shader di frammenti . Pensa ad applicare una trama di triangolo wireframe al triangolo. Tranne che non è necessaria alcuna trama, può essere generata proceduralmente. Ma basta parlare, programmiamo. Shader di frammenti:

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

E 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
}

Qui, le coordinate baricentriche sono semplicemente (1, 0, 0), (0, 1, 0)e(0, 0, 1) per i tre vertici del triangolo (l'ordine non importa, che rende imballaggio in strisce triangolo potenzialmente più semplice).

L'ovvio svantaggio di questo approccio è che consumerà alcune coordinate di trama e sarà necessario modificare l'array di vertici. Potrebbe essere risolto con uno shader di geometria molto semplice ma sospetto ancora che sarà più lento rispetto al semplice caricamento della GPU con più dati.


Ho pensato che questo sembrava promettente, tuttavia non sembra funzionare con OpenGL 3.2 (non ES). Anche se è possibile che abbia incasinato qualcosa, ci ho giocato un po 'e non sono davvero sicuro di come questo possa essere usato. Ulteriori informazioni su ciò che si intende rendere effettivamente con questi shader sarebbero utili; Non vedo come qualcosa di diverso da un riempimento produrrebbe qualcosa di utile, ma non funziona nemmeno dato che il valore alfa di gl_FragColor sembrava essere completamente ignorato in OpenGL 3.2 ...
user1167662

2
Certo che lo fa. Puoi fare riferimento all'implementazione di qualcuno della stessa idea in stackoverflow.com/questions/7361582/… .
il maiale il

1
Il problema che incontro nel tentativo di utilizzare l'implementazione suggerita è, penso, che lo shader non disegnerà mai all'esterno dell'oggetto da delineare. Questo disegnerà quindi il contorno sopra l'oggetto che viene delineato? In altre parole, il contorno sarà puramente contenuto all'interno dell'oggetto originale da disegnare?
user1167662

1
@BrunoLevy puoi coordinarti ulteriormente in webGL, no? Se sei fortunato, potresti essere in grado di ottenere quelle coordinate da texcoords se hai modelli molto semplici, ma altrimenti devi solo aggiungere nuove coordinate. Sarebbe troppo bello se funzionasse senza di esso :). Tutto ciò che serve è passare un singolo scalare per vertice (e quindi espanderlo a un vettore 3 nello shader di vertice).
il maiale

2
Ah, ora vedo ... f_width () è mio amico, a questo proposito. Grazie
Neil Gaten di

5

Se si utilizza la pipeline fissa (OpenGL <3.3) o il profilo di compatibilità che è possibile utilizzare

//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 questo caso è possibile modificare la larghezza della linea chiamando glLineWidth

Altrimenti devi cambiare la modalità poligono all'interno del tuo metodo di disegno (glDrawElements, glDrawArrays, ecc.) E potresti ottenere alcuni risultati approssimativi perché i tuoi dati di vertice sono per triangoli e stai producendo linee. Per risultati ottimali, considerare l'utilizzo di uno shader Geometry o la creazione di nuovi dati per il wireframe.


3

Il modo più semplice è di disegnare i primitivi come GL_LINE_STRIP.

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

non se si tratta di un gruppo di GL_TRIANGLES: otterresti delle linee tra di loro. In OpenGL 1.x o legacy usi glPolygonMode. In OpenGL recente giochi con lo shader della geometria.
Fabrice NEYRET,

Questo è un modo antico di fare le cose che devono essere lasciate indietro.
Benny Mackney,

2

In Modern OpenGL (OpenGL 3.2 e versioni successive), è possibile utilizzare un Geometry Shader per questo:

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

Avvisi :


1

Puoi usare le librerie glut in questo modo:

  1. per una sfera:

    glutWireSphere(radius,20,20);
    
  2. per un cilindro:

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

    glutWireCube(1.5);
    

0

Un modo semplice e buono per disegnare linee anti-alias su un target di rendering non anti-alias è quello di disegnare rettangoli di 4 pixel di larghezza con una trama 1x4, con valori del canale alfa di {0., 1., 1., 0.} e utilizzare il filtro lineare con mip-mapping disattivato. Questo renderà le linee spesse 2 pixel, ma puoi cambiare la trama per diversi spessori. Questo è più veloce e più semplice dei calcoli baricentrici.


0

utilizzare questa funzione: voP glPolygonMode (GLenum face, GLenum mode);

faccia: specifica i poligoni a cui si applica la modalità. può essere GL_FRONT per la parte anteriore del poligono e GL_BACK per la sua schiena e GL_FRONT_AND_BACK per entrambi.

modalità: sono definite tre modalità che possono essere specificate in modalità:

GL_POINT: i vertici poligonali contrassegnati come l'inizio di un bordo di confine vengono disegnati come punti.

GL_LINE: i bordi del poligono vengono disegnati come segmenti di linea. (il tuo obiettivo)

GL_FILL: l'interno del poligono è pieno.

PS: glPolygonMode controlla l'interpretazione dei poligoni per la rasterizzazione nella pipeline grafica.

per ulteriori informazioni, consultare le pagine di riferimento OpenGL nel gruppo khronos: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonMode.xhtml


-1

Se hai a che fare con OpenGL ES 2.0 , puoi scegliere una delle costanti della modalità di disegno

GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, disegnare linee,

GL_POINTS (se devi disegnare solo vertici), o

GL_TRIANGLE_STRIP, GL_TRIANGLE_FANe GL_TRIANGLESper disegnare triangoli pieni

come primo argomento per il tuo

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

o

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.