Como você processa primitivas como wireframes no OpenGL?
Como você processa primitivas como wireframes no OpenGL?
Respostas:
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
para ligar,
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
para voltar ao normal.
Observe que coisas como mapeamento de textura e iluminação ainda serão aplicadas às linhas de estrutura de arame se estiverem ativadas, o que pode parecer estranho.
Em 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);
Assumindo um contexto compatível com a frente no OpenGL 3 e superior, você pode usar glPolygonMode
como mencionado anteriormente, mas observe que as linhas com espessura superior a 1px agora estão obsoletas. Portanto, embora você possa desenhar triângulos como uma armação de arame, eles precisam ser muito finos. No OpenGL ES, você pode usar GL_LINES
com a mesma limitação.
No OpenGL, é possível usar sombreadores de geometria para pegar triângulos, desmontá-los e enviá-los para rasterização como quads (pares de triângulos realmente) emulando linhas grossas. Bem simples, na verdade, exceto que os shaders de geometria são notórios por uma escala de desempenho ruim.
O que você pode fazer e o que também funcionará no OpenGL ES é empregar o shader de fragmentos . Pense em aplicar uma textura de triângulo de arame ao triângulo. Exceto que nenhuma textura é necessária, ela pode ser gerada proceduralmente. Mas chega de conversa, vamos codificar. Shader de fragmento:
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 shader 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
}
Aqui, as coordenadas baricêntricas são simples (1, 0, 0)
, (0, 1, 0)
e (0, 0, 1)
para os três vértices do triângulo (a ordem realmente não importa, o que torna o empacotamento em tiras de triângulo potencialmente mais fácil).
A desvantagem óbvia dessa abordagem é que ela comerá algumas coordenadas de textura e você precisará modificar sua matriz de vértices. Poderia ser resolvido com um shader de geometria muito simples, mas eu ainda suspeitaria que será mais lento do que apenas alimentar a GPU com mais dados.
Se você estiver usando o pipeline fixo (OpenGL <3.3) ou o perfil de compatibilidade, poderá 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);
Nesse caso, você pode alterar a largura da linha chamando glLineWidth
Caso contrário, você precisará alterar o modo de polígono dentro do seu método de desenho (glDrawElements, glDrawArrays, etc) e poderá obter alguns resultados aproximados, porque seus dados de vértice são para triângulos e você está produzindo linhas. Para obter melhores resultados, considere usar um sombreador Geometry ou criar novos dados para o wireframe.
A maneira mais fácil é desenhar as primitivas como GL_LINE_STRIP
.
glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();
No Modern OpenGL (OpenGL 3.2 e superior), você poderia usar um Geometry Shader para isso:
#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:
layout (line_strip, max_vertices=3) out;
paralayout (points, max_vertices=3) out;
Uma maneira boa e simples de desenhar linhas com suavização de borda em um destino de renderização sem suavização de borda é desenhar retângulos de 4 pixels de largura com uma textura 1x4, com valores de canal alfa de {0., 1., 1., 0.} e use a filtragem linear com o mip-mapping desativado. Isso tornará as linhas com 2 pixels de espessura, mas você pode alterar a textura para diferentes espessuras. Isso é mais rápido e fácil do que os cálculos bariátricos.
use esta função: void glPolygonMode (face GLenum, modo GLenum);
face: especifica os polígonos aos quais o modo se aplica. pode ser GL_FRONT para a frente do polígono e GL_BACK para as costas e GL_FRONT_AND_BACK para ambos.
mode: Três modos são definidos e podem ser especificados no modo:
GL_POINT: os vértices do polígono marcados como o início de uma aresta do limite são desenhados como pontos.
GL_LINE: As arestas de limite do polígono são desenhadas como segmentos de linha. (seu objetivo)
GL_FILL: O interior do polígono é preenchido.
PS: glPolygonMode controla a interpretação de polígonos para rasterização no pipeline de gráficos.
para obter mais informações, consulte as páginas de referência do OpenGL no grupo khronos: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonMode.xhtml
Se você estiver lidando com o OpenGL ES 2.0 , poderá escolher uma das constantes do modo de desenho em
GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES,
desenhar linhas,
GL_POINTS
(se você precisar desenhar apenas vértices) ou
GL_TRIANGLE_STRIP
, GL_TRIANGLE_FAN
, E GL_TRIANGLES
para desenhar triângulos a cheio
como primeiro argumento para o seu
glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)
ou
glDrawArrays(GLenum mode, GLint first, GLsizei count)
chamadas.