2008-09-26 10 views
177

W jaki sposób renderujesz prymitywy jako wireframes w OpenGL?W jaki sposób renderujesz prymitywy jako wireframe w OpenGL?

+1

Bardziej szczegółowe informacje na temat używanej wersji OpenGL. – Vertexwahn

+0

W [ModernGL] (https://github.com/cprogrammer1994/ModernGL) możesz użyć prostownika [wireframe] (http://moderngl.readthedocs.io/en/latest/Context.html#ModernGL.Context.wireframe) atrybut [Kontekst] (http://moderngl.readthedocs.io/en/latest/Context.html#ModernGL.Context) klasa –

Odpowiedz

22

Od 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); 
+64

wykonywanie dwóch połączeń jest zbędne. use GL_FRONT_AND_BACK – shoosh

+6

Jako dodatek do komentarza @ shoosh, czerwona księga stwierdza, że ​​GL_FRONT i GL_BACK zostały wycofane i usunięte z OpenGL 3.1 i wyżej.Teraz możesz nadal używać ich przez rozszerzenie kompatybilności, ale jeśli masz wybór między kompatybilnym do przodu i wstecznym, polecam pójście do pierwszego. – fouric

309
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 

włączyć,

glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 

wrócić do normy.

Należy pamiętać, że rzeczy takie jak odwzorowanie tekstury i oświetlenie będą nadal stosowane do linii krawędziowych, jeśli są włączone, co może wyglądać dziwnie.

+1

Lubię cię. Jeszcze 4 inne. –

5

Najprostszym sposobem jest narysowanie prymitywów jako GL_LINE_STRIP.

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

nie, jeśli jest to wiązka GL_TRIANGLES: otrzymasz linie między nimi. W OpenGL 1.x lub starszych używasz glPolygonMode. W najnowszym OpenGL grasz z modułem cieniującym geometrii. –

16

Zakładając naprzód zgodnego kontekst OpenGL 3 iw górę, można użyć glPolygonMode Jak wspomniano wcześniej, ale należy pamiętać, że linie o grubości większej niż 1px są obecnie przestarzałe. Podczas gdy możesz rysować trójkąty jako ramkę z drutu, muszą być bardzo cienkie. W OpenGL ES można używać GL_LINES z tym samym ograniczeniem.

W OpenGL możliwe jest użycie shaderów geometrii do odbierania trójkątów, rozbierania ich i wysyłania do rasteryzacji jako quady (naprawdę pary trójkątów) naśladujące grube linie. Całkiem proste, z wyjątkiem tego, że shadery geometrii są znane ze złego skalowania wydajności.

Co można zamiast tego zrobić, a także, co będzie działać również w OpenGL ES, należy użyć modułu cieniującego fragment. Pomyśl o zastosowaniu tekstury trójkąta z drutu do trójkąta. Poza tym, że nie jest potrzebna żadna tekstura, można ją wygenerować proceduralnie. Ale wystarczy rozmowa, zróbmy kod. Fragment 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); 
} 

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

Tutaj barycentryczne współrzędne są po prostu (1, 0, 0), (0, 1, 0) i (0, 0, 1) dla trzech wierzchołkach trójkąta (kolejność nie ma znaczenia, co sprawia, pakowanie w paski trójkątne potencjalnie łatwiejsze).

Oczywistą wadą tego podejścia jest fakt, że zjada on pewne współrzędne tekstury i trzeba zmodyfikować macierz wierzchołków. Może być rozwiązany za pomocą bardzo prostego modułu cieniującego geometrii, ale nadal podejrzewam, że będzie wolniejszy, niż tylko dostarczanie GPU z większą ilością danych.

+0

Pomyślałem, że to wygląda obiecująco, ale wydaje się, że nie działa to w żadnym wypadku z OpenGL 3.2 (bez ES). Chociaż jest to możliwe, coś pomieszałem, grałem z tym całkiem sporo i nie jestem do końca pewien, w jaki sposób jest to przeznaczone do użycia. Przydałoby się więcej informacji o tym, co zamierzasz renderować za pomocą tych shaderów; Nie widzę, aby coś innego niż wypełnienie mogło przynieść coś użytecznego, ale to nawet nie działa, ponieważ wartość alpha gl_FragColor wydawała się całkowicie ignorowana w OpenGL 3.2 ... – user1167662

+2

Oczywiście, że tak. Możesz odwołać się do czyjejś implementacji tego samego pomysłu na http://stackoverflow.com/questions/7361582/opengl-debugging-single-pass-wireframe-rendering. –

+0

Czy jest w stanie wytworzyć linie grubsze niż 1 piksel? – user1167662

1

Można użyć biblioteki GLUT tak:

  1. na kuli:

    glutWireSphere(radius,20,20); 
    
  2. dla cylindra:

    GLUquadric *quadratic = gluNewQuadric(); 
    gluQuadricDrawStyle(quadratic,GLU_LINE); 
    gluCylinder(quadratic,1,1,1,12,1); 
    
  3. dla Cube:

    glutWireCube(1.5); 
    
0

W Nowoczesnej OpenGL (OpenGL 3.2 i wyżej), można użyć Geometry Shader na to:

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

UWAGI:

0

Jeśli to OpenGL ES 2.0 masz do czynienia, można wybrać jeden z ciągnących stałych trybu z

GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, do rysowania linii,

GL_POINTS (jeśli trzeba wyciągnąć tylko wierzchołki) lub

GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN i GL_TRIANGLES rysować wypełnione trójkąty

jako pierwszy argument do swojej

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

lub

glDrawArrays(GLenum mode, GLint first, GLsizei count) połączeń.

0

Jeśli używasz stałym rurociągiem (OpenGL < 3.3) lub profil kompatybilności można użyć

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

W tym przypadku można zmienić szerokość linii poprzez wywołanie glLineWidth

W przeciwnym razie trzeba zmień tryb wielokąta w twojej metodzie rysowania (glDrawElements, glDrawArrays, itp.), a możesz otrzymać niektóre zgrubne wyniki, ponieważ twoje dane wierzchołków dotyczą trójkątów i wyprowadzasz linie. Aby uzyskać najlepsze wyniki, należy rozważyć użycie Geometry shader lub utworzenie nowych danych dla modelu krawędziowego.