Rysowanie obramowania na wielokątu 2d za pomocą shadera fragmentów

Mam kilka prostych wielokątów (mniej niż 20 wierzchołków) renderujących płasko na prostej płaszczyźnie xy, używając GL_TRIANGLES i płaskiego koloru, symulacji 2d.

Chciałbym dodać obramowanie o zmiennej grubości i innym kolorze do tych wielokątów. Mam coś zaimplementowanego przy użyciu tych samych wierzchołków i glLineWidth / GL_LINE_LOOP, co działa, ale jest kolejnym przejściem renderowania i powtarza wszystkie transformacje wierzchołków.

Myślę, że powinienem być w stanie to zrobić w fragment shader za pomocą gl_FragCoord i dane wierzchołków i/lub współrzędne tekstur, ale nie jestem pewien, a moje naiwne próby były oczywiście błędne.

Wyobrażam sobie coś takiego.

uniform vec2 scale;  // viewport h/w
uniform float line_width;
uniform vec4 fill_color;
uniform vec4 border_color;

varying vec4 vertex; // in world coords

void main()
{
    if (distance_from_edge(gl_FragCoord, vertex, scale) < line_width)
    {
        // we're close to the edge the polygon, so we're the border.
        gl_FragColor = border_color;
    }
    else
    {
        gl_FragColor = fill_color;
    }
}

Część, którą próbuję rozgryźć, to funkcja distance_from_edge-jak to obliczyć? Czy używanie gl_FragCoord jest złym podejściem - czy powinienem używać jakiegoś rodzaju mapowania tekstur?

Jako eksperyment próbowałem przekonwertować wierzchołek na przestrzeń pikseli ze skalą, a następnie obliczyć odległość między tym a gl_FragCoord w pikselach, ale to daje dziwne wyniki, których naprawdę nie rozumiem. Poza tym potrzebuję odległości do krawędzi , a nie wierzchołka, ale nie wiem, jak to zdobyć.

Jakieś pomysły?

EDIT: na podstawie odpowiedzi Nicola moje pytanie staje się:

Zakładając, że mam trójkąt z 3 wierzchołkami narożnymi oznaczonymi jako wierzchołki krawędziowe, a jeden wierzchołek w środku oznaczony jako nie krawędź( więc renderowany z 3 trójkątami w sumie), to jak interpolować w cieniowaniu fragmentów, aby narysować obramowanie o określonej grubości? Zakładam, że przekazuję flagę krawędzi do shadera fragmentów, a także żądaną grubość linii, i robi jakieś obliczenia interpolacyjne, aby ustalić odległość między krawędzią, a nie wierzchołkami krawędzi, i proguje Kolor jako obramowanie/wypełnienie odpowiednio?

Author: Peter O., 2013-08-03

1 answers

Wszystko czego potrzebujesz to współrzędne barycentryczne, ponieważ masz do czynienia z trójkątami. Przypisz każdemu wierzchołkowi trójkąta tożsamość, a następnie użyj wbudowanej interpolacji sprzętu między wierzchołkami i etapami fragment, aby obliczyć względną odległość od każdego wierzchołka w shaderze fragmentów.

Współrzędne barycentryczne dla każdego wierzchołka można traktować jako odległość od przeciwnej krawędzi. Na poniższym diagramie przeciwną krawędzią wierzchołka P0 jest e1, a jego odległość jest reprezentowana przez h1; jej współrzędna barycentryczna to <0.0, h1, 0.0>. GPU może używać tej przestrzeni współrzędnych wewnętrznie interpolować atrybuty wierzchołków dla trójkątów gdy fragmenty są generowane podczas rasteryzacji, to sprawia, że szybka praca ważenia dla wierzchołków właściwości na podstawie lokalizacji w trójkącie.

Diagram ilustrujący obliczenie odległości od każdej krawędzi

Poniżej znajdują się dwa samouczki, które wyjaśniają, jak to zrobić, zazwyczaj jest to używane do renderowania nakładki szkieletowej, więc możesz mieć więcej szczęścia szukając tego. Na Twoje cele, ponieważ jest to efektywna specjalizacja renderowania szkieletu (z dodaniem, że chcesz wyrzucić linie, które nie należą do zewnętrznych krawędzi wielokątów), będziesz musiał zidentyfikować wierzchołki krawędzi i wykonać dodatkowe przetwarzanie.

Na przykład, jeśli wierzchołek nie jest częścią zewnętrznej krawędzi, wtedy będziesz chciał przypisać mu współrzędną barycentryczną o wartości i połączonego wierzchołka , a wewnętrzna krawędź zostanie zignorowana (zakładając, że jest krawędź naprzeciwko wierzchołka oznaczonego , jak pokazano na poniższym diagramie). Chodzi o to, że nigdy nie chcesz, aby punkt wzdłuż tej krawędzi interpolował w pobliżu 0,0 (lub jakiegokolwiek progu używanego do cieniowania fragmentu jako części granicy), czyniąc go bardzo odległym od środka trójkąta w kierunku przeciwległego wierzchołka rozwiąże to.

Schemat pokazujący jak wykluczyć krawędzie wewnętrzne

BEZ shaderów Geometry (przyjazny dla OpenGL ES):

Oto link wyjaśniający jak zrób to, jeśli jesteś w stanie zmodyfikować dane wierzchołków, aby utrzymać współrzędne barycentryczne. Ma wyższe wymagania dotyczące przechowywania i wstępnego przetwarzania (w szczególności dzielenie wierzchołków między sąsiadującymi krawędziami może nie być już możliwe, ponieważ każdy trójkąt musi składać się z trzech wierzchołków, z których każdy ma inną wejściową współrzędną barycentryczną - dlatego pożądanym rozwiązaniem są shadery geometrii). Jednak będzie działać na znacznie większym sprzęcie klasy OpenGL ES niż na bardziej ogólnych rozwiązaniach, które wymagaj shaderów geometrii.

Http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/

z Geometry Shaders (Nie OpenGL ES friendly):

Alternatywnie, możesz użyć shadera geometry, aby obliczyć współrzędne barycentryczne dla każdego trójkąta w czasie renderowania, jak pokazano w tym samouczku. Są szanse, że w OpenGL ES nie będziesz miał dostępu do shaderów geometry, więc prawdopodobnie może to być ignorowane.

Http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_10.html http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_11.html

Teoretyczne podstawy tego rozwiązania można znaleźć tutaj (dzięki uprzejmości Internet Archive Wayback Machine):

Http://web.archive.org/web/*/http://cgg-journal.com/2008-2/06/index.html

 24
Author: Andon M. Coleman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-31 17:41:34