PDA

View Full Version : Collisione terreno


okay
21-12-2003, 11:34
Dunque

Sto facendo un tutorial tutto in italiano (per vc6++ in directx 8 con direct3d) implementando un motore grafico per sviluppare videogame.

Per ora il motore a queste funzioni:
- Schermate iniziali di presentazione
- Musica in background (file mid, wav o mp3)
- Effetti sonori (sfx)
- 2 oggetti, un terreno e un cubo con le proprie texture e effetto luce sui materiali ecc, ecc.)

Ogni oggetto ha una propria telecamera (perlomeno ho capito che ogni oggetto è bene che abbia una propria telecamera.

Movimenti nel mondo attraverso i tasti freccia e movimenti nell'ambiente tramite mouse (tipo doom unreal o fifa), per intenderci.

-------------------------------------

Ora devo capire come fare gli algoritmi di collisione, ovvero riuscirei a farli, infatti sto studiando geomettria 3d (gli assi x,y e z), ma non sono riuscito a capire le variabili da prendere in considerazione per poter sviluppare l'algoritmo di collisione.

Dunque, la domanda è questa:
Avete presente un terreno montagnoso?, ebbene con il tastofreccia UP mi avvicino alle montagne, ecco..... dovrei fare in modo di non bucare la montagna, ma scalarla oppure scenderla ma non passarci attraverso

dunque ragionando insieme, se al mio terreno tolgo le montagne ovvero lo rendo un piano uniforme, riesco a camminare sul piano, correggetemi se sbaglio, il piano dovrebbe avere coordinate +0 se cammino sopra e -0 se cammino sotto.

dalla mia vista che è il vettore Z le montagne si avvicinano allo schermo, il vettore Z diminuisce fino ad andare in negativo per i poligoni che io come osservatore non vedo più in quanto sono dietro lo schermo. bene ha questo punto l'algoritmo deve permettermi di salire (spostare la telecamera della visuale sul terreno e scendere quando il vettore Z è positivo.

Se qualcuno sà come normalizzare un vettore oppure come calcolare se si è entrati in collisione con i poligoni (che poi sono triangoli) del terreno....... e mi volesse aiutare...........



Buon natale a tutti

Cionci sei forte.........

N.B Questo tutorial lo rendero di pubblico dominio
In quanto ho trovato molte difficolta a reperire materiale e info in italiano su direct3d e directx (anzi in pratica non c'è quasi niente)

cionci
21-12-2003, 12:11
Originariamente inviato da okay
Cionci sei forte.........

Sei forte te se fai una cosa del genere ;)
Sinceramente non so come potresti fare...pensa che in OpenGL mi sono fermato circa allo stesso punto...

Comuqnue qualcosa ho trovato: http://www.mvps.org/directx/articles/using_bounding_spheres.htm
Anche se non risolve il problema del terreno, ma solamente il problema della collisione fra oggetti racchiudibili in una sfera...

alfa2000
21-12-2003, 14:27
brutto non sapere di calcolo vettoriale !

PGI
21-12-2003, 15:04
Io un'idea ce l'avrei anche (tipo mappa delle altezze)

-crei una bitmap che rappresenti il terreno in 2d, "visto dall'alto"

-dall'immagine generi il terreno: ogni pixel può rappresentare un quadrilatero di coordinate P0(x,y,z), P1(x+w, y, z), P2(x+w, y, z+w), P3(x, y, z+w) dove p0.x e p0.z sono le coordinate "origine" del terreno sul piano XZ e il valore di y lo ricavi dall'intensità del colore del pixel. Dalla stessa immagine generi un matrice nxm in cui infili i valori di y usati per generare il terreno.

A questo punto per stabilire a che altezza si deve trovare un oggetto in un certo punto della mappa è sufficiente ricavare le coordinate x-z della sua posizione: se dividi x e z per il valore w usato nella costruzione del terreno e arrotondi all'intero inferiore ottieni due indici n,m che rappresentano la "cella" in cui si trova l'oggetto la cui "altezza" è quella contenuta nell'elemento n-m della matrice delle altezze.

Non è necessario che la matrice delle altezze abbia la stessa risoluzione della mappa (ad esempio potresti creare un quadrilatero per ogni pixel ai fini della creazione del terreno mentre per la matrice suddividi il pixel in 9 parti), quindi potresti risolvere il problema del "movimento a salti" aumentato il campionamento nella matrice (che è un array di [n][m] float o double).

Io una cosa del genere l'avevo provata tempo fa e funzionava ma non so se sia il metodo usato "nella realtà".

Ciao.

cionci
21-12-2003, 17:05
Originariamente inviato da alfa2000
brutto non sapere di calcolo vettoriale !
Certo, ma se certi strumenti (come quello precdente) li offrono già le Direct3D allora è meglio sfruttare quelli, visto che probabilmente saranno più efficienti quelli già integrati...

cionci
21-12-2003, 17:38
Guarda qua:

http://members.xoom.virgilio.it/robydx/VarieLess12.htm
http://members.xoom.virgilio.it/robydx/VarieLess14.htm

alfa2000
21-12-2003, 21:02
Originariamente inviato da cionci
Certo, ma se certi strumenti (come quello precdente) li offrono già le Direct3D allora è meglio sfruttare quelli, visto che probabilmente saranno più efficienti quelli già integrati...

probabilmente sì ... ma probabilmente no se vogliono farti cambiare computer ogni 12 mesi ...

comunque anche qualche nozione di aritmetica non guasterebbe per esempio:

5 + 10 = 15

e non

5 + 10 = 21 (ad oggi)

adesso che ti hanno fatto moderatore modera anche i moderatori smoderati.

okay
22-12-2003, 02:23
Okay grazie a tutti

ora metto sul terreno un'altro cubo rendolo indipendente dal terreno e cerco di farlo camminare sul terreno controllando le variabili della sua matrice (telecamera, scrivendole in un file testo) nel momento che buca i poligoni del terreno, riportandolo al piano
........ va bè ci siamo capiti

vi faccio sapere:

x PGI: ci stai vicino ............. questa è l'email di risposta di un mio amico per darmi delle idee sulla questione (potrebbe essere utile anche a voi):

x Cioci:
Grazie funambolico spirito libero....... ciao amico mio


--------------------
buone feste anche a te.

Mi mandi il codice sorgente? Così gli do una occhiata perché questa questione di usare due matrici di proiezione differenti non l'ho capita molto :-), cioè la proiezione serve per trasformare le coordinate dal sistema mondo a quello video e quindi è unica per tutta la scena; poi ci sarà una matrice diversa per ogni oggetto presente.
La catena è questa:
Locale -> Mondo -> Camera -> Base -> Proiezione

Locale -> Mondo: Matrice per le trasformazioni applicate all'oggetto (l'unica che deve cambiare all'interno della scena)
Mondo -> Camera: Matrice per trasformare le coordinate nel sistema dell'osservatore (unica per ogni frame)
Camera -> Base: Matrice per cambiare la base del sistema di riferimento (non è obbligatoria e serve ad esempio per passare da un sist. destrorso ad uno sinistrorso)
Base -> Proiezione: La classica matrice che effettua le proporzioni X/Z e Y/Z (circa)

Io sto scrivendo un emulatore software delle DirectX e utilizzo questo metodo che è il più lineare e logico.

Per quanto riguarda le collisioni ci sono diversi metodi, se hai a disposizione la mappa del terreno puoi tranquillamente prendere l'altezza dello stesso in corrispondenza dell'oggetto che ti interessa e aggiungergli una costante (se vuoi che segua il terreno), come si faceva per il voxel. A proposito se ti interessa sto scrivendo un tutorials su questo vecchio argomento.
Se invece vuoi trovare effettivamente la collisione il metodo più semplice è considerare l'oggetto come incluso in una sfera, conoscendo la posizione del suo baricentro, il raggio e la posizione dei triangoli che compongono il terreno si effettua una intersezione fra un raggio uscente dalla sfera e i triangoli; ovviamente solo sui triangoli più vicini.
Trovi molti tutorials sulla collisione e intersezione nel sito www.magic-software.com (spero di non essermi sbagliato), prova a fargli una visita; oppure fai una ricerca con i termini "Realtime collision".

Ciao!
--------------------

cionci
22-12-2003, 11:19
Originariamente inviato da alfa2000
adesso che ti hanno fatto moderatore modera anche i moderatori smoderati.
Hai ragione... Ne ho parlato ed ho riabilitato l'account a2000 però di banno questo (non si possono usare più account)...

fek
22-12-2003, 12:10
Originariamente inviato da okay
Ogni oggetto ha una propria telecamera (perlomeno ho capito che ogni oggetto è bene che abbia una propria telecamera.


Perche' una telecamera per oggetto?
Oppure stai parlando di matrice, ogni oggetto ha una propria matrice di trasformazione.


Ora devo capire come fare gli algoritmi di collisione, ovvero riuscirei a farli, infatti sto studiando geomettria 3d (gli assi x,y e z), ma non sono riuscito a capire le variabili da prendere in considerazione per poter sviluppare l'algoritmo di collisione.

Le variabili sono semplicemente la posizione dell'oggetto, il suo vettore velocita' e i dati del terreno.
Ad ogni frame tiri un "raggio" che parte dalla posizione dell'oggetto in direzione della sua velocita' e intersechi questo raggio con il terreno per capire se e dove "collidono", come dire che stai cercando di capire se durante il tragitto del corpo durante il frame, questo va a collidere in qualche punto col terreno.

I dettagli dell'algoritmo di collisione dipendono fortemente da come rappresenti il terreno.

Una soluzione veloce ti e' gia' stata descritta in questo thread e funziona bene.


Dunque, la domanda è questa:
Avete presente un terreno montagnoso?, ebbene con il tastofreccia UP mi avvicino alle montagne, ecco..... dovrei fare in modo di non bucare la montagna, ma scalarla oppure scenderla ma non passarci attraverso

Oltre al punto di collisione ti interessa la normale alla superfice in quel punto.

Una volta che hai la normale, affinche' l'oggetto non penetri il terreno devi assicurarti che la sua velocita' sia correttamente "tagliata" (si dice "chopped" in inglese ma non saprei come tradurlo bene in italiano :p).

Per capirci meglio dovrei disegnare una figura, ma immagina di camminare contro un muro, come eviti di andarci contro? Spostandoti solo parallelamente ad esso, quindi "tagliando via" ogni movimento che va verso il muro.

In termini matematici, hai il vettore N (la normale al terreno nel punto di collisione), il vettore V (la velocita' del corpo che deriva dagl'input dell'utente nel tuo caso o dai calcoli di un motore di fisica ad esempio) e ti serve calcolare la nuova velocita' V1 affinche' il corpo si muova parallelamente al muro e non verso il muro.

V1 = V - dot(V, N)*N

Dove dot(V, N) e' il prodotto scalare fra il vettore velocita' V e la normale N e rappresenta l'angolo fra la velocita' e la normale, in altre parole ti da' una valutazione di quanto il corpo si sta muovendo verso il terreno. Se il corpo si sta muovendo direttamente verso il terreno (a 90 gradi) il prodotto scalare avra' valore massimo, per la precisione pari alla lunghezza del vettore V perche' N ha per definizione lunghezza 1 (essendo una normale).

Moltiplicando il prodotto scalare per il vettore N, trovi il vettore che rappresenta esattamente di quanto il corpo si sta muovendo verso il terreno. A questo punto ti basta sottrarlo al vettore velocita' iniziale per trovare la velocita' residua parallela al terreno. Sei cosi' garantito che a seguito di una collisione, il corpo non cerchera' di penetrare il terreno perche' tu stai forzando la sua velocita' ad essere parallela al terreno stesso.



dalla mia vista che è il vettore Z le montagne si avvicinano allo schermo, il vettore Z diminuisce fino ad andare in negativo per i poligoni che io come osservatore non vedo più in quanto sono dietro lo schermo. bene ha questo punto l'algoritmo deve permettermi di salire (spostare la telecamera della visuale sul terreno e scendere quando il vettore Z è positivo.

Cancella tutto e lavora nello spazio del mondo, non in quello di proiezione.


Se qualcuno sà come normalizzare un vettore oppure come calcolare se si è entrati in collisione con i poligoni (che poi sono triangoli) del terreno....... e mi volesse aiutare...........

La prima domanda e' facile, la seconda meno :)

Per normalizzare un vettore devi dividerlo per la sua lunghezza.

La lunghezza (o norma) di un vettore V e' definita come:

V / dot(V, V)

Dove dot() e' il prodotto scalare, che per vettori in 3 dimensioni si calcola cosi':

dot(V, U) = Vx * Ux + Vy * Uy + Vz * Uz



Buon natale a tutti


Ciao e buon natale.

okay
22-12-2003, 14:30
okay fek...........

Si scusami intendevo una matrice per oggetto!

dunque..............
Da buon programmatore autodidatta (asm, c++, vb, web ecc,ecc.)
Ho costruito le mie classi in c++, il mio problema ora è la geometria 3d applicata al pc (si era capito eh......!?!?)
..... ora, quello che mi manca è il refiremento alle variabili per poter fare gli algoritmi di collisione al terreno (per adesso):
per es. (le mie classi):

Terreno.h

struct TERRAIN_CUSTOMVERTEX
{
FLOAT x, y, z; //Posizione dei vertici
FLOAT nx, ny, nz; //Luce
FLOAT tu, tv; //Coordinate Texture
};

WORD m_wRows; //righe
WORD m_wCols; //colonne
WORD m_wMaxHeight; //massima altezza terreno
float m_rTileSize; //ampiezza rettangoli (poligoni)

DWORD m_dwNumOfVertices; //n. vertici
DWORD m_dwNumOfIndices; //n. indici
DWORD m_dwNumOfPolygons; //n. poligoni



Terreno.cpp

m_dwNumOfVertices = (m_wCols + 1) * (m_wRows + 1);
m_dwNumOfPolygons = m_wRows * m_wCols * 2;
m_dwNumOfIndices = m_dwNumOfPolygons * 3;


D3DXVECTOR3 CTerrain::GetTriangeNormal(D3DXVECTOR3* vVertex1, D3DXVECTOR3* vVertex2, D3DXVECTOR3* vVertex3)
{
D3DXVECTOR3 vNormal;
D3DXVECTOR3 v1;
D3DXVECTOR3 v2;

D3DXVec3Subtract(&v1, vVertex2, vVertex1);
D3DXVec3Subtract(&v2, vVertex3, vVertex1);

D3DXVec3Cross(&vNormal, &v1, &v2);

D3DXVec3Normalize(&vNormal, &vNormal);

return vNormal;
}


bool CTerrain::SetSize(WORD wRows, WORD wCols, float rTileSize, WORD wMaxHeight)
{
//Setto grandezze
m_wRows = wRows;
m_wCols = wCols;

//Setto grandezza quadrati dei poligoni
m_rTileSize = rTileSize;

//Setto la massima altezza dei vertici
m_wMaxHeight = wMaxHeight;

//Setto i contatori per il terreno
m_dwNumOfVertices = (m_wCols + 1) * (m_wRows + 1);
m_dwNumOfPolygons = m_wRows * m_wCols * 2;
m_dwNumOfIndices = m_dwNumOfPolygons * 3;

AggiornoVertici();

return true;
}





bool CTerrain::AggiornoVertici()
{

DWORD i = 0;
VOID* pVertices;
WORD* pBufferIndices;
D3DXVECTOR3 vNormal;
DWORD dwVertex1;
DWORD dwVertex2;
DWORD dwVertex3;

WORD* pNumOfSharedPolygons = new WORD[m_dwNumOfVertices];

D3DVECTOR* pSumVertexNormal = new D3DVECTOR[m_dwNumOfVertices];

TERRAIN_CUSTOMVERTEX* pcvVertices = new TERRAIN_CUSTOMVERTEX[m_dwNumOfVertices];
float x, z;

//Centro il terreno intorno all'origine
float zStart = (float)(0.0 - (m_wRows/2.0));
float zEnd = (float)(m_wRows/2.0);
float xStart = (float)(0.0 - (m_wCols/2.0));
float xEnd = (float)(m_wCols/2.0);
//Initialise the random number generator
srand(timeGetTime());

//Cancello memoria e setto i vertici del terreno
for(z = zStart; z <= zEnd; z++)
{
for(x = xStart; x <= xEnd; x++)
{
pNumOfSharedPolygons[i] = 0;
pSumVertexNormal[i] = D3DXVECTOR3(0,0,0);

pcvVertices[i].x = x * m_rTileSize;

if((z == zStart) || (z == zEnd) || (x == xStart) || (x == xEnd))
{
pcvVertices[i].y = 0.0;
}
else
{
//Random altezza per y
pcvVertices[i].y = (float)(rand() % m_wMaxHeight);

}


pcvVertices[i].z = -z * m_rTileSize;
pcvVertices[i].nx = 0.0;
pcvVertices[i].ny = 0.0;
pcvVertices[i].nz = 0.0;

if(((int)z % 2) == 0)
{
if(((int)x % 2) == 0)
{
pcvVertices[i].tu = 0.0;
pcvVertices[i].tv = 0.0;
}
else
{
pcvVertices[i].tu = 1.0;
pcvVertices[i].tv = 0.0;
}
}
else
{
if(((int)x % 2) == 0)
{
pcvVertices[i].tu = 0.0;
pcvVertices[i].tv = 1.0;
}
else
{
pcvVertices[i].tu = 1.0;
pcvVertices[i].tv = 1.0;
}
}

i++;
}
}



m_pIndexBuffer->Lock(0, m_dwNumOfIndices * sizeof(WORD), (BYTE**)&pBufferIndices, D3DLOCK_READONLY);

//Aggiungo attraverso la normale nei vertici
//quale è la normale?????????

for(i = 0; i < m_dwNumOfIndices; i += 3)
{
dwVertex1 = pBufferIndices[i];
dwVertex2 = pBufferIndices[i + 1];
dwVertex3 = pBufferIndices[i + 2];

vNormal = GetTriangeNormal(&D3DXVECTOR3(pcvVertices[dwVertex1].x, pcvVertices[dwVertex1].y, pcvVertices[dwVertex1].z),
&D3DXVECTOR3(pcvVertices[dwVertex2].x, pcvVertices[dwVertex2].y, pcvVertices[dwVertex2].z),
&D3DXVECTOR3(pcvVertices[dwVertex3].x, pcvVertices[dwVertex3].y, pcvVertices[dwVertex3].z));


pNumOfSharedPolygons[dwVertex1]++;
pNumOfSharedPolygons[dwVertex2]++;
pNumOfSharedPolygons[dwVertex3]++;

pSumVertexNormal[dwVertex1].x += vNormal.x;
pSumVertexNormal[dwVertex1].y += vNormal.y;
pSumVertexNormal[dwVertex1].z += vNormal.z;

pSumVertexNormal[dwVertex2].x += vNormal.x;
pSumVertexNormal[dwVertex2].y += vNormal.y;
pSumVertexNormal[dwVertex2].z += vNormal.z;

pSumVertexNormal[dwVertex3].x += vNormal.x;
pSumVertexNormal[dwVertex3].y += vNormal.y;
pSumVertexNormal[dwVertex3].z += vNormal.z;

}


//Quì calcolo la normale?????????

for(i = 0; i < m_dwNumOfVertices; i++)
{
vNormal.x = pSumVertexNormal[i].x / pNumOfSharedPolygons[i];
vNormal.y = pSumVertexNormal[i].y / pNumOfSharedPolygons[i];
vNormal.z = pSumVertexNormal[i].z / pNumOfSharedPolygons[i];

D3DXVec3Normalize(&vNormal, &vNormal);

pcvVertices[i].nx = vNormal.x;
pcvVertices[i].ny = vNormal.y;
pcvVertices[i].nz = vNormal.z;
}


Quali altre variabili ho biogno per fare l'algoritmo di collisione al terreno?????????????????

Queste sono tutte le variabili che ho ha disposizione........
ne devo mettere altre????????
Come faresti tu????????
Cosa prendere in considerazione per i calcoli di collisione al terrenio???????

N.B.
Questa è la chiamata in main.cpp per creare il terreno attraverso il device

//TERRENO

//creo l'oggetto terreno (device, tile rows, tile cols, tile size, max height)
//Questo sotto creo montagne (ma è disabilitata dal commento)
//m_pTerrain1 = new CTerrain(g_pDevice, 20, 20, 10.0, 15);
//questa sotto creo un piano liscio erboso
m_pTerrain1 = new CTerrain(g_pDevice, 100, 100, 1.0, 1);
//setto la texture
m_pTerrain1->SetTexture("Texture//Grass.bmp");

ciao

fek
22-12-2003, 14:50
Originariamente inviato da okay
Queste sono tutte le variabili che ho ha disposizione........
ne devo mettere altre????????
Come faresti tu????????
Cosa prendere in considerazione per i calcoli di collisione al terrenio???????

Hey, inizia dalle cose piu' semplici e poi passa al terrain rendering ;)

Bane
22-12-2003, 16:19
Originariamente inviato da fek
V1 = V - dot(V, N)*N

Dove dot(V, N) e' il prodotto scalare fra il vettore velocita' V e la normale N e rappresenta l'angolo fra la velocita' e la normale, in altre parole ti da' una valutazione di quanto il corpo si sta muovendo verso il terreno.


Non per essere pignolo... ma altrimenti mica si capisce =)

dot(V, N) rappresenta la "lunghezza" (con segno) della proiezione di V su N (dato che N e' unitario), non l'angolo fra V ed N.

Chiusa parentesi =)

fek
22-12-2003, 18:01
Originariamente inviato da Bane
Non per essere pignolo... ma altrimenti mica si capisce =)

dot(V, N) rappresenta la "lunghezza" (con segno) della proiezione di V su N (dato che N e' unitario), non l'angolo fra V ed N.

Chiusa parentesi =)

Fai bene ad essere pignolo :)

Sono stato indeciso per un po' se scrivergli la formuletta oppure no, ma poi ho optato per una versione "soft".
Tagliamo la testa al toro e scriviamola tutta allora:

dot(V, N) = |V||N|cos(a)

Dove:
|V| = lunghezza del vettore V
|N| = lunghezza del vettore N
a = angolo fra i due vettori

In parole, il prodotto scalare rappresenta quanto un vettore si "appoggia" su un altro e dipende dall'angolo fra i due vettori. Tornando all'esempio del muro, se mi dirigo direttamente sul muro il mio vettore velocita' e' parallelo alla normale al muro quindi si "appoggia" interamente su essa. Se cammino parallelamente, allora la velocita' e perpendicolare alla normale e non si "appoggia".

Spero sia piu' chiaro cosi'.