[ susumiga @ 23.10.2004. 21:01 ] @
Zna li iko gde moze da se nadje primer za import 3ds skeletona u Delphi ili C++ i manipulaciju koskama?
[ yooyo @ 25.10.2004. 13:28 ] @
3DS zna da radi sa koskama (bones) i BIP-ovima (character studio). Ljudi se uglavnom odlucuju za BIP-ove jer character studio olaksava animiranje pokreta.
U svakom slucaju, ako imas instaliran MAX u njemu postoji i SDK za pisanje pluginova. Prouci malo materiju pa napisi exporter.

Sa druge strane, ja imam gomilu pokreta u HTR, BVH ili FBX formatu. Pogledaj attach i tu ces naci jedan jednostavan pokret u HTR formatu pa probaj da ga animiras.

Kratko objasnjenje:
HTR je u prevodu hierarhijska translacija i rotacija. U pitanju je txt file u kome su zabelezene sledece informacije:
Header:
NumSegments - broj kostiju
NumFrames - broj frejmova u animaciji
EulerRotationOrder - redosled rotacija. Ovo je jako bitno
RotationUnits - stepeni ili radijani
BoneLengthAxis - orijentacija koske. I ovo je bitno

SegmentNames&Hierarchy:
Ovde stoji spisak koski i njihove zavisnosti. Prvo ide child pa parent. root nema parent pa tu stoji kljucna rec GLOBAL

BasePosition:
Ovde za svaku kost stoji zapisana njena pocetna (base) pozicija. Sve vrednosti zavise od parent koske tj. zadane su lokalno u odnosu na parent, tako da moras rekurzivno da izracunas world pozicije (ako ti to treba).
Znaci...
Code:

void crtaj_kost(kost k)
{
glTranslate(k.Tx, k.Ty, k.Tz);
i zatim proveri EulerRotationOrder iz headera i uradi rotacije (primer za ZYX)
glRotate(0,0,1,Rz);
glRotate(0,1,0,Ry);
glRotate(1,0,0,Rx);
i nacrtaj liniju koja krece od (0,0,0) do (0,duzina_koske,0) ako je kost orijentisana po npr. y osi.
posle toga uradi for petlju za sve childove trenutne koske:
for (i=0; i<kost.num_childs; i++
{
 glPushMatrix();
   crtaj kost.child[i];
 glPopMatrix();
}
}

Ako je sve u redu dobices bind pozu (T-Pozu)

Animacija je malo drugacija. Racuna se rekurzivno ali su u fajlu zapisani relativni pomeraji u odnosu na base pozu. Racunica za neku kosku izgleda ovako:
translacija = base_pose_translacija + frame_translacija
glTranslatef(translacija.x, translacija.y, translacija.z)
3 x glRotate() za base pos
3 x glRotate() za frame pos.

Ako je sve u redu dobices skeleton koji hoda.

Kad sve apsolviras, javi sa da ti objasnim osnove skinninga, tj. kako da pokret "nabacis" na 3d character.

yooyo
[ susumiga @ 25.10.2004. 16:01 ] @
'fala brate!
Oma cu da se bacim na proucavanje.
[ Nothingman @ 04.12.2004. 01:01 ] @
Hej zasto ste stali? Ovo je odlican topic i evo veceras sam se dao na posao da prikazem skelet. Posle nekih sitnijih problema mislim da sam uspeo. Naime, morao sam da okrenem Z-osu prilikom translacije da bih dobio ispravnu orijentaciju. Takodje, skelet je i tada bio suvise veliki i morao sam da ga odmaknem jos za nekih 1000.0f da bih mogao celog da ga vidim. Ne znam da li sam ja negde pogresio ili je model tako zadat. Nisam dobio klasicnu T-pozu jer su ruke malo krivudave a i noge su pri dnu zakrivljene(to su verovatno stopala). Ono sto je cudno je to da dobijem isti rezultat bez obzira da li rotiram kao XYZ ili ZYX, ali to ce verovatno doci do izrazaja kad pocnem da ga animiram.
Interesuje me da li mozes da mi das savet za strukturu koja predstavlja skelet?
Ja sam koristio sledecu strukturu ali mi se cini da bi moglo dosta bolje (za sada ne podrzava frameove) :


Code:

typedef struct BONE_TAG
{
    char name[20];
    
    float tx, ty, tz;
    float rx, ry, rz;
    float boneLenght;
    int numOfChild;
    BONE_TAG *child[MAX_CHILDREN];

}BONE;

typedef struct SKELET_TAG
{

    int boneLengthAxis;
    int rotationOrder;
    BONE root;

}SKELET;


Da li postoji neki slican binarni fajl format? Meni nema vece kazne nego kad moram da parsujem tekstualni fajl, pa bi mi neki binarni HTR ekvivalent dobro dosao.

I sada dolazimo do nabacivanja skinova. Jednom sam citao da to radi po principu da svaki vertex ima pointer na kosti koje na njega utichu kao i jacine tih uticaja, pa ti onda samo animiras skelet a vertexe pomeras u zavisnosti od njega. Da li je to i ovde slucaj?Ako jeste gde da nabavim fajlove sa skinovima? Ajde ako te ne mrzi
daj nam malo vise detalja o svemu tome. U kojim programima ti radis ove skelete?

Uf, mislim da je ovo dosta pitanja za jedan post.
Pozdrav!
[ yooyo @ 13.12.2004. 13:37 ] @
Hmm.. Ako bi postovao screenshot mogu ti pomoci...
HTR je jednostavan za parsiranje. Binarni format za sada ne postoji... Mogao bi da ga izmislis :)

