Prezentacja mojego silnika MagicEngine


#1

Witajcie,
od czasu do czasu po pracy włączam sobie kompilator i coś tam próbuje sobie napisać własny silnik do tworzenia gier MMORPG 3D. Ogólnie to zacząłem to jako projekt na studia w 2014 roku, ale dopiero chyba teraz zaczyna to cokolwiek przypominać bo trochę więcej wiem o programowaniu gier :stuck_out_tongue: (może później wrzuce jakieś stare fotki).

Korzystam z:

  • modułu algorytmiczngo silnika LibGDX -> mapy, tablice, sortowanie
  • moduł matematyczny silnika LibGDX -> wektory, kwaterniony, macierze (większość obliczeń jest liczona w C++)
  • LWJGL (2.9.3)
  • Kryonet
  • Java
  • OpenGL (min. 4.0)
  • SWING

To sam już zrobiłem:

  • obsługa strumieniowania z plików (wszystko jest liczone i robione w C++)
  • obsługa shaderów: vertex, geometry, tessellation evaluation, tessellation control, fragment
  • wstępne ładowanie tekstur z plików PNG (w przyszłości może jakiś własny format plików) i obsługa atlasów tekstur
  • obsługa wielu canvasów jednocześnie, które dzielą context openGL’a pomiędzy sobą
  • obsługa sieciowa po TCP/IP, działa przesyłanie pakietów i szyfrowanie XTEA (dla pakietów), RSA (dla pakietu logowania)
  • kamera ortograficzna
  • biblioteka do wyświetlania figur geometrycznych na ekranie (2D i 3D)
  • biblioteka do wyświetlania GUI (2D)
  • projekt wstępnej kamery projekcyjnej (w tym tzw. fly camera)
  • wstępny projekt skydome
  • wstępne wyświetalnie terenu oparte na tesalacjii i drzewie czwórkowym
  • skończony edytor do lokalizacji i przypisywania voice overów
  • ładowanie z plików obj (pozycja, tekstura i normalna wierzchołka tylko)
  • deffered shading (scene color defrred, normal, distortion, albedo + AO)
  • obsługa światła - stożkowe, kierunkowe, punktowe

W planach:

  • skończyć material editor (85%)
  • zabrać się za katalog do assetów (80%)
  • deffered shading (emissive, translucency, mask) - (85%)
  • zabrać się za edytor siatki (0%)
  • ocean FFT
  • dokończyć wyświetlanie terenu

I poniżej póki co tylko podgląd na to co obecnie można jedynie zobaczyć, czyli mój edytor materiałów, który jest skończony w jakiś 60%. Ogólnie to inspiracja płynie z silnika Redkit 2 (Wiedźmin 2) bo edytor sam w sobie dawał mnóstwo swobody i można było stworzyć w nim większość shaderów, ale żeby nie było trochę rzeczy zrobiłem po swojemu (jak atrybuty) żeby po prostu było trochę czytelniej i bardziej poukładane.


Początkowy wygląd diagramów, gdzie niebieskie bloki oznaczały uniformy, a czerwone zmienne.

https://imgur.com/Ys477EH
Wstępny szkic atrybutów, które są przekazywane z vertex shadera do fragment shadera oraz końcowy output node czyli obliczenie konkretnego koloru piksela.

https://imgur.com/tkwodFi
Wszystkie nody odpowiedzialne za obliczenia matematyczne (na razie tylko te co są dostępne w redengine 2) oraz nowy uniform - czas.

https://imgur.com/0nzTEkR
Tutaj widać, że node editor zaczyna tłumaczyć nody na język glsl. Na pomarańczowo zmienne, na niebiesko uniformy.

https://imgur.com/FxV52yF
Tutaj edytor zaczyna tłumaczyć połączenia pomiędzy nodami na język glsl.

https://imgur.com/A6J8wol
Tutaj widać wielki test dodawania kilku wartości :P.

https://imgur.com/qXd2tBQ
Tutaj dodana reszta funkcji matematycznych. Widać, że jak edytor musi dodać wektor4D i floata to tego drugieo przekształca do wektora4D.

https://imgur.com/QpO16fR
Widok drzewa atrubutów w edytorze. Działa zmiana parametrów dla zmiennych w glslu. Zasada jest taka, że wyszstke uniformy mają ustawione standardowe wartości. Jeżeli użytkownik zmieni, któryś z nich w edytorze modeli (wkrótce) to tworzy się nowa instancja materiału z tym zmienionym paramterem.

