Jak renderujesz prymitywy jako szkielety w OpenGL?

220

Jak renderujesz prymitywy jako szkielety w OpenGL?


źródło
2
Dokładniej określ używaną wersję OpenGL.
Vertexwahn
Dzięki ModernGL możesz po prostu użyć atrybutu wireframe klasy Context
Szabolcs Dombi
używać GL_LINES zwrócić krawędziowe
oksyny

Odpowiedzi:

367
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

włączyć,

glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

wrócić do normalności.

Pamiętaj, że takie elementy jak mapowanie tekstur i oświetlenie będą nadal stosowane do linii szkieletowych, jeśli są włączone, co może wyglądać dziwnie.


źródło
2
Lubię cię. Jeszcze 4.
Jo So
37

From 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);
John Millikin
źródło
75
wykonywanie dwóch połączeń jest zbędne. użyj 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 nowszych. Teraz możesz nadal korzystać z nich za pomocą rozszerzenia kompatybilności, ale jeśli masz wybór między zgodnym w przód a wstecznym, zaleciłbym wybranie tego pierwszego.
fouric
1
Link w tej odpowiedzi zwraca 404.
Ondrej Slinták
1
@ OndrejSlinták Naprawiono teraz.
MaxiMouse
24

Zakładając kontekst zgodny z Open w OpenGL 3 i nowszych, możesz użyć albo glPolygonModejak wspomniano wcześniej, ale pamiętaj, że linie o grubości większej niż 1px są teraz przestarzałe. Tak więc, chociaż możesz rysować trójkąty jako ramkę drucianą, muszą one być bardzo cienkie. W OpenGL ES można używać GL_LINESz tymi samymi ograniczeniami.

W OpenGL można używać shaderów geometrii do pobierania przychodzących trójkątów, demontowania ich i wysyłania do rasteryzacji jako quady (naprawdę pary trójkątów) emulujące grube linie. Całkiem proste, naprawdę, z wyjątkiem tego, że shadery geometrii są znane z powodu słabego skalowania wydajności.

Zamiast tego możesz także zastosować w OpenGL ES moduł cieniujący fragmenty . Pomyśl o zastosowaniu do niego tekstury trójkąta o konstrukcji drucianej. Tyle, że tekstura nie jest potrzebna, można ją wygenerować proceduralnie. Ale dość gadania, napiszmy kod. Moduł cieniujący fragmenty:

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

I moduł cieniujący wierzchołek:

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)a (0, 0, 1)za trzy wierzchołki trójkąta (kolejność nie ma znaczenia, co sprawia, że pakowanie w paski trójkąta potencjalnie łatwiej).

Oczywistą wadą tego podejścia jest to, że zje ono niektóre współrzędne tekstury i trzeba zmodyfikować tablicę wierzchołków. Można to rozwiązać za pomocą bardzo prostego modułu cieniującego geometrię, ale nadal podejrzewam, że będzie on wolniejszy niż tylko zasilanie GPU większą ilością danych.

świń
źródło
Pomyślałem, że to wygląda obiecująco, jednak wydaje się, że nie działa to w żaden sposób z OpenGL 3.2 (nie ES). Chociaż możliwe, że coś pomieszałem, bawiłem się tym dość długo i nie jestem pewien, jak to w ogóle ma być wykorzystane. Pomocne będą wszelkie dodatkowe informacje na temat tego, co zamierzasz renderować za pomocą tych programów cieniujących; Nie rozumiem, jak coś innego niż wypełnienie dałoby coś użytecznego, ale to nawet nie działa, biorąc pod uwagę, że wartość alfa gl_FragColor wydaje się być całkowicie ignorowana w OpenGL 3.2 ...
użytkownik1167662
2
Oczywiście, że tak. Można odwołać się do czyjegoś realizacji tego samego pomysłu w stackoverflow.com/questions/7361582/... .
świnie
1
Problem, na który napotykam, próbując użyć sugerowanej implementacji, jest, myślę, że moduł cieniujący nigdy nie będzie rysował poza obiektem, który ma zostać zarysowany. Spowoduje to zatem narysowanie konspektu na zarysowanym obiekcie? Innymi słowy, kontur będzie wyłącznie zawarty w oryginalnym obiekcie do narysowania?
user1167662,
1
@BrunoLevy możesz uzyskać dodatkową koordynację w webGL, nie? Jeśli masz szczęście, możesz uzyskać te współrzędne z texcoordów, jeśli masz bardzo proste modele, ale w przeciwnym razie musisz tylko dodać nowe współrzędne. Byłoby zbyt miło, gdyby działało bez niego :). Wystarczy przekazać jeden skalar na wierzchołek (a następnie rozwinąć go do 3-wektorowego modułu cieniującego wierzchołki).
świnie
2
Ach, teraz widzę ... f_width () jest pod tym względem moim przyjacielem. Dzięki
Neil Gatenby
5

