This is the Polish translation of Model-Loading/Assimp article of learnopengl.com tutorial series.

We wszystkich dotychczasowych scenach bardzo często nadużywaliśmy naszego małego przyjaciela kontenera na wiele sposobów, ale z biegiem czasu nawet nasi najlepsi przyjaciele mogą się trochę znudzić. W praktycznych zastosowaniach graficznych zwykle jest dużo skomplikowanych i interesujących modeli, które są znacznie ładniejsze niż statyczny kontener. Jednak w przeciwieństwie do obiektu kontenera, nie możemy zdefiniować ręcznie wszystkich wierzchołków, wektorów normalnych i współrzędnych teksturowania złożonych kształtów, takich jak domy, pojazdy lub postacie podobne do postaci ludzkich. Chcemy zamiast tego importować te modele do aplikacji; modele, które zostały starannie zaprojektowane przez artystów 3D w narzędziach takich jak Blender, 3DS Max lub Maya.

Te tak zwane narzędzia do modelowania 3D umożliwiają artystom tworzenie skomplikowanych kształtów i nakładanie na nie tekstur za pomocą procesu zwanego mapowaniem uv. Następnie narzędzia automatycznie generują wszystkie współrzędne wierzchołków, wektory normalne i współrzędne teksturowania podczas eksportowania ich do pliku z odpowiednim formatem. W ten sposób artyści dysponują bogatym zestawem narzędzi do tworzenia modeli o wysokiej jakości, nie troszcząc się zbytnio o szczegóły techniczne. Wszystkie aspekty techniczne są ukryte w eksportowanym pliku modelu. My, jako programiści grafiki, musimy jednak dbać o te szczegóły techniczne.

Naszym zadaniem jest więc przeanalizować wyeksportowane pliki modeli i wyodrębnić wszystkie istotne informacje, abyśmy mogli je przechowywać w formacie zrozumiałym dla OpenGL. Powszechną kwestią jest jednak to, że istnieją dziesiątki różnych formatów plików, z których każdy eksportuje dane modelu w swój własny unikalny sposób. Formaty modeli, takie jak Wavefront.obj zawierają tylko dane modelu z pomniejszymi informacjami dot. materiałów, takimi jak kolory modeli i mapy diffuse/specular, natomiast formaty modeli, bazujące na XML-u takie jak format pliku Collada są bardzo obszerne i zawierają geometrię modeli, światła, wiele rodzajów materiałów, dane animacji, kamery, pełne informacje o scenie i wiele więcej. Format obiektu Wavefront jest generalnie uważany za łatwy do przeanalizowania. Zaleca się odwiedzić stronę wiki formatu Wavefront co najmniej raz, aby zobaczyć, jak zbudowany jest taki format pliku. Powinno to dać podstawową wiedzę na temat tego, jaką strukturę mają formaty plików modeli.

W sumie istnieje wiele różnych formatów plików, w których zwykle nie ma wspólnej, ogólnej struktury. Jeśli więc chcemy zaimportować model z tych formatów plików, musielibyśmy sami napisać importer dla każdego z formatów plików, które chcemy zaimportować. Na szczęście, istnieje biblioteka do tego zadania.

Biblioteka ładująca modele

Bardzo popularna biblioteka importująca modele nazywa się Assimp, co rozwija się do Open Asset Import Library. Assimp może importować dziesiątki różnych formatów plików modeli (i eksportować je również do niektórych formatów), ładując wszystkie dane modelu do uogólnionych struktur danych Assimp. Gdy tylko Assimp załaduje model, możemy pobrać wszystkie potrzebne dane ze struktur danych Assimp. Ponieważ struktura danych Assimp pozostaje taka sama, niezależnie od formatu importowanego pliku, nie musimy znać struktury różnych formatów plików.

Podczas importowania modelu, Assimp ładuje cały model do obiektu scene, który zawiera wszystkie dane zaimportowanego modelu/sceny. Assimp następnie ma kolekcję węzłów (ang. nodes), gdzie każdy węzeł zawiera indeksy danych przechowywanych w obiekcie sceny, gdzie każdy węzeł może mieć dowolną liczbę dzieci. Poniżej przedstawiono uproszczony model struktury Assimp:

  • Wszystkie dane sceny/modelu zawarte są w obiekcie Scene, podobnie jak wszystkie materiały i siatki. Zawiera także odniesienie do głównego węzła sceny.
  • Root node (pol. węzeł główny) sceny może zawierać węzły podrzędne (jak wszystkie inne węzły) i może mieć zestaw indeksów, które wskazują dane siatki w tablicy mMeshes. Węzeł główny mMeshes zawiera konkretne obiekty Mesh, wartości w tablicy mMeshes węzła są tylko indeksami dla tablicy siatek.
  • Obiekt Mesh (pol. siatka) zawiera wszystkie istotne dane wymagane do renderowania, w tym pozycje wierzchołków, wektory normalnych, współrzędnych tekstury i materiałach obiektu.
  • Siatka zawiera kilka ścianek. Face (pol. ścianka) reprezentuje prymityw renderowania obiektu (trójkąty, punkty). Ścianka zawiera indeksy wierzchołków tworzących prymityw. Ponieważ wierzchołki i indeksy są rozdzielone, to ułatwia nam renderowanie za pomocą bufora indeksów (zobacz Witaj trójkącie).
  • Wreszcie siatka zawiera również obiekt Material, który obsługuje kilka funkcji służących do wyszukiwania właściwości materiału obiektu. Pomyśl o kolorach i/lub mapach tekstur (jak mapy diffuse i specular).