https://imgur.com/vu0BOKl
Widok drzewa atrybutów dla tekstur. Myślę, że tutaj możnaby zrobić troszeczkę większe te tekstury.

Mam nadzieję, że uda mi się na bierząco aktualizować zmiany w silniku. Jak ma ktoś jakieś sugestie, rady i uwagi to proszę o komentarz, będę bardzo wdzięczny :).

AKTUALIZACJE:

  1. Zdjęcia z silnika (2014/2015 rok): Prezentacja mojego silnika MagicEngine
  2. Filmik prezentujący tworzenie postaci z 2015 roku: Prezentacja mojego silnika MagicEngine
  3. Update material edytora: Prezentacja mojego silnika MagicEngine
  4. Update material editora i dodane FBO: Prezentacja mojego silnika MagicEngine
  5. Deferred rendering: Prezentacja mojego silnika MagicEngine
  6. Asset edytor: Prezentacja mojego silnika MagicEngine
  7. Początek detail mapowania: Prezentacja mojego silnika MagicEngine
  8. Koniec robienia detail map: Prezentacja mojego silnika MagicEngine

#2

Po co własny format? Świat uzywa DXT1, 2, 3 itd, formaty te wspierane są przez sprzęt. Wczytując z dysku jakis PNG czy JPG musisz tak na prawdę wysłać do GPU czystą bitmapę. Marnujesz pamięć.
Własny format plików to tez utrudnienie podczas importowania assetów do gry. Oprócz modelu, kości, animacji itp trzeba jeszcze konwertować grafikę.

Skoro lubisz Javę to mogłeś się zainteresować JMonkeyEngine. Oprócz tesselacji ma wszystko, to co twój i ciut więcej. A silnik to poważna sprawa i to raczej nie jest wyzwanie na jedną osobę.
Zakładając, że go kiedyś udostępnisz, to dopóki nie będzie on open source to bał bym się opierać na nim jakiś swój projekt.

Wrzucaj na GITa i buduj wokół niego community, bo żeś się narobił, szkoda by, żeby poszło do szuflady.


#3

@up
Na początku dzięki za odpowiedź :smiley:
Bardziej mi chodziło o zmodyfikowanie formatu .xbm żeby dodać tam jakieś dodatkowe parametry dla tekstury tylko :).

Jeżeli chodzi o JMonkeyEngine to jest to fajny silnik, ale niestety nie jest zoptymalizowany i pewne elemnty 3D po prostu strasznie kuleją. Przykład: w grze chciałem zaimplementować teren o maksymalnej wielkości 8km x 8km (to jest maksymalna wielkość lokacji). Tak więc odpaliłem kod bez LOD i bez Frustum culling i osiągnąłem 7 FPSów, ponad to podniosła się starsznie temperatura na karcie graficznej (nie mówiąc już, że zaczęła wydawać dziwne dźwięki :P). Podobny test na moim silniku to 25 FPSów, kiedy jeszcze nie miałem tesalacji (i było to pod OpenGL 3.3). Podobnych rzeczy jest jeszcze więcej (patrz kopiowanie strumeni na przykład). Próbowałem przerabiać ten silnik na własną użyteczność, ale no strasznie dużo czasu schodziło i w końcu przeniosłem większość kodu do mojego silnika. Nie mówię, że to zły silnik, ale nie spełnia moich potrzeb i tyle. W ogóle jeżeli chodzi o teren to w dużej mierze bazuje na rozwiązaniach z firmy Dice (seria Battlefield). Także dla mnie póki co liczy się tylko podróż z pisaniem silnika, a czy go napiszę kiedyś zobaczymy jak się potoczy historia :).

Co do GITa to póki co wolałbym się wstrzymać bo na moim silniku chodzą moje aplikacje, które zarządzają programami, które wyświetlają coś na telebimach i no nie fajnie by było udostępniać, jednak w przyszłości jakiejś będę starał się jakieś tam może nawet tutoriale na youtube umieścić bo w sumie napisanie silnika nie jest trudne tylko nigdzie nie ma informacji jak to dokładnie zrobić. Oczywiście jak długo się korzysta z jakiegoś silnika typu Unity i Unreal 4 to po pewnym czasie można łatwo wpaść na pomysł jak to samemu napisać trzeba się tylko zagłębić w core :). Ja osobiście polecam RedKit 2 do nauki bo jak się w niego wczytać to znajdziesz tam nawet shadery, które wszystko liczą w silniku, a to już jakaś połowa sukcesu :slight_smile:

@edit
Jako, że dokopałem się do screenów mojego silnika z 2014/2015 roku to udostępniam bo chyba warto zobaczyć ten old school :P. Całość była pisana w Javie (bez OpenGLa jeszcze) i miała to być wersja 2D. Połączenie socketowe było tragiczne i ciągle sypało wyjątkami. Ponad to taka ciekawostka: część grafik była wzięta z Tibii w wersji 3.1 (1997 rok):


Okno tworzenia postaci


Edytor do tworzenia przedmiotów i obiektów


Edytor do tworzenia lokacji


Widok zmiany stroju


Jakaś tam karczma. Widok niestety z edytora bo musiałbym skonfigurować bazę danych żeby wrzucić widok z gry :confused:


Jakieś pole i wieżyczka


Świątynia, gdzie zaczynało się grę i kawałek portu.


#4

Dla mnie czarna magia. Ale szanuję, szanuję :wink:


#5

Czymkolwiek był by kilometr, ale to już masz błąd projektowy - po prostu trzeba lokacje dzielić na mniejsze obszary. Oprócz samego wyświetlania terenu 3D dojdzie ci jeszcze obsługa zdarzeń na tych obszarach. A przy MMO tych zdarzeń może być dużo. Więc od razu trzeba to sobie podzielić na sensownej wielkości fragmenty. Im mniejszy obszar tym więcej terenu poza zasięgiem gracza możesz wyłączyć. takie wyłączenie powinno działać oczywiście dwustronnie - serwer też musi wiedzieć jakie obszary masz aktywne, albo lepiej - serwer powinien decydować które kawałki mapy masz załączone, bo tylko z nich będziesz dostawał zdarzenia. A zdarzenia to akcje mobów, innych graczy itp oraz powiązane z nimi obiekty, które tez trzeba wyświetlać na scenie, obsługiwać, animować. No i 25fps w MMO jest niedopuszczalne, w takich grach liczy się płynność. Dla gracza lag = śmierć, więc trzeba optymalizować wszystko i na każdym kroku.

Co do JME to ja z niego korzystam i na nim oparłem mój Skullstone. Guru odnośnie 3D nie jestem, ale dałem radę całkowicie zmienić renderujacy pipeline, na chwile obecną z silnikowych szaderów to chyba już nic nie zostało.
Powiedział bym, że jak wszędzie - defaulty są dla dzieci, customizacja zawsze wiąże się z optymalizacją pod dane zagadnienie. Mnie się po prostu nie chciało wyważać otwartych drzwi i pisać wszystkiego od zera, ruszyłem tylko te miejsca, które mi zawadzał. A w JME było to dość łatwe.


#6

@frozenshade
Spokojnie, mówię to był test tego, że mogę coś zrobić lepiej niż JME. Jest to fajny silnik, ale dla mnie po prostu nie wystarcza. Musiałbym tam wszystko zmienić łącznie ze wszystkimi edytorami: materiałów, terenu itd. Po prostu szybciej jest mi napisać coś co od początku rozumiem i wiem jak to działa. Zrobienie takich rzeczy jak kopiowanie buforów (do VAO/plików), shadery to naprawdę prosta sprawa bo wszystko jest opisane w dokumentacji GLSLa. Problem pojawia się gdy chcę się zaimplementować coś fajnego wtedy zaczyna się kombinowanie jak to zrobić i tutaj przychodzą na pomoc gotowe silniki takie jak Unity. W ogóle gdybym chciał pójść na łatwiznę to wybrałbym Unreal 4, ale ten sam engine też jest dla mnie zbyt ograniczony bo wymusza pewne schematy i zamyka przez to świat gry. Programowanie na gotowych silnikach fajnie w jakimś wywiadzie kiedyś skomentował Michał Iwanicki (programista The Last of Us).

Poza tym przy okazji mojego silnika sporo rzeczy piszę w C++ a nie w Javie co mocno już samo w sobie przyśpiesza obliczenia. A co do terenu to spokojnie teraz dodałem frustum culling, tesalacje i morphing do terenu z poziomu shadera i mam przy tym samym terenie 120+ FPSów.

