tortuga - ¿Cómo se hacen primitivas como wireframes en OpenGL?
rectangulo opengl (8)
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);
¿Cómo se hacen primitivas como wireframes en OpenGL?
En Modern OpenGL (OpenGL 3.2 y superior), podrías usar un Geometry Shader para esto:
#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();
}
Avisos:
- para los puntos, cambie el
layout (line_strip, max_vertices=3) out;
a lalayout (points, max_vertices=3) out;
- Leer más sobre Geometry Shaders
La forma más fácil es dibujar los primitivos como GL_LINE_STRIP
.
glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();
Puedes usar las bibliotecas de glut de esta manera:
para una esfera:
glutWireSphere(radius,20,20);
para un cilindro:
GLUquadric *quadratic = gluNewQuadric(); gluQuadricDrawStyle(quadratic,GLU_LINE); gluCylinder(quadratic,1,1,1,12,1);
para un cubo:
glutWireCube(1.5);
Si está utilizando la canalización fija (OpenGL <3.3) o el perfil de compatibilidad que puede usar
//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);
En este caso, puede cambiar el ancho de línea llamando a glLineWidth
De lo contrario, debe cambiar el modo de polígono dentro de su método de dibujo (glDrawElements, glDrawArrays, etc.) y puede obtener algunos resultados aproximados porque sus datos de vértice son para triángulos y está generando líneas. Para obtener los mejores resultados, considere usar un sombreador de geometría o crear nuevos datos para la estructura alámbrica.
Si se trata de OpenGL ES 2.0 , puede elegir una de las constantes de modo de dibujo de
GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES,
para dibujar líneas,
GL_POINTS
(si solo necesitas dibujar vértices), o
GL_TRIANGLE_STRIP
, GL_TRIANGLE_FAN
y GL_TRIANGLES
para dibujar triángulos rellenos
como primer argumento a tu
glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)
o
glDrawArrays(GLenum mode, GLint first, GLsizei count)
llamadas.
Suponiendo un contexto compatible con versiones posteriores en OpenGL 3 y superior, puede usar glPolygonMode
como se mencionó anteriormente, pero tenga en cuenta que las líneas con grosor de más de 1px ahora están en desuso. Entonces, si bien puedes dibujar triángulos como armazón de alambre, deben ser muy finos. En OpenGL ES, puedes usar GL_LINES
con la misma limitación.
En OpenGL es posible usar sombreadores de geometría para tomar los triángulos entrantes, desmontarlos y enviarlos para la rasterización como quads (pares de triángulos realmente) emulando líneas gruesas. Bastante simple, en realidad, excepto que los sombreadores de geometría son notorios por escalabilidad de rendimiento pobre.
Lo que puede hacer en su lugar, y lo que también funcionará en OpenGL ES es emplear el sombreado de fragmentos . Piensa en aplicar una textura de triángulo de alambre al triángulo. Excepto que no se necesita textura, se puede generar de manera procesal. Pero basta de hablar, vamos a codificar. Sombreador de fragmentos:
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);
}
Y sombreador de vértice:
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
}
Aquí, las coordenadas baricéntricas son simplemente (1, 0, 0)
, (0, 1, 0)
y (0, 0, 1)
para los tres vértices de triángulos (el orden no importa realmente, lo que hace que el empacamiento en tiras de triángulos sea potencialmente más fácil).
La desventaja obvia de este enfoque es que consumirá algunas coordenadas de textura y usted necesita modificar su matriz de vértices. Podría resolverse con un sombreador de geometría muy simple, pero aún sospecharía que será más lento que simplemente alimentar a la GPU con más datos.
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
encender,
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
para volver a la normalidad.
Tenga en cuenta que cosas como el mapeado de texturas y la iluminación aún se aplicarán a las líneas de alambre si están habilitadas, lo que puede parecer extraño.