Jeśli używasz stałego potoku (OpenGL <3.3) lub profilu zgodności, którego możesz 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 takim przypadku możesz zmienić szerokość linii, wywołując glLineWidth

W przeciwnym razie musisz zmienić tryb wielokąta w metodzie rysowania (glDrawElements, glDrawArrays itp.) I możesz skończyć z grubymi wynikami, ponieważ twoje dane wierzchołków dotyczą trójkątów i wyprowadzasz linie. Aby uzyskać najlepsze wyniki, rozważ użycie modułu cieniującego geometrię lub utworzenia nowych danych dla modelu szkieletowego.

Zaphyk
źródło
3

Najprostszym sposobem jest narysowanie prymitywów jako GL_LINE_STRIP.

glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();
Hochester
źródło
nie, jeśli jest to wiązka GL_TRIANGLES: dostaniesz linie między nimi. W OpenGL 1.x lub starszej wersji używasz glPolygonMode. W najnowszym OpenGL grasz z modułem cieniującym geometrię.
Fabrice NEYRET
Jest to starożytny sposób robienia rzeczy, które należy porzucić.
Benny Mackney
2

W Modern OpenGL (OpenGL 3.2 i wyżej) możesz użyć Geometru Shadera w tym celu:

#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:

LMD
źródło
1

Możesz użyć takich bibliotek glut:

  1. dla kuli:

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

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

    glutWireCube(1.5);
    
H.Mohcen
źródło
0

Dobrym i prostym sposobem rysowania wygładzonych linii na nie-wygładzonym celu renderowania jest narysowanie prostokątów o szerokości 4 pikseli z teksturą 1x4, z wartościami kanału alfa {0., 1., 1., 0.} i użyj filtrowania liniowego przy wyłączonym mapowaniu mip. Spowoduje to, że linie będą miały grubość 2 pikseli, ale możesz zmienić teksturę dla różnych grubości. Jest to szybsze i łatwiejsze niż obliczenia barymetryczne.

Peter Soltesz
źródło
0

użyj tej funkcji: void glPolygonMode (twarz GLenum, tryb GLenum);

twarz: określa wielokąty, których dotyczy tryb. może być GL_FRONT dla przedniej strony wielokąta i GL_BACK dla jego pleców oraz GL_FRONT_AND_BACK dla obu.

tryb: zdefiniowane są trzy tryby, które można określić w trybie:

GL_POINT: Wierzchołki wielokąta oznaczone jako początek krawędzi granicznej są rysowane jako punkty.

GL_LINE: Krawędzie granicy wielokąta są rysowane jako segmenty linii. (Twój cel)

GL_FILL: Wnętrze wielokąta jest wypełnione.

PS: glPolygonMode kontroluje interpretację wielokątów do rasteryzacji w potoku graficznym.

Aby uzyskać więcej informacji, zobacz strony referencyjne OpenGL w grupie Khronos: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonMode.xhtml

Omar Ghannou
źródło
-1

Jeśli jest to OpenGL ES 2.0 masz do czynienia z , możesz wybrać jedną ze stałych trybu rysowania

GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, rysować linie,

GL_POINTS (jeśli musisz rysować tylko wierzchołki), lub

GL_TRIANGLE_STRIP, GL_TRIANGLE_FANiGL_TRIANGLES narysować wypełnione trójkąty

jako pierwszy argument do twojego

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

lub

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

Zwycięzca
źródło