A sad skinning...

Vertex pored svojih standardnih atributa (position, color, normal, texcoord) moze da ima i dodatne atribute. Definisimo vertex na sledeci nacin:

Code:

typedef struct tagVertex
{
  // standardni atributi
  float pos[3];
  float norm[3];
  float texcoord[2];
  float color[4];
  // dodatni atributi
  float boneWeights[4];
  float boneIndices[4];
} tVertex;


boneWeights i je niz od max 4 elementa u kome se nalaze tezinski koeficijenti, tj. koliko neki bone utice na doticni vertex. Ove informacije mozes izvuci iz omiljenog programa (Maya, MAX ili nesto trece). Suma svih koeficijenata MORA biti 1.0!!!

boneIndices je niz od max 4 elementa (mora biti iste duzine kao i boneWeights za isti vertex) u tu su smesteni indexi u nizu matrica koje predstavlja bonse u nekom frejmu.

Kako se predstavlja bone kao matrica? Jednostavno. to je matrica 4x4 ali u world space-u, tj. kada se rekurzivno kreces kroz hierarhiju skeleta, akumuliraj transformacije i to smesti u niz. Dakle i-ti bone zauzima i-to mesto u nizu matrica 4x4.

A sad matematika!

Bind poza je predstavlja poziciju skeleta i mesha u 3D programu (Maya ili MAX). Skinovan vertex predstavlja sumu svih pozicija transformisanog pocetnog vertexa i pomnozenog sa odgovarajucim tezinskim koeficijentom. Posto se T-poza u HTR-u nemora poklapati sa bind pozom u Mayi ili MAX-u potrebno je uvesti jos i bidn_pose_matrix_inv, tj. inverznu matricu bone-a u bind pozi.
bind_pose_vertex je u stvari pos u nasoj Vertex strukturi.


skinned_vertex = sum{j in boneInidices} (boneWeights[j] * bone_matrix[j] * bind_pose_matrix_inv[j] *bind_pose_vertex)


Formula se moze dalje optimizovati:

bone_matrix_composition = bone_matrix[j] * bind_pose_matrix_inv[j]

bone_matrix_composition se racuna na CPU u svakom frejmu. Nova formula izgleda:

skinned_vertex = sum{j in boneIndices} (boneWeights[j] * bone_matrix_composition[j] * bind_pose_vertex)


Ako model NEMA nonuniform scale (tj. neproporcionalno skaliranje) dalja optimizacija bi izgledala ovako:

skinned_vertex = sum{j in boneIndices} (boneWeights[j] * bone_matrix_composition[j]) * bind_pose_vertex


Zato moze da se izracuna skin matrica:

skin_matrix = sum{j in boneIndices} (boneWeights[j] * bone_matrix_composition[j])


Najzad, formula izgleda ovako:

skinned_vertex = skin_matrix * bind_pose_vertex


Ova matrica se moze primeniti i na ostale atribute (normalu, tangentu i binormalu)

skinned_normal = skin_matrix * vec4(bind_pose_normal, 0.0)
skinned_tangent = skin_matrix * vec4(bind_pose_tangent, 0.0)
skinned_binormal = skin_matrix * vec4(bind_pose_binormal, 0.0)

Ovde cu se orijentisati na vertex shader i GLSL implementaciju istog.
GLSL shader izgleda ovako:

Code:

attribute vec4 boneWeights; // vec4 je niz od 4 float-a
attribute vec4 boneIndices;

uniform mat4 bones[30]; // max 30 kostiju.

varying vec4 col;

mat4 BuildSkinMatrix()
{
    vec4 b = boneIndices;
    vec4 w = boneWeights;    

    mat4 result;
    int i;
    for (i=0; i<4; i++)
    {
     result = result + (w[i] * bones[int(b[i])]);
    }
    
    return result;
}

void main(void)
{
    vec4 vtx;
    vec4 nrm;

    mat4 skinmatrix = BuildSkinMatrix();
    vtx = skinmatrix * gl_Vertex;

    gl_Position = gl_ModelViewProjectionMatrix * vtx;
}



Da bi iskoristili gornji code uradite sledece:
1. ucitajte mesh u niz vertexa. Vertexe smestite u strukuru na pocetku.
2. kreirajte VBO i tu iskopirajte sve vertexe.
3. postavite standardne pointere na vertexe u okviru VBO-a
4. postavite pointere na dodatne atribute koriscenjem glVertexAttribPointer().
5. Aktivirajte GLSL vertex shader
6. Za neki frejm izracunajte bone_matrix_composition za sve bonse. Rezultat smestite u uniform varijablu bones.
7. pozovite glDrawElements i posaljite na iscrtavanje sve trouglice iz mesh-a.

