
Poniższe materiały dotyczą prostego silnika graficznego obsługujące obie z bibliotek (OpenGL i DirectX). Wcześniej pisałem w OpenGL, ale powiadają, że trzeba poznać obie, aby móc świadomie wybrać dla siebie lepszą. Choć dlaczego by nie znać i nie używać obu.
OpenGL jest przenośny, DirectX umożliwia programistom naukę rozszerzeń, których nie obsługują ich karty graficzne (emulacja). Różnic jest trochę, ale mimo wszystko wiele wiele łączy te biblioteki. Zmienia się właściwie tylko API, idee pozostają te same.
Engine ma za zadanie uprościć jak najbardziej korzystanie z możliwości obu bibliotek. Bez warunków typu
if (OpenGL)
{ ... }
else if (DirectX)
{ ... }
Mamy natomiast jeden wskaźnik np. GUI, który zostaje przypisany na początku do obiektu OpenGL lub DirectX, a te dziedziczą po wspólnej klasie abstrakcyjnej OpenX. To samo dotyczy innych struktur, jak np. Materiały lub Tekstury. Tworzymy jedną klasę np. CMaterials, i dla niej oddzielnie pochodne COpenGLMaterials i CDirectXMaterials, które używają już odpowiedniego dla nich interfejsu, poleceń OpenGL czy to DirectXa.
To samo dotyczy obiektów 3D. Mamy jedną klasę wspólną CMesh i dwie pochodne dla każdego z interfejsów tj. COpenGLMesh i CDirectXMesh dziedziczące po niej. Obiekt typu CMesh ładujemy np. za pomocą importera plików OBJ, a następnie konwertujemy do odpowiedniego formatu (OpenGL, DirectX) np. tak:
CMesh tmp_mesh;
CLoadOBJ loader;
loader.Import("file.obj", &tmp_mesh, &listObj,
&listMaterial, false);
// Conversion to OpenGL or DirectX format
CMesh *Mesh;
Mesh = GUI->New(&tmp_mesh);
// Init buffers
tmp_mesh -> InitBuffer();
// Draw mesh
tmp_mesh -> Render();
Można by spytać po co te komplikacje, moglibyśmy stworzyć od razu wersję ładowania pliku OBJ do odpowiedniego interfejsu
(format OpenGL lub DirectX), ale chcemy mieć większą kontrolę nad tym procesem. W tej chwili możemy załadować wszystkie
pliki obiektów przed wyborem interfejsu, a dopiero po tym wyborze konwersję do odpowiedniego formatu. Przydatna opcja
gdy planujemy tworzyć własny format plików sceny.
Konwersję powyższą można by zamienić na te kilka linii:
if (OpenGLInterface)
{
Mesh = COpenGLMesh(tmp_mesh);
}
else if (DirectXInterface)
{
Mesh = CDirectXMesh(tmp_mesh);
}
Ale chcemy pozbyć się takich warunków, więc korzystając z wirtualności metody New obiektu COpenX (*GUI) robi to za nas. Można by się spierać czy to najszybsza z metod (polimorfizm zabiera czas procesora), ale podczas pisania złożonych projektów w początkowych fazach optymalizacja często powodowała więcej problemów.
Różnice w ideach, wymagające oddzielnego konwertowania danych. Spis jest rezultatem pisania silnika i odkrywania właśnie tych różnic między OpenGL a DirectX (oczywiście, niektóre z różnic mogą być wynikiem konkretnej implementacji, wersji posiadanego sprzętu - ale nie zaszkodzi zwrócić uwagę, gdy coś jednak nie będize identycznie wyglądać)
#define RGBA(r,g,b,a) \ ((((a)&0xff)<<24)|(((b)&0xff)<<16)| (((g)&0xff)<<8)|((r)&0xff))w DirectX:
#define RGBA(r,g,b,a) \ ((((a)&0xff)<<24)|(((r)&0xff)<<16)| (((g)&0xff)<<8)|((b)&0xff));
Pliki VRML mogą pomóc nam wyeksportować obiekty statyczne w postaci hierarchii Bones oraz ich animację (translacja, rotacja, skalowanie), czego np. nie potrafił format OBJ.
Format dość popularny, więc nie powinno być problemu eksportu do niego. Co prawda VRML wypierany jest przez X3D, to soft, którego używam (sic!) niezbyt sobie z nim radzi. A i w samych VRML exporterach jest trochę rozbieżności, natury parserowania - i tak np. zamiast przecinków używa się znaków nowej linii itp itd, więc poniżej spis tego pod czym parser VRML 'działa'.
Zaimplementowany parser plików VRML jest zapudełkowany w klasę CVRMLImport, korzystający z klas CVRML_Node i jej pochodnych do rekurencyjnego parserowania pliku .WRL. A w efekcie końcowym potrafi zaimportować światła CLight, materiały CMaterial, oraz obiekty CObject3D, które dzielą się na statyczne CMesh oraz grupy obiektów połączonych hierarchią CGroup3D - których węzły umożliwiają animację w postaci klatek kluczowych CAnim_KeyFrame używających macierzy przekształceń.
Interpolacja animacji
Eksportując animację możemy zdefiniować tylko kilka klatek kluczowych, resztę robi za nas interpolacja - używamy przy tym SLERP (kwaternionów do interpolacji obrotów)
Parser VRML BETA
Parser formatu VRML jest dość roboczą wersją, testowaną na jednym eksporterze (podanym w wymaganiach) i w dalszym ciągu nie
obsługującym wielu opcji VRMLa - nie były potrzebne jak narazie.
Obiekty VRML
Parser obsługuje jedynie obiekty najbardziej ogólne, tj. typu IndexedFaceSet, pomija Box, Sphere itp. W maxie wystarczy
przekonwertować takie podstawowe do Mesh (nadać modyfikację Mesh Edit).
Błędy parsera
Dokumentacja pewnie nie powstanie tak szybko, więc o ile siedzi mi jeszcze w głowie, a coś się krzaczy bezustannie - pisać śmiało!