OpenGL wyświetla zarys wielu nakładających się obiektów


10

Właśnie miałem pomysł na moją grę w OpenGL w c ++: Chciałbym mieć duży zarys (5-6 pikseli) na wielu nakładających się obiektach, gdy gracz coś wygra.

Pomyślałem, że najlepszym sposobem jest użycie bufora szablonów, ale kilka godzin próbuję wykonać renderowanie bufora szablonów poza ekranem i nie mogę osiągnąć żadnego wyniku, więc probab. istnieją inne techniki!

Oto, co chcę uzyskać:

wprowadź opis zdjęcia tutaj

Jakieś pomysły?


Używać filtra wykrywającego krawędzie, wypełniać krawędzie grubymi kolorowymi liniami, a następnie wyodrębniać renderowane obrazy kształtów i nakładać na warstwę kolorowych linii?
Shotgun Ninja

co masz na myśli przez filtr wykrywający krawędzie? shader? filtr przetwarzania obrazu? jak opencv (renderowanie do tekstury, zastosowanie filtru do tekstury, wypchnięcie zmodyfikowanej tekstury)?
nkint

Nie mam pojęcia; Na początku nie jestem zbyt dobrze zaznajomiony z renderowaniem 3d.
Shotgun Ninja

masz jakiś przykład takiego bufora szablonów? Myślę, że za pomocą bufor szablonowy sposób byłoby czystsze, ale nie jestem w stanie uczynić żadnej pracy bufor szablonowy
nkint

Odpowiedzi:


4
  1. Włącz i wyczyść bufor szablonu.
  2. Narysuj obiekty, ustawiając bufor szablonu. Obiekty mogą być półprzezroczyste itp.
  3. Teraz ustaw tryb szablonu tak, aby zapisywał piksele tylko wtedy, gdy szablon nie jest ustawiony.
  4. I narysuj ponownie każdy obiekt, lekko powiększony, w pożądanym kolorze obramowania i bez tekstur.
  5. Wyłącz bufor szablonu.

Oto kod zaadaptowany z jakiegoś kodu szablonu webGL, który mam działający:

// drawing will set stencil stencil
    gl.enable(gl.STENCIL_TEST);
    gl.stencilFunc(gl.ALWAYS,1,1);
    gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE);
    gl.stencilMask(1);
    gl.clearStencil(0);
    gl.clear(gl.STENCIL_BUFFER_BIT);
// draw objects
for(var object in objects)
  objects[object].draw();
// set stencil mode to only draw those not previous drawn
    gl.stencilFunc(gl.EQUAL,0,1);
    gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
    gl.stencilMask(0x00);
// draw object halo
for(var object in objects)
  objects[object].drawHalo(1.1,red); // each mesh should be individually scaled e.g. by 1.1
// done
    gl.disable(gl.STENCIL_TEST);

Myślę, że wykorzystałem to podejście w grach RTS, aby narysować aureole wokół wybranych jednostek, ale to było dawno temu i nie pamiętam, czy są jakieś gotcha i wszystkie niuanse.


masz jakiś przykład takiego bufora szablonów? Myślę, że za pomocą bufor szablonowy sposób byłoby czystsze, ale nie jestem w stanie uczynić żadnej pracy bufor szablonowy
nkint

7
Należy pamiętać, że renderowanie lekko skalowanych obiektów nie spowoduje jednolitej grubości linii. Krawędzie dalej będą cieńsze. Jeśli uwzględnisz to podczas skalowania obiektów, długie obiekty rozciągające się na odległość będą miały niejednorodną grubość. Jest nieco więcej tego efektu, aby linie były ładne i równe.
Sean Middleditch

2
Lepsze niż zwykłe skalowanie obiektów jest napisanie modułu cieniującego wierzchołki, który przesuwa każdy wierzchołek w niewielkiej odległości wzdłuż jego normalnej. Działa to całkiem dobrze w przypadku gładkich obiektów, ale spowoduje pęknięcia na twardych krawędziach. Możesz spróbować zbudować siatkę za pomocą alternatywnego zestawu normalnych, które są wygładzane wszędzie i sprawdzać, gdzie cię to zaprowadzi.
Nathan Reed,

