Thank you for the answers.
I will now post some (a lot;-)) code fragments which are important for collision detection.
I will begin with the important structures:
Code: Select all
The Bounding-Box. Each node have one.
//###################### Bounding-Box ########################
typedef struct BBOX{
VECT vMin; //---Maximaler Eckpunkt
VECT vMax; //---Minimaler Eeckpunkt
VECT vMitte; //---Mitte der Bounding Box
}boundBox;
used for normal determination/calculation.
//######################## plane #####################
typedef struct PLANE{
VECT atPlane; //---Punkt auf Ebene;
VECT normale;
float distanz;
}pPlane;
What the player/camera can see. Each leaf contain a polygon-list.
//#### polygon structure ####
typedef struct POLYGON{
int id;
int anzVertexe; //---anzahl der Punkte
int prim_count; //---primitive count
D3DLVERTEX punkte[4];
PLANE ebene; //--- teilungsebene
BOOL splitter; //--- war splitter??
int anzIndexe;
WORD indexListe[100];
char* textr_name;
}pPolygon;
//######### BSP node structure ##########
typedef struct TREENODE{
int id; //---id dieses Nodes
PLANE ebene; //--- ebene welche die nodes in front&back spaltet
BOOL isLeaf; //--- Ist der raum konvex? dann ein Leaf!
TREENODE *front_node; //---zeiger auf den Frontzweig
TREENODE *back_node; //---zeiger auf den Heck-zweig
int anzPolygone; //--- anz. der Polygone wenn node ein leaf
POLYGON *poly; //---zeiger auf diePolygonliste wwenn node ein Leaf
BBOX bdBox; //--- Bounding Box
}tNode;
Next the BSP-Building-Function, because BSP-Collision-Detection is used, the comments are in german:
Code: Select all
void Build_Tree(TREENODE *currNode){
int polyClass;
TREENODE *back = NULL,*front = NULL;
BOOL currentPlane;
//---calculate bbox for this node
/*currNode->bdBox = this->createBBox(currNode->poly,currNode->anzPolygone);*/
//---get the best splitting-plane
currentPlane = GetPlane(currNode->poly,
currNode->anzPolygone,
&currNode->ebene);
if(!currentPlane){
/*
--- CreateSolidLeaf() ---
So.. hier ist nun ein konvexer Bereich,dh.Leaf
Hier werden die Polygone weiter in Front/Backliste unterteilt
bis alle Polygone(auch normale Splitter) Splitter/Teilungsebenen
waren!
*/
/*currNode->isLeaf=TRUE;
currNode->back_node = NULL;
currNode->front_node = NULL;*/
CreateSolidLeaf(currNode);
/*FILE *tt;
tt = fopen("debug1.txt","a");
fprintf(tt,"Klassifizierung gegen Ebene übersprungen! Irgendwas stimmt nicht\n");
fclose(tt);*/
return;
}
//---Nodes aus Node-Array reservieren
front = &tNodePool[tNodePoolIndex++];
back = &tNodePool[tNodePoolIndex++];
//---Polygonzähler für aktuelle Knoten auf NULL setzen
front -> anzPolygone = 0;
back -> anzPolygone = 0;
//---speicher für diese Polygonlisten reservieren
front->poly = (POLYGON*)malloc(sizeof(POLYGON)*currNode->anzPolygone);
back->poly = (POLYGON*)malloc(sizeof(POLYGON)*currNode->anzPolygone);
for(int x=0; x < currNode->anzPolygone; x++){
//---Polygon gegen ebene Klassifizieren
polyClass = KlassifizierePoly(currNode->ebene,
&currNode->poly[x]);
/*FILE *fp;
fp = fopen("debug.txt","w");
fprintf(fp,"sortiere Polygon NO[%i]....\n"
"Klassifizierungs ergebnis: %i\n",
x,polyClass);
fclose(fp);*/
if(polyClass == POLY_FRONT){
//---Polygon in Frontliste einteilen
front ->poly[front->anzPolygone] = currNode->poly[x];
front ->anzPolygone++;
/*this-> anz_front++;*/
}
else if(polyClass == POLY_BACK){
//---Polygon in Backliste einteilen
back ->poly[back->anzPolygone] = currNode->poly[x];
back ->anzPolygone++;
/*this->anz_back++;*/
}
else if(polyClass == POLY_SPLIT){
POLYGON polypFront,polypBack;
splitPoly(&currNode->poly[x],&currNode->ebene,
&polypFront,&polypBack);
/*front->poly[front->anzPolygone] = currNode->poly[x];*/
front->poly[front->anzPolygone] = polypFront;
front->anzPolygone++;
/*back->poly[back->anzPolygone] = currNode->poly[x];*/
back->poly[back->anzPolygone] = polypBack;
back->anzPolygone++;
/*this->anz_split++;*/
}
else if(polyClass == POLY_PLANAR){
//---Poly-Normal-Vektor gleiche richtung wie Teilungsebene??
//--- "" "" same direction as splitting-plane
float dotProduct;
dotProduct = currNode->poly[x].ebene.normale.x *
currNode->ebene.normale.x +
currNode->poly[x].ebene.normale.y *
currNode->ebene.normale.y +
currNode->poly[x].ebene.normale.z *
currNode->ebene.normale.z;
//---in Front oder Backliste einsortieren
if(dotProduct >= 0){
//---Frontliste
front->poly[front->anzPolygone] = currNode->poly[x];
front->anzPolygone++;
}else{
back->poly[back->anzPolygone] = currNode->poly[x];
back->anzPolygone++;
}//---else
/*this->anz_planar++;*/
}//--if(PLANAR)
}//---for(alle Polygone im Node durchlaufen und einsortieren);
//---Speicher jetzt genau anpassen
front->poly = (POLYGON*)realloc(front->poly,sizeof(POLYGON)*front->anzPolygone);
back->poly = (POLYGON*)realloc(back->poly,sizeof(POLYGON)*back->anzPolygone);
//---aktuelle Listen setzen
currNode -> back_node = back;
currNode -> front_node = front;
//---alte listen löschen
free(currNode->poly);
currNode->poly = NULL;
Build_Tree(currNode->front_node);
Build_Tree(currNode->back_node);
return;
}
Next i listed the LineOfSight()- function which, return incorrect plane-intersection-values,
when i try to calculate the intersection point. The intersection point i need for my player-heigt-adjustion.
Code: Select all
//###################### LineOfSight() ########################
BOOL LineOfSight(TREENODE *bspRoot,
D3DXVECTOR3 st_point,
D3DXVECTOR3 end_point,
PLANE *plane,TREENODE *currNode){
D3DXVECTOR3 schnittPunkt;
TREENODE *tempNode;
float tempVal;
int class_pos_1,class_pos_2;
/*currNode->ebene.atPlane.x = 5;
currNode->ebene.atPlane.y = 5;
currNode->ebene.atPlane.z = 2;*/
//---Wurzel-Node festlegen; falls akt. Node undefiniert
//---set root-node; if actual node undefinied
if(currNode == NULL) {
tempNode = bspRoot;
}
else {
tempNode = currNode;//--ansonsten rekursiver Aufruf
}
//---Punkte der Linie klassifizieren
//---classify points of the line
class_pos_1 = KlassifizierePunkt(tempNode->ebene,st_point);
class_pos_2 = KlassifizierePunkt(tempNode->ebene,end_point);
/*FILE *fp;
fp = fopen("section.txt","a");
fprintf(fp,"\nstartpunkt: %i\nendpunkt: %i\n",class_pos_1,class_pos_2);
fclose(fp);*/
//---LINIE: Startpunkt->Front && Endpunkt->Back
if((class_pos_1 == POLY_FRONT) && (class_pos_2 == POLY_BACK)){
//---Teil der Sichtlinie im Solidbereich?
if(tempNode->back_node ==NULL){
if(plane != NULL) *plane = tempNode->ebene;
return FALSE;
}//---if
//---schnittpunkt der Linie zur ebene berechnen
//---calculate the intersectionpoint between line and plane
/*
Ersetzt das Liniensegment durch 2 Liniensegmente:
Segment1: Start = st_point && Ende = schnittpunkt
Segment2: Start = schnittpunkt && Ende = end_point
*/
interSectionPoint(&st_point,&end_point,&tempNode->ebene.atPlane,
&tempNode->ebene.normale,&schnittPunkt,&tempVal);
//---testet Liniensegmente ob diese durch solide Räume laufen
//---test the line-segments if there "walked" through solid-space
return(LineOfSight(NULL,st_point,schnittPunkt,plane,tempNode->front_node)
&&
LineOfSight(NULL,schnittPunkt,end_point,plane,tempNode->back_node) );
}//---if(LINIE:Startpunkt->Front && Endpunkt->Back)
//---LINIE: Startpunkt -> Back && Endpunkt -> Front
if( (class_pos_1 == POLY_BACK) && (class_pos_2 == POLY_FRONT) ){
if(tempNode->back_node == NULL){
if(plane !=NULL) *plane = tempNode->ebene;
return FALSE;
}//---if
//---Schnittpunkt der Linie zur Ebene berechnen
//---calculate the intersectionpoint between line and plane
/*
Ersetzt das Liniensegment durch 2 Liniensegmente:
Segment1: Start = st_point && Ende = schnittpunkt
Segment2: Start = schnittpunkt && Ende = end_point
*/
interSectionPoint(&st_point,&end_point,&tempNode->ebene.atPlane,
&tempNode->ebene.normale,&schnittPunkt,&tempVal);
//--- Beide Liniensegmente GETRENNT darauf prüfen ob sie durch
//--- soliden Raum laufen, und das Ergebnis mit && verknupfen
//--- A = SEG1=0 && SEG2 = 1 deutet darauf hin das sich im
//--- 1. Liniensegment solider Raum befindet, dh. Sichlinie unterbrochen!!
/*
test both line-segments seperate if there walked through solid space
and concat the result with &&
A = SEG1=0 && SEG2 = 1 ; mean that line-segment SEG1 contain solid space,
the line of sight is "braked"
*/
return(LineOfSight(NULL,st_point,schnittPunkt,plane,tempNode->back_node)
&&
LineOfSight(NULL,schnittPunkt,end_point,plane,tempNode->front_node) );
}//---if(LINIE: Start -> Back && Ende -> Front)
if( ((class_pos_1 == POLY_PLANAR) && (class_pos_2 == POLY_PLANAR)) ||
((class_pos_1 == POLY_FRONT) || (class_pos_2 == POLY_FRONT)) ){
//---Sichlinie prüfen falls node kein Leaf ist
if(tempNode->isLeaf == FALSE){
return LineOfSight(NULL,st_point,end_point,plane,tempNode->front_node);
}else{
return TRUE; //---Sichtlinie ist gültig,wenn Node ein Leaf!!
}
}else{
//---Falls Backnode NULL(Raum ist SOLIDE!!) Sichtline ungültig!
if(tempNode->back_node == NULL){
if(plane !=NULL) *plane = tempNode->ebene;
return FALSE;
}else{
//---Falls Backnode existiert prüfe dort auf gültige Sichtlinie
//--if backnode exists test there for an proper lineofsight.
return LineOfSight(NULL,st_point,end_point,plane,tempNode->back_node);
}//---else
}//---else
}//---function
The next function is the camera-function and is used for movement BSP-collision detection.
The main Problem that i have, is that the player height must be automatically adjustet at ground.
The m_camPos is an D3DXVECTOR and a member in the D_DXScene-Class.
The function LineOfSight() is used to check for collision detection.
Code: Select all
void D_DXScene::DMoveCamera(D_IMSG userMessage){
float pi2 = D3DX_PI / 2.0f;
D3DXVECTOR3 vStart;
D3DXVECTOR3 vEnd;
vStart = m_camPos;
if(userMessage.flag == D_KEYBOARD_INPUT){
switch(userMessage.kButton){
//---rotation
case D_ROTLEFT:
m_rotY -= 0.13f;
break;
case D_ROTRIGHT:
m_rotY += 0.13f;
break;
//---moving
case D_MOVEFRONT:
vStart.x += 0.4f * sinf(m_rotY);
vStart.z += 0.4f * cosf(m_rotY);
break;
case D_MOVEBACK:
vStart.x -= 0.4f * sinf(m_rotY);
vStart.z -= 0.4f * cosf(m_rotY);
break;
default:
D3DXMatrixIdentity(&m_matTrans);
}//---switch
}
if(userMessage.flag == D_MOUSE_INPUT){
m_rotY += userMessage.mX*0.005f;
if( (m_rotX < pi2) && (m_rotX > -pi2))
m_rotX += userMessage.mY*0.005f;
/*FILE*fp;
fp=fopen("mouse_move.txt","a");
fprintf(fp,"lx: %i ly: %i",userMessage.mX,userMessage.mY);
fclose(fp);*/
}
if(userMessage.kButton == -1){
D3DXMatrixIdentity(&m_matTrans);
}
//---blickrichtung der kamera berechnen (x,z ebene)
m_LookAt.x = sinf(m_rotY) + m_camPos.x;
m_LookAt.z = cosf(m_rotY) + m_camPos.z;
//---the look height (y direction)
m_LookAt.y = sinf(m_rotX) + m_camPos.y;
D3DXVECTOR3 vecDir;
vecDir.x = vStart.x - m_camPos.x;
vecDir.y = vStart.y - m_camPos.y;
vecDir.z = vStart.z - m_camPos.z;
D3DXVec3Normalize(&vecDir,&vecDir);
vEnd.x = vStart.x + 2.5f * vecDir.x;
vEnd.y = vStart.y + 2.5f * vecDir.y;
vEnd.z = vStart.z + 2.5f * vecDir.z;
//--test for collision
if(LineOfSight(&NODE_ROOT,vStart,vEnd,NULL,NULL) == TRUE){
//create new position and rotation for camera
/*D3DXVECTOR3 camPos (m_camPos.x,m_camPos.y,m_camPos.z);*/
m_camPos = vStart;
}//---if
<-------------
Here im tried to adjust the player-height, with the LineOfSight()-function.
The 4Th param normally return an intersection with an plane, but the reurned result are
not correct!
<---------------
D3DXMatrixLookAtLH(&m_matView,
&m_camPos,
&m_LookAt,
&m_UpVect);
lpD3DDevice_I1 -> SetTransform(D3DTS_VIEW,&m_matView);
}
I tried to test for a intersection with LineOfSight, below the collisin test to adjust the player-height.
I created a startvector/point with the same
coordinates as m_camPos and then a endpoint with the same coordinates as m_camPos except THE Y-Value.
A constant value about -100.0f was added to the endpoint y-value to face the "floor".
I thought the ray must go straight DOWN and intersect the next polygon(a poly-list is contained in the 1st params node)
plane (under the players feet), how i understand the function. And then the returned(4Param) intersection-point is used
to define the actuel player-height(plane-intersection plus an constant value about 1.8f).
I can later post a link to a sample application, witch demonstrates this "hover" problem with my camera.
Thank for your patience
M.f.G Denis Marasovic