3deng qa 01

Q :
V tom prvním 3d-engine je chyba. Když se přiletí s letadlem blízko ke kameře, tak se prohodí předek a zadek.

A :
Není to chyba v engine, jen je špatně nastavená konstanta perspektivního zkreslení. Zkus si ji změnit (přidej si obsluhu třeba tlačítky */) a uvidíš.



Q :
Říkal jsi že první tři řádky v matici jsou různé vektory a pozice matice. Dá se toho nějak využít ? A dá se matice posouvat taky podle os souřadnicového systému a ne podle vlastních jak to dělá funkce translatematrix() ?

A :
Ano, dobrá otázka - zapomněl jsem to tam dát. Matice jsou vlastně čtyři vektory. Tři udávají směr souřadných os (x, y, z), jsou na sebe tudíž vždycky kolmé a jejich velikost je 1 a ten čtvrtý je už vzpomenutá pozice :


+                    +
| u.x  v.x  w.x  p.x |
| u.y  v.y  w.y  p.y |
| u.z  v.z  w.z  p.z |
| 0    0    0    1   |
+                    +

Dobře.. u je vektor, směřující doprava, v směřuje nahoru a vektoru w dopředu (pokud matice patří kameře, kamera se dívá právě tímto směrem) jak jsem na to přišel ? Můžete si to odvodit z jednotkové matice :


+                    +
| 1    0    0    0   |
| 0    1    0    0   |
| 0    0    1    0   |
| 0    0    0    1   |
+                    +

Potom u = (1, 0, 0), v = (0, 1, 0), w = (0, 0, 1) a pozice = (0, 0, 0) - je to jednoduché. Dá se to použít třeba ke konstrukci kamery když známe jen její pozici a místo, kam se dívá :


Matrix Camera_Create(Vector pos, Vector target)
{
    Vector up, right, direction;
    Matrix cam;

    up.x = 0;
    up.y = 1;
    up.z = 0;
    // vektor ukazujici nahoru

    direction.x = target.x - pos.x;
    direction.y = target.y - pos.y;
    direction.z = target.z - pos.z;
    _Normalize(direction);
    // vektor "kudy se kamera diva"

    _Cross(up, direction, right);
    _Normalize(right);
    // vektor doprava
    // (anebo taky doleva pokud prohodite poradi up a dir.)

    _Cross(right, direction, up);
    _Normalize(up);
    // ted uz jsou na sebe vsechny vektory zarucene kolme

    cam[0][0] = right.x;
    cam[0][1] = right.y;
    cam[0][2] = right.z;
    // doprava

    cam[1][0] = up.x;
    cam[1][1] = up.y;
    cam[1][2] = up.z;
    // nahoru

    cam[2][0] = direction.x;
    cam[2][1] = direction.y;
    cam[2][2] = direction.z;
    // direction

    cam[3][0] = pos.x;
    cam[3][1] = pos.y;
    cam[3][2] = pos.z;
    // pozice

    cam[0][3] = 0;
    cam[1][3] = 0;
    cam[2][3] = 0;
    cam[3][3] = 1;
    // posledni radek

    return cam;
}

Tahle funkce vytvoří matici kamery, která je na pozici pos a dívá se směrem k target. Posouvat matici po osách systému jde, prostě se k vektoru pozice v kameře přičte vektor posunutí. Je to logické a nebolí to :-)



Q :
Ahoj ! Prokousávám se seriálem o 3D-Enginech, právě se učím matice v matice - to je legrační. Kde se to vlastně dá naučit ? Mám takovej problém - když počítám inverzní matici tak mi ta tvoje funkce dá vždycky jinej výsledek ! Je to špatně ?

A :
No, špatně to určitě není, jinak by to nefungovalo. Musíš si pamatovat že v posledním řádku matice je vždy {0, 0, 0, 1} a na to je taky funkce optimalizovaná. Zkus si to spočítat třeba v excelu a mělo by to vyjít - je tam přímo funkce pro inverzi matice. Když se to počítá ručně, musíš si pamatovat že většina věcí v učebnicích se dělá pro matice 3.řádu a pro matice 4.řádu ty pravidla většinou už neplatí a musí se vypouštět řádky a sloupce a vznikají menší matice se kterými se operace provádí znovu dokud nevyjde matice dost malá atd.. Naučit se to dá - pokud umíš anglicky, zadej v googlu matrix a budeš se tím moct prokousávat roky :-) nebo zkus www.math.com, tam taky něco bude. No a pokud anglicky neumíš, puč si nějaký středoškolský skripta nebo učebnice na matiku, je to skoro ve všech průmyslovkách, občas i v ekonomkách a občas i úplně jinde. Jo, a taky - matice je nejen inverzní, ale i transponovaná ! (má prohozené řádky a sloupce)



Q :
Zrovna se prokousávám těma maticema, co tam máš napsané v enginech. Zajímala by mě jedna věc: používá se tam pole typu float. Chápu ze to musí byt přesně. Proč velikost 4*4 ? Píšeš tam ze jsou to čtyři vektory a jeden ukazuje doprava druhý nahoru a třetí dopředu. To znamená x,y,z. Proč je každá souřadnice napsaná třemi čísly. Možná ze jsi nepochopil co po tobě vlastně chcu tak se to zkusím napsat nějak lip. Proč je směr doprava definován třemi neznámými (čísly), nahoru taky třemi, dopředu taky třemi ?