W ogóle dobrym przykładem tego iż można samemu napisać swój engine i go sprzedawać jest drean, który stworzył Esenthel Engine i kiedyś gdzieś tutaj nawet pisał coś na forum.

Co do renderowania akcji itd. to spójrz na to, że we wszystkich silnikach masz coś takiego, że nawet w odległości powiedzmy na to 20m od gracza (strzelam) nie wyświetlają się już nawet animacje postaci, a przemieszczają się one bez nich. Od strony serwera wygląda to tak, że jest sobie mapa czwórkowa, która przechowuję obiekt tzw. tile (który ma określone rozmiary w metrach). Następnie graczowi znajdującemu się na danym tile’u wysyłane jest wszystko z tego tile: przedmioty typu items jak miecze leżące na ziemi itd. NPC, potwory oraz inni gracze oraz z tili, które są w zasięgu gracza (ten zasięg też się ustala). Reszta nie jest wysyłana przez sieć, ale renderowana statycznie w kliencie (wszystkie światła itd. - no chyba, że gracz niesie w ręku jakieś światło, czy ma efekt cząsteczkowy). Więcej info można w sumie sobie poczytać z kodu the forgotten server, który jest open source :).

@EDIT
Dla mnie jeden terrain chunk to 33x33 vertexy, a 2x2 vertex to 1mx1m :slight_smile:


#7

