Warsztat.GDCompo!ProjektyMediaArtykułyQ&AForumOferty pracyPobieranie

Opisz napotkaną sytuację, a redakcja niezwłocznie znajdzie rozwiązanie!

wyślij anuluj

Milkshape plugin

Tekst został importowany z Warsztatowych artykułów. Jego oryginalnym autorem jest SirMike. Jeżeli został importowany poprawnie, usuń ten szablon!

Każdy programista gier staje kiedyś przed pewnym wyborem. Zadaje sobie pytanie - jakiego formatu modeli użyć w swoich aplikacjach ?

Odpowiedzi jest kilka. Można podpasować się pod jakiś istniejący format plików stworzony przez wielkie firmy czy też "małych - wielkich" programistów. Niektóre takie formaty są łatwe do rozgryzienia ale np. nie mamy możliwości użycia ich w komercyjnych programach ponieważ autor formatu może akurat tego nie chcieć. Najlepszym wyborem (i moim zdaniem jedynym sensownym) w takiej sytuacji jest stworzenie własnego formatu plików z grafiką 3d.

Najlepiej będzie napisać plugin eksporujący geometrię (i nie tylko) z ogólnie znanych programów do tworzenia trójwymiarowej graiki. Możemy wziąć 3dstudio, Maya, Blender'a czy Milkshape'a.

Ja wybrałem ten ostatni ponieważ napisanie plugina do tego edytora jest śmiesznie łatwe a i sam program jest bardzo łatwo zdobyć.

Właśnie to wam opiszę poniżej.

Rzeczy, które będą nam potrzebne:

  • program Milkshape 3D do ściągnięcia z http://www.milkshape3d.com (jest to wersja shareware ale w zupełności wystarczy do tego co zamierzamy zrobić)
  • pakiet Milkshape 3D SDK również do ściągnięcia ze wyżej wymienionej strony
  • jakiś kompilator języka C++ (ja będę używał MSVC++ 6.0)
  • umiejętność programowania bibliotek DLL w języku C++

Zaczynajmy więc bo szkoda czau.

