|
Detekce kolizí kamery s BSP scénou
|
|
|
Princip detekce kolizí kamery s BSP scénou je celkem jednoduchý.
V předešlém tutorialu na načítání Quake III BSP scény jsme se dozvěděli,
že je scéna rozdělena na tzv. listy. Každý list obsahuje také informace
o kolizích (brushes). Tyto informace již máme načteny, takže stačí procházet scénou
a testovat, zda list, do kterého právě vcházíme obsahuje informace o kolizích. Pokud
informace obsahuje, tak vrátíme kameru zpět na pozici před kolizí. Pokud list
informace o kolizích neobsahuje, tak jím můžeme procházet.
Detekce kolize se neprovádí na bod pozice kamery, což by bylo nejjednodužší, ale
vytvořil jsem kolem kamery detekční body. Pokud bychom prováděli detekci jen s bodem
pozice kamery, nemohli bychom určit výšku a šířku avatara a navic by kamera byla tak
blízko stěn, že by v některých případech docházelo k pohledu skrz stěnu.
Princip detekčních bodů si vysvětlíme na bodech přímky souřadnice X.
Když kameru otočíme podle souřadnicového systému, tak
vpravo od kamery je detekční bod +X, po levé straně detekční bod -X.
Pokud dojde k detekci kolize bodu +X se stěnou, tak se kamera pohne v X
směru zpět o hodnotu rychlosti kamery (KameraX = KameraX - RychlostX).
Pokud dojde k detekci kolize bodu -X se stěnou, tak se kamera pohne v X
směru zpět o hodnotu rychlosti kamery (KameraX = KameraX + RychlostX).
Bod +X a -X tvoří přímku X. X přímky jsou tři. Horní a dolní, které určují
výšku avatara a výšku předmětu, který nepude překročit. Třetí prostřední přímka protíná
bod pozice kamery. Stejný algoritmus se provádí i pro souřadnici Z. U souřadnice Y
jsou detekční přímky dvě, aby avatar nepropad skrz podlahu při přechodu z jednoho listu do druhého.
Spodní body se generují tak, že v cyklu se odečítají hodnoty od výšky předmětu, který nejde
překročit, po nejmenší hodnotu -Y, která určuje výšku avatara. Body se generují v cyklu
aby avatar mohl chodit do schodů, případně překračovat objekty. Na obrázku jsou všechny tyto
body a přímky názorně zobrazeny. Pozice kamery je uprostřed těchto přímek.
Funkce BspCameraCollision(); vytvoří detekční body podle aktuální
pozice kamery.
|
|
inline void K_CQuake3Bsp::BspCameraCollision()
{
int i_dist = 30; // Nastav detekční vzdálenost
int i_ray_leaf_index; // Index listu ve kterém se zrovna nachází bod aktuálního detekčního paprsku
float pf_ray_point[3]; // XYZ pozice bodu aktuálního detekčního paprsku
// X ray left down, point 1
// Nastav levý dolní paprsek X, bod 1
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] - i_dist;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1] - 15;
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] - 10;
if(g_bViewCameraCollisionPoints) // Jestli to máš povolený, tak vykresli kolizní bod
{
glPushMatrix(); // Začátek prostorové matice
glPointSize(100.0f); // Nastav velikost bodu
glBegin( GL_POINTS ); // Začni vykreslovat body
glVertex3fv( pf_ray_point ); // Zadej vrchol bodu
glEnd(); // Ukonči vykreslování bodů
glPopMatrix(); // Konec prostorové matice
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0); // Najdi list ve kterém se nachází kolizní bod
if(CheckBrushCollision(i_ray_leaf_index)) // Jestliže došlo k detekci kolize
{
// Jestliže pohybuji kamerou doleva, nebo doprava, tak
if(g_bCameraStrafeLeft || g_bCameraStrafeRight)
{
// Musíš posunout X pozici kamery zpět o dnojnásobek hodnoty rychlosti
g_Camera.m_pfCurrPosition[0] += g_Camera.m_fSpeed * 2;
}
else // Jinak
{
// Posuň X pozici kamery zpět o hodnotu rychlosti
g_Camera.m_pfCurrPosition[0] += g_Camera.m_fSpeed;
}
}
// X ray left down, point 2
// Nastav levý dolní paprsek X, bod 2
// Kód je podobný, akorát je jiná pozice bodu a kamera se při detekci vrací opačným směrem
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] + i_dist;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1] - 15;
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] - 10;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
if(g_bCameraStrafeLeft || g_bCameraStrafeRight)
{
g_Camera.m_pfCurrPosition[0] -= g_Camera.m_fSpeed * 2;
}
else
{
g_Camera.m_pfCurrPosition[0] -= g_Camera.m_fSpeed;
}
}
// X ray middle, point 1
// Nastav prostřední paprsek X, bod 1
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] - i_dist;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1];
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2];
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
if(g_bCameraStrafeLeft || g_bCameraStrafeRight)
{
g_Camera.m_pfCurrPosition[0] += g_Camera.m_fSpeed * 2;
}
else
{
g_Camera.m_pfCurrPosition[0] += g_Camera.m_fSpeed;
}
}
// X ray middle, point 2
// Nastav prostřední paprsek X, bod 2
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] + i_dist;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1];
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2];
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
if(g_bCameraStrafeLeft || g_bCameraStrafeRight)
{
g_Camera.m_pfCurrPosition[0] -= g_Camera.m_fSpeed * 2;
}
else
{
g_Camera.m_pfCurrPosition[0] -= g_Camera.m_fSpeed;
}
}
// X ray right up, point 1
// Nastav pravý horní paprsek X, bod 1
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] - i_dist;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1] + 15;
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] + 10;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
if(g_bCameraStrafeLeft || g_bCameraStrafeRight)
{
g_Camera.m_pfCurrPosition[0] += g_Camera.m_fSpeed * 2;
}
else
{
g_Camera.m_pfCurrPosition[0] += g_Camera.m_fSpeed;
}
}
// X ray right up, point 2
// Nastav pravý horní paprsek X, bod 2
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] + i_dist;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1] + 15;
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] + 10;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
if(g_bCameraStrafeLeft || g_bCameraStrafeRight)
{
g_Camera.m_pfCurrPosition[0] -= g_Camera.m_fSpeed * 2;
}
else
{
g_Camera.m_pfCurrPosition[0] -= g_Camera.m_fSpeed;
}
}
//////////////////////////////////
// Y ray right backward, point 1
// Nastav pravý zadní paprsek Y, bod 1
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] + 2;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1] - 50;
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] + 2;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
// Cykluj, pokud je bod větší než jemenší detekční hodnota
// Cyklus se provádí aby kamera chodila do schodů
while(pf_ray_point[1] > g_Camera.m_pfCurrPosition[1] - 70)
{
pf_ray_point[1]--; // Odečti hodnotu bodu
int i_ray_leaf_index = FindLeaf(pf_ray_point, 0); // Najdi list ve kterém se nachází kolizní bod
if(CheckBrushCollision(i_ray_leaf_index)) // Jestliže došlo k detekci kolize
{
g_Camera.GoUp(); // Tak pohni kamerou nahoru
break; // A vyskoč z cyklu
}
}
// Y ray right forward, point 1
// Nastav pravý přední paprsek Y, bod 1
// Opakuje se předchozí algoritmus
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] + 2;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1] - 50;
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] - 2;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
while(pf_ray_point[1] > g_Camera.m_pfCurrPosition[1] - 70)
{
pf_ray_point[1]--;
int i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
g_Camera.GoUp();
break;
}
}
// Y ray right backward, point 2
// Nastav pravý zadní paprsek Y, bod 2
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] + 2;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1] + 20;
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] + 2;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
g_Camera.GoDown(); // Posuň kameru dolu
}
// Y ray right forward, point 2
// Nastav pravý přední paprsek Y, bod 2
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] + 2;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1] + 20;
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] - 2;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
g_Camera.GoDown();
}
/////////////////////////////////
// Z ray left down, point 1
// Nastav levý dolní paprsek Z, bod 1
// Algoritmus stejný jako s osou X, akorát se kamera vrací v Z ose
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] - 10;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1] - 15;
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] - i_dist;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
if(g_bCameraStrafeLeft || g_bCameraStrafeRight)
{
g_Camera.m_pfCurrPosition[2] += g_Camera.m_fSpeed * 2;
}
else
{
g_Camera.m_pfCurrPosition[2] += g_Camera.m_fSpeed;
}
}
// Z ray left down, point 2
// Nastav levý dolní paprsek Z, bod 2
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] - 10;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1] - 15;
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] + i_dist;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
if(g_bCameraStrafeLeft || g_bCameraStrafeRight)
{
g_Camera.m_pfCurrPosition[2] -= g_Camera.m_fSpeed * 2;
}
else
{
g_Camera.m_pfCurrPosition[2] -= g_Camera.m_fSpeed;
}
}
// Z ray middle, point 1
// Nastav prostřední paprsek Z, bod 1
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0];
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1];
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] - i_dist;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
if(g_bCameraStrafeLeft || g_bCameraStrafeRight)
{
g_Camera.m_pfCurrPosition[2] += g_Camera.m_fSpeed * 2;
}
else
{
g_Camera.m_pfCurrPosition[2] += g_Camera.m_fSpeed;
}
}
// Z ray middle, point 2
// Nastav prostřední paprsek Z, bod 2
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0];
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1];
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] + i_dist;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
if(g_bCameraStrafeLeft || g_bCameraStrafeRight)
{
g_Camera.m_pfCurrPosition[2] -= g_Camera.m_fSpeed * 2;
}
else
{
g_Camera.m_pfCurrPosition[2] -= g_Camera.m_fSpeed;
}
}
// Z ray right up, point 1
// Nastav pravý horní paprsek Z, bod 1
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] + 10;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1] + 15;
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] - i_dist;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
if(g_bCameraStrafeLeft || g_bCameraStrafeRight)
{
g_Camera.m_pfCurrPosition[2] += g_Camera.m_fSpeed * 2;
}
else
{
g_Camera.m_pfCurrPosition[2] += g_Camera.m_fSpeed;
}
}
// Z ray right up, point 2
// Nastav pravý horní paprsek Z, bod 2
pf_ray_point[0] = g_Camera.m_pfCurrPosition[0] + 10;
pf_ray_point[1] = g_Camera.m_pfCurrPosition[1] + 15;
pf_ray_point[2] = g_Camera.m_pfCurrPosition[2] + i_dist;
if(g_bViewCameraCollisionPoints)
{
glPushMatrix();
glPointSize(100.0f);
glBegin( GL_POINTS );
glVertex3fv( pf_ray_point );
glEnd();
glPopMatrix();
}
i_ray_leaf_index = FindLeaf(pf_ray_point, 0);
if(CheckBrushCollision(i_ray_leaf_index))
{
if(g_bCameraStrafeLeft || g_bCameraStrafeRight)
{
g_Camera.m_pfCurrPosition[2] -= g_Camera.m_fSpeed * 2;
}
else
{
g_Camera.m_pfCurrPosition[2] -= g_Camera.m_fSpeed;
}
}
}
|
Pro každý bod se volá funkce CheckBrushCollision(i_ray_leaf_index)
která zjistí, zda došlo ke kolizi bodu s BSP listem, který obsahuje brush informace.
|
|
// Zjisti potřebné informace pro kolize kamery se stěnama scény
inline bool K_CQuake3Bsp::CheckBrushCollision(int i_leaf_index)
{
// Pokud se detekuje kolize s těmito listy, tak vrať funkci false
if((i_leaf_index == 440) || (i_leaf_index == 1609) || (i_leaf_index == 255) || (i_leaf_index == 197)
|| (i_leaf_index == 1395) || (i_leaf_index == 1474) || (i_leaf_index == 1035) )
{
return false;
}
// Jinak
TBspLeaf *pt_bsp_leaf = &(m_ptBspLeaf[i_leaf_index]); // Získej hodnoty aktuálního listu
int i_num_leaf_brushes = pt_bsp_leaf->i_num_of_leaf_brushes; // Získej počet kolizí
// Jestliže list obsahuje kolize
if(i_num_leaf_brushes)
{
// Jestliže je povoleno vykreslování detekční obálky kolizního listu ve které je kamera, tak
if (g_bRenderBoundingBoxCameraLeafColl)
{
// Vykresli obálky
RenderBoundingBox(m_ptBspLeaf[i_leaf_index].pi_min_box, m_ptBspLeaf[i_leaf_index].pi_max_box);
}
return true;
}
else // Pokud nedochází k detekci kolize
{
return false;
}
}
|
Toť vše. Příště zkusíme načíst QuakeIII animované postavy MD3 a potom se
vrhneme na AI těchto postav.
|
|
Home