Wiem jak działa backend w grach mmorpg, pisałem takie rzeczy (serwery Lineage 2 na L2j :slight_smile:

W ogóle podstawa to nie renderować danej klatki animacji jeśli obiekt (i jego cień) jest poza frustumem kamery.

Tzn chodzi ci o to, że tereny, zabudowania, drzewa i inne takie są trzymane tylko po stronie klienta? No to tak, serwer musi mieć jedynie odwzorowanie tego terenu w postaci jakiejś low poly ‘geodaty’, oczywiście bez tekstur i innych takich. Chodzi o to, żeby serwer niezależnie od klienta wyliczał położenie obiektów ruchomych (gracze, moby) i sam zarządzał tym, czy postać może iść czy nie. Żeby gracze nie łazili przez ściany na zmodowanych klientach.

Kurde no… wreszcie ktoś, kto wie jak się robi MMORPG. Będę kierował do tego tematu wszystkich ludzi którzy tu przychodzą i piszą ‘cześć jestem jasio i bende robił gre mmorypygy. zbieram ekipę. pisać!’. Niech sobie poczyta i się przestraszy :wink:


#8

No w MMORPG siędzę już właśnie ze 3 lata od tego 2014. Najpierw projekt na przedmiot Java i Inżynieria opragramowania, a potem wyszła nawet z tego praca licencjacka (chociaż z prespektywy czasu to jak tam opisywałem pewne aspekty sieciowe MMORPG to aż sam się wstydze :P).

Tak dokładnie oto chodzi bo oszustów w tego typu grach jest mnóstwo :smiley:. Co do budynków to jeszcze w sumie nie wiem bo ta technika jest ok do póki nie chcesz jakiegoś budynku rozwalić na kawałki jak na przykład właśnie w battlefield (jak ktoś ma dokument jak to oni robią to będę wdzięczny :stuck_out_tongue:), ale to plany na jakąś daleką przyszłość.

Każdy kto na początku zaczyna to chcę się porwać na 3D, a moim zdaniem to błąd bo po prostu za dużo się tam dzieje (też tak miałem na początku). U mnie już w sumie w silniku warstwa przesyłania i zarządzania jest w sumie ok chociaż chyba nigdy nie powinno się czegoś być pewnym :stuck_out_tongue:


#9

Kurcze, porwałem się na początku za 3D (nie wiedziałem jak działa while, i masy innych podstaw) :smiley:

Odnośnie DXT… DXT to nie jest format tekstur, tylko kompresja. Własny format tekstur jak najbardziej sie przydaje, tym bardziej jak zakładasz możliwość wykorzystania czegoś więcej niż tylko DXT :slight_smile: Zapisywanie cube map, formatów float, i wgl., no wszystko co ma OGL :smiley:

Zazwyczaj ludzie piszą własny silnik, bądź grę na własnym silniku, nie dlatego, że uważają że tak będzie łatwiej :smiley:

Fajnie czytać, że ktoś jeszcze pisze własny silnik :slight_smile: W zasadzie każdy projekt gdzie ludzie programują zamiast skryptować, to cieszy moje oczy :slight_smile:


#10

Jeżeli chodzi o tekstury to muszę poszukać. W starych książkach o programowaniu gier pamiętam, że polecali pliki tga bo dało się tam określić klucz koloru czy jakoś (musiałbym odkopać je :P), ale raczej jestem za formatem xbm bo założenia ma bardzo fajne no i da się tam dodać własne jakieś parametry :D. Cube mapa to już w ogóle będzie u mnie na pewno osobny format, który tylko i wyłącznie ma wskazywać na nazwy plików znajdujące się w tym samym folderze (na przykład z rozszerzeniem xbm) :slight_smile:.

Zobaczymy co z tego finalnie mi wyjdzie, ale jakoś tak po zrozumieniu jak to wszystko działa wydaje mi się proste w zaimplementowaniu i dam sobie głowę uciąć, że jest to złudne :stuck_out_tongue:

EDIT:
Poniżej filmik prezentujący tworzenie postaci z wersji ALPHA 2D mojego silnika z 2015 roku:


#11

TGA z tego co wiem posiada tylko kompresje RLE (bardzo prosta kompresja) , raczej nei jest zbyt dobry do gier :smiley: tzn. do importu może być, ale trzymać najlepiej inaczej :slight_smile:

W zasadzie wszystko jak się umie to jest proste :smiley: W samym silniku zazwyczaj problemem jest ogrom możliwości, no i czasami implementacja wszystkiego razem jest trudna (nawet jak każdy pojedynczy element jest prosty) :slight_smile:

Poza tym istnieje też troche technik, których pojęcie i implementacja to kwestia czasami i miesięcy :smiley:


#12

na pewno nie jest dobry do gier. Dobrze się tym kompresuje proste grafiki z mała ilością kolorów, z dużymi obszarami w tym samym kolorze. Poza tym, żeby dostać się do pixela na pozycji x,y to trzeba dekompresować obraz aż do tego miejsca. dxt1/2/3 mają tą zaletę, że nie muszą być dekompresowane.


#13

To jeden z tych tematów, które sprawiają, że spędzam pół nocy na googlowaniu :smiley:
Zupełnie jakbym czytał świat wiedzy :stuck_out_tongue:


#14

dxt1/2/3 mają tą zaletę, że nie muszą być dekompresowane.

Tak jak pisałem, DXT to tylko kompresja, a nie pełnoprawny format tekstur :slight_smile: DXT to tak jakby RLE, a TGA samo w sobie nie jest RLE, po prostu wspiera taką kompresję. Standardowo TGA miało wspierać bodajże 4 typy kompresji (w nagłówku jakieś dane pozostały, nie pamietam dokładnie), ale zaimplementowano tylko RLE :slight_smile:

Samo DXT faktycznie posiada zaletę taką, że jest dekompresowane przez sprzętowo (jest dekompresowane, ale bardzo wydajnie, zyskujesz większą wyddajność niż bez kompresji bo lepiej w cache trafia i takie sprawy). Ale używanie kompresji DXT jako jedynej słusznej opcji też nie jest idealnym wyjsciem :slight_smile: Przykłąd: telefony nie wspierają DXT (ale doszlismy juz, że autor w telefony nie celuje). Poza tym DXT wspiera tylko RGB i RGBA (no i SRGB, ale to prawie to samo :D), czyli wszystkie tekstury typu Float16, grayscale i inne trzeba zapisywać inaczej. Sama alfa w DXT często nie prezentuje zadowalającej jakości więc zastępuje się ją innym formatem.

Poza tym na samym dysku twardym teksture skompresowaną DXT jeszcze warto czymś skompresować :smiley: Zajmie znacznie mniej miejsca na dysku :slight_smile:


#15

To była książka pewnie z 2001 roku, więc może wtedy był to jakiś dobry pomysł :smiley:

Wczoraj sporo programowałem i pojawiło się mnóstwo problemów. Dodałem ładowanie z plików obj (dopóki nie będzie własnego formatu i edytora to będę pracował na nich). Póki co ładuje pozycje wierzchołka, współrzędne tekstury i normalną. Tangent wylicza na podstawie face’a (trzech wierzchołków) i na końcu uśrednia go. Binormal wylicza z cross produktu normalnej i tangent’a.

Niestety pojawiło się mnóstwo problemów. Po pierwsze OpenGL nie pozwala wyłączać parametrów przez co jeżeli obiekt nie posiada tangenta i binormalnej to i tak koniec konców musi je mieć puste. Moim zdaniem to marnowanie pamięci, ale nie wiem czy to da się ominąć :confused: (podobnie jest w silniku z Wiedźmina 2 - przeliczyłem renderowane KB i rzeczywiście kosta posiada tam również tangent i binormal chociaż z nich nie korzysta). Ten problem dalej przekłada się na bufor modelu ponieważ w takiej sytuacji jeżeli chcę nałożyć shadera na efekt cząsteczkowy i na przykład topór to muszę stworzyć dwa oddzielne VAO co dalej oznacza, że muszę stworzyć dwa oddzielne vertex shadery dla jednego materiału. Może to ma jakiś sens, ale chciałem jakoś to ominąć. No niestety póki co fragment shadera w momencie zapisu materialu się generuje do stringa, i zapisuje go na samej górze (tak, żeby nie musieć odtwarzać go z nodów w silniku), a vertex shader generowane jest w zależności od tego co renderuje. Mam nadzieję, że jakoś to wytłumaczyłem :stuck_out_tongue:. Jako, że w końcu mi działa już eksporter modelów z wiedźmina 2, więc w demkach do pokazania czegoś będę ich właśnie używał :slight_smile:


#16

Problem da sie ominac :slight_smile: Jezeli chodzi o VAO to Valve pisalo, ze w kazdym tescie VAO wychodzilo im wolniej niz zwykle VBO bindowane recznie, sam nie mialem czasu jeszcze tego przetestowac :slight_smile: Ale jak dobrze ulozysz pamiec w buforach to praktycznie nie musisz ustawiac buforow, bo masz powiedzmy jeden VBO 8MB (Nvidia kiedys polecala 4MB, ale to stare dzieje, wiec zalozmy te 8MB) to zmiesci Ci sie w nim duzo modeli, zazwyczaj wiec mkdele z indentycznym ukladem wiercholka nie musza byc bindowane bo wystarczy inny offset (BaseVertex) w funkcji rysujacej ( dla OGL bodajze od wersji 4.2 mozna dawac offset takze dla instancji).
Jezeli masz zamiar nie wykorzystywac tangentow to znaczy ze jest to inny material (nie zakladajacy istnienia tangentow) i wystarczy sprawdzac przy nakladaniu na model, czy dana siatma wspiera dany model wkercholka :slight_smile: Jezeli chodzi o wrzucanie jednego materialu na rozne typy obiektow, material jest niby jeden, ale w praktyce ma on duzo shaderow ktore dobiera w zaleznosci od typu obiektu. Zalozmy material polprzezroczystej kulki moze byc nalozony na obiekt statyczny, animowany, particle i teren. W praktyce pod tym materialem kryja sie wiec cztery shadery.
Tak wiec dla optymalizacji trzeba to odpowiednio posortowac, zalozmy tak: Material -> Shader -> VBO -> odleglosc :slight_smile: akurat w przypadku polprzezroczysfych musisz po odleglosci zeby uzyskac dobry wynik :slight_smile: Oczywiscie materialy uklada sie w zaleznosci od wymagan :slight_smile: Zaleta jest taka ze o ile shadery musisz zmienic to nie musisz rebindowac wszystkich ich danych (tym bardziej wykorzystujac UBO, czy nowsze OGL).
EDIT:
Odnosnie binormalnej, pamietaj ze cross normalnej i tangenta moze dac Ci binormalna w dwoch kierunkach, tzn. jak rovisz cross to zawsze wychodzi Ci identyczny relatywny do normalnej i tangenta zwrot binormalnej. trzeba sprawdzic czy binormalna po cross-ie nie powinna byc odwrocona (sam zwrot jest zalezny od kierunku wspolzednych tekstur, zle przygotowany model nie moze miec poprawnych tangentow, musi zostac podzielony, ale zazwyczaj robia to importery, badz eksportery).


#17

A sprawdzę sobie to w wolnej chwili bo ciekawe to bardzo :smiley:

Myślałem, że da się to jakoś oszukać na przykład poprzez wyłączenie w buforze jakoś atrybutu w takim sensie, że na przykład zmniejsza o te 6 floatów, ale teraz wiem, że błędnie to rozumiałem bo rzeczywiście no nie da się tego jak zrobić. Poza tym stwierdziłem, że można w sumie to “olać” bo w grze wszystkie modele mają korzystać z normal map poza tymi, które coś znaczą w edytorze -> na przykład model sugerujący, że w tym miejscu ma być światło albo kula symbolizująca zasięg efektu dźwiękowego. W samej grzej tak czy inaczej nie będzie się to i tak wyświetlać :slight_smile:. Póki co mam cztery przypadki: bufor modelu, bufor efektu cząsteczkowego, bufor animowanego modelu (postaci itd.) oraz bufor koloru (zawiera tylko atrybuty: kolor oraz pozycja).

W moim przypadku jeszcze jest dodatkowo tak: Material -> Shader -> Encja materiału (na przykład ktoś zmienił wartość jakiegoś uniformu odpowiedzialnego za to jak obiekt mocno się błyszczy) -> VBO -> odległość. Może jeszcze coś wejdzie, ale właśnie tak chciałem to zrobić :).