Każdy plugin (czy to do 3dstudio czy Milkshape'a) ma to do siebie, że jest w postaci biblioteki dołączanej dynamicznie. Krótko mówiąc musimy stworzyć bibliotekę DLL, która załaduje się wraz z Edytorem 3D i w odpowiednim momencie wykona eksport do pliku tego co wyczarowaliśmy sobie na ekranie.

Tworzymy więc DLL'a:

z menu File wybieramy New a później "Win32 Dynamic-Link Library". Posiadacze innych kompilatorów niż MSVC++ muszą to zrobić nieco inaczej, stosownie dla wersji swojego oprogramowania. Ja skupię się tylko na kompilatorze Microsoftu.

Tutaj jedna przestroga. Projekt DLL'a trzeba ustawić tak aby plik wynikowy miał nazwę "ms*.dll" czyli na przykład "msMOJPLUGIN.dll" czy "msExport.dll". Takie są wymagania programu Milkshape i nic na to nie poradzimy. Czyli nazywamy nasz projekt "msPlugin" i dalej wybieramy "a simple DLL project". Na koniec dajemy OK.

Wygeneruje się nam kod prostej biblioteki.

Zanim przejdziemy do pisania kodu musimy odpowiednio skonfigurować nasz kompilator dodając odpowiednie katalogi dla plików .h i .lib.

Pamiętacie co ściągnęliście ze strony Milkshape'a ? No właśnie, był tam taki plik który miał w swojej nazwie SDK. Musimy to gdzieś rozpakować. Zobaczymy, że jest tam kilka katalogów z przykładami jak również katalog "msLIB". Właśnie w tym miejscu mamy to co nas najbardziej interesuje. Pliki "msLib.h", "msPlugIn.h" oraz w podkatalogu lib "msModelLibd.lib". Pamiętajmy o podaniu kompilatorowi ścieżek dostępu do tych plików lub skopiujmy je do katalogu VC++ gdzie trzymane są wszystkie pliki nagłówkowe.

To są rzeczy, które musimy dołączyć do naszego projektu. Czyli na poczętku naszego kodu (w pliku msPlugin.cpp) dodajemy:

#include "msLib.h" #include "msPlugIn.h"

Wciśnijmy jeszcze ALT+F7 i nakażmy linkerowi dołączać plik "msModelLibd.lib". Dopisujemy jego nazwę do pola Object/Library Modules w zakładce Link.

Teraz musimy stworzyć klasę potrzebną do wywoływania kilku metod (Funkcje te wywołuje sam Milkshape w stosownych momentach):

class CPlugin : public cMsPlugIn { char szTitle[64]; public: CPlugin (); virtual ~CPlugin (); public: int GetType (); const char * GetTitle (); int Execute (msModel* pModel); };

Nasze zadeklarowane metody to funkcje wirtualne klasy z której dziedziczymy więc trzeba napisać do nich implementację.

CPlugin::CPlugin () { strcpy (szTitle, "Eksporter Geometrii"); } CPlugin::~CPlugin () { } int CPlugin::GetType () { return cMsPlugIn::eTypeExport; } const char* CPlugin::GetTitle () { return szTitle; } int CPlugin::Execute (msModel *pModel) { return 0; }

W konstruktorze do zmiennej szTitle trafia nazwa jaka będzie wyświetlana w menu Exports programu Milkshape. Ja nazwałem ją eksporter geometrii.

Destruktora nie ruszamy. Kolejna metoda GetType zwraca nam typ plugina jaki piszemy. Jest to typ wyliczeniowy a możliwe wartości to:

eTypeImport
eTypeExport
eTypeTool
eTypeEdit
eTypeVertex
eTypeFace
eTypeAnimate

Nasz plugin będzie z gatunku eksportujących więc dajemy eTypeExport.

Metoda GetTitle zwraca nazwę ustalaną w konstruktorze.

Ostatnia i zarazem najważniejsza metoda to Execute. Milkshape wywołuje tą metodę w momencie kiedy klikniemy opcję eksportu. Tutaj zaczyna się cała zabawa bo w tym miejscu wywołujemy funkcje, które zwracają wszystkie dane o tym co mamy aktualnie wyedytowane w programie (wierzchołki, trójkąty, normalne itd.)

Metoda ta powinna zwracać 0.

Jest jeszcze jedna ważna rzecz. Aby nasz plugin w ogóle był widzoczny musimy zadeklarować jeszcze jedną funkcję:

cMsPlugIn *CreatePlugIn () { return new CPlugin (); }

Jej typ jest zadeklarowany w pliku msPlugIn.h i jest ona potrzebna do tego aby nasz plugin w ogóle był widoczny w Milkshape. Musimy jeszcze sprawić aby ta funkcja stała się funkcją eksportową bo ją także musi widzieć program. Najlepiej stwórzmy sobie w katalogu projektu plik o nazwie msPlugin.def i dodajmy do niego następujące linie:

LIBRARY      "msPlugin"
EXPORTS    CreatePlugIn

Dodatkowo wciśnijmy jeszcze ALT+F7 i w polu Project Options zakładki Link dodajmy wpis:

/def:".\msPlugin.def"

Teraz skompilujmy sobie naszą bibliotekę i jeśli wszystko poszło dobrze to powinniśmy otrzymać plik o nazwie msPlugin.dll w podkatalogu Debug naszego projektu. Przegrajmy teraz ten plik do katalogu głównego Milkshape'a i uruchommy go (Milkshape oczywiście).

Gdy wybierzemy File->Export powinniśmy zobaczyć taki wpis jak "Eksporter Geometrii". Gdy go klikniemy to kompletnie nic się nie stanie ponieważ jeszcze nic nie wpisaliśmy do metody Execute.

Otwórzmy sobie plik o nazwie "msLib.h" (to ten plik dostarczany wraz z SDK do Milkshape'a). Co w nim widzimy ? Wszystkie możliwe struktury i funkcje z jakich możemy korzystać w naszej metodzie Execute. Każdy kto zna choć trochę angielski powinien od razu zorientowac się o co tu chodzi ponieważ każda funkcja jest nazwana adekwatnie do tego co w rzeczywistości robi. Np.:

int msModel_GetMeshCount (msModel *pModel) - zwraca ilość Mesh'y (siatek) stworzonych w edytorze
msMesh* msModel_GetMeshAt (msModel *pModel, int nIndex) - zwraca wskaźnik na Mesh'a o numerze nIndex
int msMesh_GetVertexCount (msMesh *pMesh) - zwraca ilość wierzchołków danego Mesh'a

Jest tego znacznie więcej ale nie będę tutaj opisywał wszystkiego. Trzeba popracować troche samemu ;)

My do naszej metody Execute dopiszemy coś co wyeksportuje wszystkie wierzchołki z wszystkich meshy do zadanego pliku.

Dodajmy jeszcze tylko na początku nagłówek do obsługi plików:

#include <fstream.h>

A teraz kod, który należy wpisać do metody Execute:

ofstream plik; plik.open("C:\\eksport.txt"); //do tego pliku zapiszemy współrzędne wierzchołków int ilemesh, ilevertexow; ilemesh=msModel_GetMeshCount(pModel); plik<<ilemesh<<endl; //ilosc meshy jaka bedzie zapisana w pliku for (int x=0; x<ilemesh; x++) //przejdz przez wszystkie meshe { msMesh *mesh; mesh=msModel_GetMeshAt(pModel,x); ilevertexow=msMesh_GetVertexCount(mesh); plik<<"Mesh"<<endl; plik<<ilevertexow<<endl; //ilosc wierzcholkow dla danego mesha for (int t=0; t<ilevertexow; t++) //przejdz przez wszystkie vertexy { msVertex *wierzcholek; msVec3 vx; wierzcholek=msMesh_GetVertexAt(mesh,t); msVertex_GetVertex(wierzcholek,vx); plik<<vx[0]<<" "<<vx[1]<<" "<<vx[2]<<endl; } } MessageBox(NULL,"Eksport OK",NULL,MB_OK); plik.close();

No i teraz opis:

pierwsza linia to deklaracja pliku, druga to jego otwarcie do zapisu. W zmiennych ilemesh oraz ilevertexow bedziemy przechowywac liczby reprezentujące ilość mesh'y w modelu i ilość wierzchołków w każdym mesh'u.

Dalej, wywołujemy pierwszą funkcję z SDK - mianowicie msModel_GetMeshCount(pModel); Za parametr przyjmuje ona wskaźnik na model edytowany właśnie w Milkshape a my ten wskaźnik otrzymujemy z parametru metody Execute. Wiemy już ile mamy mesh'y w naszym modelu więc zapiszmy sobie to do pliku (wykonuje to kod z kolejnej linii).

Teraz nadchodzi pętla, która wykonuje się tyle razy ile mamy mesh'y.

Deklarujemy sobie wskaźnik na strukturę msMesh i do niej zapiszemy dane o naszej pierwszej siatce. Ta struktura wygląda następująco:

typedef struct msMesh { byte nFlags; char szName[MS_MAX_NAME]; char nMaterialIndex; word nNumVertices; word nNumAllocedVertices; msVertex* pVertices; word nNumNormals; word nNumAllocedNormals; msVec3* pNormals; word nNumTriangles; word nNumAllocedTriangles; msTriangle* pTriangles; } msMesh;

nazwy zmiennych są tu bardzo intuicyjne więc nie ma sensu ich opisywać.

Wywołujemy funkcję msModel_GetMeshAt(pModel,x). Zwraca nam ona wskaźnik na mesh o numerze x.

Kiedy mamy już pierwszego mesh'a jako strukturę danych to możemy wyciągnąć z niego wszystko co się da. Dla każdej struktury istnieje szereg funkcji, które wyciągają tylko to co chcemy w prosty i przyjemny sposób. My chcemy współrzędne wierzchołków więc najpierw dowiedzmy się ile ich tak naprawdę jest ( msMesh_GetVertexCount(mesh) ) i zróbmy kolejną pętlę, która odczyta nam każdy wierzchołek i zapisze go do pliku.

W pętli odczytującej wierzchołki napotykamy nieznaną dla nas strukturę msVertex. Spójrzmy do pliku msLib.h i sprawdźmy co to za struktura:

typedef struct msVertex { byte nFlags; msVec3 Vertex; float u, v; char nBoneIndex; } msVertex;

widzimy, że jest tam coś takiego jak typ msVec3. To nic innego jak tablica trzech zmiennych typu float reprezentujących współrzędną wierzchołka. Są także dane koordynatów tekstury i jakaś zmiena opisująca kości. Nam na razie nie jest to potrzebne.

Dalej, deklarujemy sobie właśnie zmienną typu msVec3 aby zapisać do niej współrzędne wierzchołka. Funkcja msMesh_GetVertexAt(mesh,t) zwraca nam wskaźnik do wierzchołka o numerze t z żądanego mesha. Tablicę współrzędnych (u nas vx) wypełnimy stosując funkcję msVertex_GetVertex(wierzcholek,vx). Za parametry przyjmuje ona wskaźnik na wierzchołek i adres zmiennej typu msVec3, do której zostaną zapisane dane o współrzędnych. Dzięki temu ze struktury wierzcholek (msVertex) dostajemy tylko to co chcemy - czyli współrzędne x,y i z. Zmienna vx to tablica 3 liczb float więc współrzędna x znajdzie się pod vx[0], współrzędna y pod vx[1] a współrzędna z pod vx[2].

Po wykonaniu się metody Execute (czyli po kliknięciu Export->Eksport Geometrii w Milkshape) dostaniemy komunikat o wykonaniu zadania a na dysku C pojawi sie plik eksport.txt z współrzędnymi wierzchołków.

Możliwości eksportu jest oczywiście więcej ale nie będę tu opisywał wszystkiego bo można do tego dojść samemu studiując plik "msLib.h"

Można wyeksportować dosłownie wszystko, począwszy od najprostszych danych o wierzchołkach na teksturach i kościach skończywszy.

To by było na tyle. Postaram się wkrótce napisać podobny tutorial z tym, że obiektem zainteresowań będzie 3dStudioMAX.

Miłego kodowania,
SirMike

Przykład: milkshape_sample.rar

Tekst dodał:
Adam Sawicki
09.04.2006 19:05

Ostatnia edycja:
Adam Sawicki
09.04.2006 19:05

Kategorie:

Aby edytować tekst, musisz się zalogować.

# Edytuj Porównaj Czas Autor Rozmiar
#1 edytuj 09.04.2006 19:05 Adam Sawicki 12.79 KB
Zwykły
Do sprawdzenia
Do akceptacji
  • Napisz komentarz:
    Aby dodać swój komentarz, musisz się zalogować.
Licencja Creative Commons

Warsztat używa plików cookies. | Copyright © 2006-2017 Warsztat · Kontakt · Regulamin i polityka prywatności
build #ff080b4740 (Tue Mar 25 11:39:28 CET 2014)