2

Zacznij od znalezienia wszystkich grup obiektów, gdzie grupa obiektów to zbiór nakładających się obiektów. Standardowe wykrywanie kolizji powinno wykonać zadanie. Przypisz każdej grupie unikalny kolor. Każdy kolor by wystarczył.

Renderuj wszystkie obiekty jako kolory jednolite, używając koloru grupy, do tekstury.

Utwórz nową teksturę konturu o tych samych wymiarach co cel renderowania. Zeskanuj każdy tekst docelowego renderowania i sprawdź, czy jest innego koloru niż otaczające go tekstury. Jeśli tak, zmień odpowiedni tekstur w teksturze konturu na żądany kolor linii.

Na koniec weź tę teksturę konturu i wyrenderuj ją na górze obrazu, który chcesz narysować na ekranie (możesz oczywiście to zrobić w tym samym czasie, co wykrywanie krawędzi w module cieniującym fragmenty i uniknąć tworzenia tekstury krawędzi w pierwszym miejsce).

Jeśli wykonasz ten krok na jednostce centralnej za pomocą pętli for, aby przejść przez tekstury celu renderowania, będzie to dość powolne, ale prawdopodobnie wystarczająco dobre, aby przetestować, a nawet użyć w niektórych przypadkach. Aby użyć tego w czasie rzeczywistym, najlepiej poradzić sobie z tym w module cieniującym.

Moduł cieniujący fragmenty do tego wykrywania krawędzi może wyglądać tak;

precision mediump float;

uniform sampler2D s_texture;

varying vec2 v_texCoord;

void main()
{
    gl_FragColor = vec4(0.0);

    vec4 baseColor = texture2D(s_texture, v_texCoord);
    gl_FragColor += baseColor - texture2D(s_texture, top);
    gl_FragColor += baseColor - texture2D(s_texture, topRight);
    gl_FragColor += baseColor - texture2D(s_texture, right);
    gl_FragColor += baseColor - texture2D(s_texture, bottomRight);
    gl_FragColor += baseColor - texture2D(s_texture, bottom);
    gl_FragColor += baseColor - texture2D(s_texture, bottomLeft);
    gl_FragColor += baseColor - texture2D(s_texture, left);
    gl_FragColor += baseColor - texture2D(s_texture, topLeft);
}

Gdzie drugą wartością w look2 texture2D jest współrzędna 2d względem v_texCoord. Zastosowałbyś to, renderując pierwszy cel renderowania jako teksturę na poczwórnym ekranie. Jest to podobne do zastosowania efektów rozmycia na pełnym ekranie, takich jak rozmycie gwiaździste.

Powodem użycia pierwszego celu renderowania z jednolitymi kolorami jest po prostu upewnienie się, że nie ma zauważalnej krawędzi między różnymi nakładającymi się obiektami. Jeśli po prostu wykonałeś wykrywanie krawędzi na obrazie na ekranie, prawdopodobnie odkryłbyś, że wykrywa on również krawędzie na zakładkach (zakładając, że obiekty mają różne kolory / tekstury / oświetlenie).


2
przepraszam, ale co masz na myśli mówiąc „Skanuj przez każdy tekst”? pętla for chociaż każdego piksela? w jednostce centralnej? więc jest to coś w rodzaju: renderowanie jednolitym kolorem na teksturę, przeniesienie obrazu do procesora, skanowanie, ponowne umieszczenie ich w teksturze? lub zrobić to w shaderze?
nkint

Najlepiej zrób to w module cieniującym, renderując quad na pełnym ekranie, używając celu renderowania jako tekstury, w podobny sposób jak efekt rozmycia po procesie, ale możesz go najpierw uruchomić na jednostce centralnej za pomocą pętli for, aby zobaczyć jeśli działa wystarczająco dobrze.
OriginalDaemon
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.