Znam da je ovaj post zesci udar na mozak, pogotovu za one koji nisu familijarni sa GLSL shaderima i VBO. Rado bih postovao i neki primer, ali mi je poprilicno nezgodno da to iscupam iz mog programa. Zato... pitajte sve sto vam nije jasno.

yooyo
[ Nothingman @ 14.12.2004. 04:36 ] @
Evo okacio sam dva screenshota. Jedan dobijem prilikom XYZ rotacije, a drugi
prilikom ZYX rotacije.Kao sto vidis skoro su identicni. Inache da bi se
skelet video kao na tim slikama morao sam da ga transliram -8000 po z osi.
Ako ne uradim tu translaciju onda se ne vidi nista, ako transliram za recimo
-1000 onda se vidi samo jedan deo, tek posle -5000 vidi se celi skelet.
Koliko sam ja provalio, nakon sto se izvrsi funkcija DrawBone() skelet se nalazi
malo iza kamere (pri default orijentaciji koordinatnog sistema u openGL-u)
i ogroman je, tako da moram mnogo da ga transliram da bih ga celog video.
Znaci gotovo istu stvar mogu da dobijem i ako rotiram kameru za 180 stepeni i transliram skelet ali u suprotnom smeru.

Dakle kod izgleda ovako:
Code:
 
    glLoadIdentity();
    glTranslatef(0.0f,0.0f,-8000.0f);
    DrawBone(skelet.root);
    glutSwapBuffers();

Da li bi mogao da okacis jedan skin fajl koji odgovara ovom skeletu, jer
ja nemam ni MAX ni Maya (u stvari nemam ni jedan program za 3d modelovanje :)
kako bih pokusao da sve to skupa animiram. Za sada cu se skoncentrisati
samo na to da dobijem kompletnu wireframe animaciju jer jos uvek nista
ne znam o GLSL, ali jedno po jedno doci ce i to na red :)
Ocekuj uskoro jos pitanja na ovu temu (ako nije problem).

Pozdrav!
[ yooyo @ 14.12.2004. 12:50 ] @
hmm... slicice su prilicno sitne pa nemogu tacno da utvrdim da li je sve OK. Zato ti saljem u prilogu Maya screenshot base pose i 2 Maya MEL scripta koji ce ti olaksati zivot.

Dakle...
1. Startuj Mayu i otvori script editor (mala ikonica pored edit polja u donjem desnom cosku programa)
2. Kada otvoris script editor iz njegovog menija otvori readHTRBasePose.mel.
3. Script editor je podeljen na 2 dela. u donjem delu se nalazi tvoj script. Selektuj sve i pritisni Ctrl+Enter. Script ce biti interpretiran i spreman za koriscenje.
4. Obrisi sve iz donjeg dela

Sada ukucaj:

readHTRBasePose "" <Ctrl+Enter>

i otvorice se File Open dijalog. Izaberi walk.htr i pojavice se skeleton u Mayi. Zatvori script editor. Posto je najverovatnije skeleton ogroman neces nista videti na ekranu. Pritisni taster 'F' i Maya ce fitovati scenu na ekran i videces ceo skeleton.
Mozes ga razgledati pomocu 'Alt' tastera i levi/srednji/desni taster misa za rotaciju/pan/zoom.

Drugi script moze da importuje celu htr animaciju. Potrebno je da prvo ucitas base pozu (kao gore), zatim da selektujes ROOT joint i da pokrenes drugi script. Ukucaj start i end frame i saceka malo... reziltat je animacija skeletona.

yooyo
[ Nothingman @ 15.12.2004. 00:11 ] @
Animirao sam skeletona i moram priznati da sam se odusevio animacijom.
Ovo nije walk, ovo su neki karate potezi :) Mislim da sam nasao sebi zanimaciju
za duze vreme jer se necu smiriti dok mu ne nabacim skin i texturu, a posle toga
cu verovatno da se bacim i na GLSL.
Okacio sam exe fajl ako neko zeli da vidi kako animacija izgleda. Nisam ogranicio FPS jer kod mene radi OK, mada bi kod ljudi sa boljim masinama moglo biti prebrzo...

Sada mi ostaje da negde nabavim Maya i da napravim skin za ovaj skelet.
Nadam se da u programu postoje neki gotovi skinovi jer u suprotnom
ko zna kada bih sam uspeo da ga napravim od pocetka :)

Pozdrav!

p.s. hvala yooyo!
[ yooyo @ 16.12.2004. 17:55 ] @
Na www.alias.com mozes skinuti studentsku verziju Maye koja je veoma slicna pro verziji osim sto se nemogu razmenjivati fajlovi iz ove 2 verzije. Studensta verzija je free i mozes je koristiti za ucenje.

yooyo