Come si rendono le primitive come wireframe in OpenGL?
Come si rendono le primitive come wireframe in OpenGL?
Risposte:
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.
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);
Supponendo un contesto compatibile con il forward in OpenGL 3 e versioni successive, è possibile utilizzare glPolygonMode
come 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.
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.
Il modo più semplice è di disegnare i primitivi come GL_LINE_STRIP
.
glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();
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 :
layout (line_strip, max_vertices=3) out;
inlayout (points, max_vertices=3) out;
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.
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
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_FAN
e GL_TRIANGLES
per 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.