Chcemy najpierw wczytać model do obiektu Scene, rekursywnie pobrać odpowiednie obiekty Mesh z każdego z węzłów (rekursywnie przeszukujemy dzieci każdego węzła) i przetworzyć każdy obiekt Mesh, aby pobrać dane wierzchołków, indeksy i ich właściwości materiałów. Rezultatem jest zbiór danych siatki, które chcemy zawrzeć w pojedynczym obiekcie Model.

Siatka (mesh)
Podczas modelowania obiektów w narzędziach do modelowania, artyści zazwyczaj nie tworzą całego modelu z jednego kształtu. Zwykle każdy model ma kilka podmodeli/kształtów, z których się składa. Każdy z tych pojedynczych kształtów, z których zbudowany jest model, nazywa się mesh (pol. siatka). Pomyśl o ludzkiej postaci: artyści zazwyczaj modelują głowę, kończyny, ubrania, bronie, wszystkie jako oddzielne komponenty, a połączone elementy stanowią ostateczny model. Pojedyncza siatka to minimalna reprezentacja tego, czego potrzebujemy, aby narysować obiekt w OpenGL (dane wierzchołków, indeksy i właściwości materiałów). Model (zwykle) składa się z kilku siatek/meshy.

W następnym tutorialu stworzymy własne klasy Model i Mesh, które załadują i przechowają dane importowanych modeli przy użyciu struktury, którą właśnie opisaliśmy. Jeśli chcemy narysować model, nie będziemy renderować modelu jako całości, ale będziemy renderować wszystkie poszczególne siatki, z których składa się model. Zanim jednak zaczniemy importować modele, musimy najpierw włączyć bibliotekę Assimp do naszego projektu.

Budowanie/kompilacja Assimpa

Możesz pobrać bibliotekę Assimp ze strony autorów i wybrać odpowiednią wersję. Podczas pisania tego samouczka, najnowszą wersją Assimp była wersja 3.1.1. Zaleca się samodzielne skompilowanie biblioteki, ponieważ ich wstępnie skompilowane biblioteki nie działają na większości systemów. Zapoznaj się z samouczkiem Tworzenie okna, jeśli nie pamiętasz, jak skompilować bibliotekę samodzielnie przy użyciu CMake.

Notka od tłumacza
Możesz również zobaczyć jak skompilować bibliotekę Assimp w tym tutorialu.

Jednak podczas budowania Assimp może pojawić się kilka problemów, więc opiszę je tutaj wraz z ich rozwiązaniami, na wypadek, gdyby któryś z was dostał te same błędy:

  • CMake nieustannie podaje błędy podczas pobierania listy konfiguracyjnej o brakujących bibliotekach DirectX:

    ```Could not locate DirectX
    CMake Error at cmake-modules/FindPkgMacros.cmake:110 (message):
    Required library DirectX not found! Install the library (including dev packages) 
    and try again. If the library is already installed, set the missing variables 
    manually in cmake.```
    

    Rozwiązaniem jest zainstalowanie pakietu DirectX SDK, jeśli wcześniej tego nie instalowałeś. Możesz pobrać SDK tutaj.

  • Podczas instalacji DirectX SDK może pojawić się kod błędu s1023. W takim przypadku najpierw odinstaluj pakiety redystrybucyjne C++ przed zainstalowaniem SDK zgodnie z tym, co napisano tutaj.
  • Po zakończeniu konfiguracji możesz wygenerować plik solucji Visual Studio, otworzyć go i skompilować biblioteki (albo jako wersję Release, albo wersję do Debug).
  • Domyślna konfiguracja powoduje, że Assimp jest biblioteką dynamiczną, więc musimy dołączyć wynikową bibliotekę DLL o nazwie assimp.dll wraz z plikami binarnymi aplikacji. Możesz po prostu skopiować bibliotekę DLL do tego samego folderu, w którym znajduje się plik wykonywalny aplikacji.
  • Po skompilowaniu programu Assimp, biblioteka wynikowa i plik DLL znajdują się w folderze code/Debug lub code/Release.
  • Następnie przenieś plik .lib i bibliotekę DLL do odpowiednich lokalizacji, połącz je z solucją VS i pamiętaj, aby nie zapomnieć o skopiowaniu nagłówków programu Assimp do katalogu include (pliki nagłówkowe znajdują się w folderze include w plikach pobranych ze strony Assimp).

Jeśli nadal otrzymujesz jakieś błędy, poproś o pomoc w komentarzach poniżej.

Jeśli chcesz, aby program Assimp używał wielowątkowości w celu zwiększenia wydajności, możesz skompilować program Assimp wraz z biblioteką Boost. Pełne instrukcje instalacji można znaleźć na ich stronie instalacyjnej.

Teraz powinieneś mieć skompilowaną bibliotekę Assimp, która jest połączona z aplikacją. Następny krok: importowanie modeli 3D!