A :
Správně. sou tam tři vektory, takže stačí matice 3 × 3. ale pokud chceš s objektem ještě posouvat, potřebuješ ještě tři souřadnice. ale s maticí 3 × 4 nemůžeš pracovat - matice musí být čtvercová - takže se rozšiřuje na 4 × 4 ...

doufám ze to tak stačí, kdyžtak esce napiš...



Q :
Asi jsem fakt napsal blbe otázku a tak ještě jednou. Otázka byla proč je jeden směr definován třemi neznámými. Já jsem si proste myslel ze když chcu mít bod v prostoru tak k vyjádření jeho polohy mi stačí tři čísla. A ta matice je 4*4 takže jeden sloupec je určen k posouvání (poslední sloupec) a jeden řádek - ten poslední dolní je na doplnění k nutnosti počítáni aby byla ne 3*4 ale 4*4. A teď k jádru věci zbývá nám tedy (bez posunovacího sloupce a doplňujícího řádku) matice velikosti 3*3 což dohromady dává devět prvků. A zjevně jak jsem pochopil se nakonec používá asi jenom diagonála (3 prvky). Poslední větu neber jako součást otázky, ale můžeš k tomu taky něco napsat.

A :
Aha .. byl jsem nějak mimo .. ne, nepoužívá se jen diagonála, ale všechny prvky v matici. Diagonála se naplní jedničkami, aby vektory odpovídaly původnímu směru souřadnicových os x, y, z ... Při transformaci se jich použije všech devět. ty 3 × 3 jsou tri vektory - nahoru, doprava a dopředu - což tedy odpovídá osám x, y, z. jde samozřejmě definovat i pomoci dvou, jenže s tím se nedá počítat (pomalu) ...



Q :
Tak a jsme konečně u jádra věci. Tři vektory nahoru doprava a dopředu. Teda spíš doprava nahoru a dopředu. V celé matici je nakonec ale uložená pozice jenom jednoho bodu ne ? Proč je nutné aby byl směr (jedna souřadnice) definovaná vektorem a ne jenom jedním číslem. Vektory jsou totiž v tomto případě čísla 3 nebo se mýlím?

A :
to jo.. jeden bod, jenže ten bod je relativní ke svému vlastnímu souřadnicovému systému. jednou maticí se transformuje celý objekt, takže ty body se otáčí kolem nuly v objectspace. Jednodušeji to opravdu nejde. Můžeš jen použít polární souřadnice, což by vyšlo na minimum čísel, ale složitější počítání. Mimochodem - Vektor definuje směr, číslo je jen tzv. skalár - délka.



Q :
Tak fajn tím už se nebudu zabývat. Zkoušel jsem k tomu tvém enginu dávat svoje scény ze 3d studia MAX a zjistil jsem že jeden objekt se vůbec nehýbe a ten druhý se hýbe po vlastních osách, ale rotace je trochu divná protože objekt nerotoval po svých osách ale po těch které byly ve studiu. To znamená že když jsem tam mel třeba krychli tak se netočila kolem svého středu, ale kolem nějakého bodu mimo ni. Dá se to nějak vyřešit?

A :
Když objekty nahraješ, musíš jim inicializovat matice, až potom s nimi pracovat .. jestli to bude ten efekt co chceš.. jinak tam je problém, že 3d-studio má asi trochu chybu v maticích, protože posuny občas nezahrne do matice, ale dá je přímo do vertexů ... je to trochu problém. Já používám 3D Max R3 a R5, u R3 nebyl problém, spíš mi vadilo u třeba letadla z více částí Že každá část (křídla, motory …) rotuje po vlastních souřadnicích :-)



Q :
Potřeboval bych objasnit jeden řádek ve funkci násobení matic. Je to ten poslední a asi bude něco předávat dál, ale nechápu ho - nevím co je to za příkaz a jak funguje. Je to tento řádek :

    memcpy(r, temp, sizeof(Matrix));

Jinak radši tady dám celou funkci, aby to bylo jasnější a přehlednější.


void Matrix_Multiply(Matrix *a, Matrix *b, Matrix *r)
{
    Matrix temp;
    int i, j;
 
    for(i = 0; i < 4; i ++) {
        for(j = 0; j < 4; j ++)
            temp[i][j] = (*a)[0][j] * (*b)[i][0] + (*a)[1][j] * (*b)[i][1] +
                (*a)[2][j] * (*b)[i][2] + (*a)[3][j] * (*b)[i][3];
    }
    memcpy(r, temp, sizeof(Matrix));
}

A :
ten příkaz zkopíruje obsah matice temp do matice r. nejde napsat r = temp, protože r je ukazatel do paměti. r[0] = temp taky nebude fungovat, protože je to dvourozměrné pole (-> pole pointerů) takže se musí kopírovat paměť. Funkci dáš pointer kam, pointer odkud a velikost v bytech a už to jede :-)
No, konečně se to rozjelo - a stačil jeden člověk. Velké díky Petrovi K :-) pište dál, a to sem !
Zpátky


Valid HTML 4.01!
Valid HTML 4.01