Co do UBO to czytałem o tym i widziałem mnóstwo przykładów więc pewnie jakoś w przyszłości zaimplementuje bo super sprawa jeżeli chodzi na przykład o kamere :smiley:.

Przy obliczeniach korzystam z tych gotowych wzorów (v0, v1, v2 są to wierzchołki face’a):

Vector3 delatPos1 = new Vector3(v1.getPosition()).sub(v0.getPosition());
Vector3 delatPos2 = new Vector3(v2.getPosition()).sub(v0.getPosition());
Vector2 uv0 = textures.get(v0.getTextureIndex());
Vector2 uv1 = textures.get(v1.getTextureIndex());
Vector2 uv2 = textures.get(v2.getTextureIndex());
Vector2 deltaUv1 = new Vector2(uv1).sub(uv0);
Vector2 deltaUv2 = new Vector2(uv2).sub(uv0);

float r = 1.0f / (deltaUv1.x * deltaUv2.y - deltaUv1.y * deltaUv2.x);
delatPos1.scl(deltaUv2.y);
delatPos2.scl(deltaUv1.y);
Vector3 tangent = delatPos1.sub(delatPos2);
tangent.scl®;
v0.addTangent(tangent);
v1.addTangent(tangent);
v2.addTangent(tangent);

A następnie wyliczam tangent:

for(Vector3 tangent : tangents)
{
averagedTangent = averagedTangent.add(tangent);
}
averagedTangent.nor();

Póki co mi wychodził wynik ok, ale racja warto się temu w razie czego przyjżeć :slight_smile:


#18

Akurat nie chodziło mi o samo liczenie tangentow :slight_smile: Jezeli dobrze liczysz tangent, to i tak cross normalnej z tangentem moze dac zła binormalna… bo zauwaz ze jak masz dwa wektody, normalna i tangent to istnieja dwa wektory prostopadle do nich… zalozmy tak: dla wektorow (1,0,0) i (0,1,0) istnieja wektory styczne (0,0,1) i (0,0,-1)… cross wektorow da (0,0,1), a binormalna moze byc (0,0,-1) :smiley: Standardowym podejsciem jest trzymanie tanget-u jako vec4, gdzie czwarta skladowa oznacza zwrot binormalnej, czyli 1, badz -1 :slight_smile:


#19

Racja miałeś racje jest błąd w binormalnej :smiley:. Wcześniej liczyłem sobie takie rzeczy w vertex shaderze (w sumie to się zastanawiam czemu by znowu binormalnej tam nie liczyć). Teraz rzeczywiście wrzuciłem to i czasami źle liczy. Więc pewnie dzisiaj jeszcze poprawie :smiley:

EDIT:
Tyle kombinowania, a wystarczyło do równania podstawić: binormal = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x)*r; :stuck_out_tongue:


#20

Graś screenów z tego co udało mi się zrobić w poprzednim tygodniu:


Skończony string edytor do edytowania wszystkich napisów w grze


Możliwość usuwania nodów oraz połączeń między nimi


Myślę, że już ostatnia prosta jeżeli chodzi o edytor materiałów. W przyszłości zamiast pozycję kamery wyliczać z view matrixa zastąpi to pewnie uniform lub nawet UBO. Pozostało mi w sumie tylko już aktualizować shadera i dodać deffered lightning, które póki co nie do końca wiem jak działa jeszcze, ale pewnie wyjaśni się to mi na dniach :slight_smile: