Problem mit dem SAT Algorithmus



  • Hallo zusammen, ich habe massive Probleme mit dem SAT Algortithmus. Dieser zeigt immer wieder Kollisionen an, obwohl gar keine existiert!! Was habe ich falsch gemacht?

    // -------------------------------- __handleCollisionDetection --------------------------------
    void KB_TriggerManager::__handleCollisionDetection(void){
     // get the trigger - array in c - style to avoid performance penalities
     KB_Trigger **ppArrTri = reinterpret_cast<KB_Trigger**>(this->lstTri.getAllObjects());
     UINT       numTri     = this->lstTri.getNumberOfObjects();
     KB_Vector3 arrFce[15];
    
     for(UINT i=0;i<numTri;++i){
      for(UINT k=i+1;k<numTri;k++){
       // extract the two triggers
       KB_Trigger *pTri1 = ppArrTri[i];
       KB_Trigger *pTri2 = ppArrTri[k];
       bool       bSep   = false;
    
       // jump to the next loop if both trigger are inactive
       if(!(ppArrTri[i]->isActive() || ppArrTri[k]->isActive())) continue;
    
       // get the bounding boxes of the actual triggers
       KB_BoundingBox *pArrBox[2] = {pTri1->getBoundingBox(),pTri2->getBoundingBox()};
    
       // get the faces
       arrFce[0] = *pArrBox[0]->getFront();
       arrFce[1] = *pArrBox[0]->getRight();
       arrFce[2] = *pArrBox[0]->getUp();
       arrFce[3] = *pArrBox[1]->getFront();
       arrFce[4] = *pArrBox[1]->getRight();
       arrFce[5] = *pArrBox[1]->getUp();
    
       // calculate the cross - products of the face - normals
       D3DXVec3Cross(&arrFce[6],pArrBox[0]->getFront(),pArrBox[1]->getFront());
       D3DXVec3Cross(&arrFce[7],pArrBox[0]->getFront(),pArrBox[1]->getRight());
       D3DXVec3Cross(&arrFce[8],pArrBox[0]->getFront(),pArrBox[1]->getUp());
       D3DXVec3Cross(&arrFce[9],pArrBox[0]->getRight(),pArrBox[1]->getFront());
       D3DXVec3Cross(&arrFce[10],pArrBox[0]->getRight(),pArrBox[1]->getRight());
       D3DXVec3Cross(&arrFce[11],pArrBox[0]->getRight(),pArrBox[1]->getUp());
       D3DXVec3Cross(&arrFce[12],pArrBox[0]->getUp(),pArrBox[1]->getFront());
       D3DXVec3Cross(&arrFce[13],pArrBox[0]->getUp(),pArrBox[1]->getRight());
       D3DXVec3Cross(&arrFce[14],pArrBox[0]->getUp(),pArrBox[1]->getUp());
    
       // start a loop for walking each potential separation - axis
       for(int l=0;l<15;++l){
        // declare and init scope variables
        float arrMin[2] = {0.0f},arrMax[2] = {0.0f};
    
        // start a loop for walking each involved bounding - box
        for(int m=0;m<2;++m){
         // calculate the radius of the projected interval
         float rad  = fabs(D3DXVec3Dot(pArrBox[m]->getRight(),&arrFce[l]))*pArrBox[m]->getSize()->x;
               rad += fabs(D3DXVec3Dot(pArrBox[m]->getUp(),&arrFce[l]))*pArrBox[m]->getSize()->y;
               rad += fabs(D3DXVec3Dot(pArrBox[m]->getFront(),&arrFce[l]))*pArrBox[m]->getSize()->z;
    
         // calculate the minimum and maximum - point
         float cnt = D3DXVec3Dot(pArrBox[m]->getPosition(),&arrFce[l]);
         arrMin[m] = cnt - rad;
         arrMax[m] = cnt + rad;
        }
    
        // check if the projected intervals overlap
        if(arrMin[0] > arrMax[1] || arrMin[1] > arrMax[0]){
         // define that a separation - axis were found and break the loop
         bSep = true;
         break;
        }
       }
    
       // check if no separation - axis could be found
       if(!bSep){
        // call the onTrigger - event for the active window
        this->pWnd->onTrigger(pTri1,pTri2);
    
        // call the onTrigger - event for the assigned components 
        if(pTri1->isComponentAssigned()) pTri1->getComponent()->onTrigger(pTri1,pTri2);
        if(pTri2->isComponentAssigned()) pTri2->getComponent()->onTrigger(pTri1,pTri2);
       }
      }
     }
    }
    // --------------------------------------------------------------------------------------------
    


  • was ist der SAT Algorithmus - hast du da ein Tutorial dazu? oder Buch?
    du weißt doch selber wie das ist wenn dir einer ne Seite Quellcode hinklatscht und du weißt gar nicht wo das Problem liegt - ich werde dir nicht weiterhelfen können, da mich damit nicht auskenne, aber wenn das Problem etwas abstrakter Dargestellt wird kann dir eher geholfen werden



  • Hi,

    also für meine müden Augen sieht das erstmal korrekt aus. Nur eine Frage:

    Box::getSize()

    Gibt das die tatsächliche Größe auf der jeweiligen Achse oder die halbe Größe? Für die Projektion verwendet man nur die halbe Abmesung der Box.

    Ciao,
    Stefan



  • @Stefan Zerbst
    Vielen Dank, das war das Problem, ich habe den Algorithmus noch ein wenig abgeändendert und so erweitert, dass ebenfalls der MTD berechnet wird. Hier ist nocheinmal der vollständige Code mit MTD!
    Kannst du mal überprüfen, ob alles stimmt, besonders die Sache mit dem MTD habe ich komplett improvisiert, da ich keinen Beispielcode gefunden hatte, den ich hätte ableiten können...

    P.S.
    Als nächstes muss ich die Implementation noch dahingehend erweitern, dass jeder Trigger sogenannte Subtriggers haben kann. Sowas wie ein OOB - Tree, aber dass dürfte nun kein Problem mehr sein! 😋 👍

    Grüsse aus der Schweiz

    // -------------------------------- __handleCollisionDetection --------------------------------
    void KB_TriggerManager::__handleCollisionDetection(void){
     // get the trigger - array in c - style to avoid performance penalities
     KB_Trigger **ppArrTri = reinterpret_cast<KB_Trigger**>(this->lstTri.getAllObjects());
     UINT       numTri     = this->lstTri.getNumberOfObjects();
     KB_Vector3 arrVecAxi[15];
    
     // update all triggers
     for(UINT i=0;i<numTri;++i) ppArrTri[i]->update();
    
     // start loops for walking each trigger by each trigger
     for(UINT i=0;i<numTri;++i){
      for(UINT k=i+1;k<numTri;k++){
       // extract the two triggers
       KB_Trigger     *pTri1      = ppArrTri[i];
       KB_Trigger     *pTri2      = ppArrTri[k];
       KB_BoundingBox *pArrBox[2] = {pTri1->getBoundingBox(),pTri2->getBoundingBox()};
       bool           bSep        = false;
       KB_Vector3     vecRay,vecMtd,vecMtdTmp;
    
       // jump to the next loop if both trigger are inactive
       if(!(pTri1->isActive() || pTri2->isActive())) continue;
    
       // get the faces
       arrVecAxi[0] = *pArrBox[0]->getFront();
       arrVecAxi[1] = *pArrBox[0]->getRight();
       arrVecAxi[2] = *pArrBox[0]->getUp();
       arrVecAxi[3] = *pArrBox[1]->getFront();
       arrVecAxi[4] = *pArrBox[1]->getRight();
       arrVecAxi[5] = *pArrBox[1]->getUp();
    
       // calculate the cross - products of the face - normals
       D3DXVec3Cross(&arrVecAxi[6],pArrBox[0]->getFront(),pArrBox[1]->getFront());
       D3DXVec3Cross(&arrVecAxi[7],pArrBox[0]->getFront(),pArrBox[1]->getRight());
       D3DXVec3Cross(&arrVecAxi[8],pArrBox[0]->getFront(),pArrBox[1]->getUp());
       D3DXVec3Cross(&arrVecAxi[9],pArrBox[0]->getRight(),pArrBox[1]->getFront());
       D3DXVec3Cross(&arrVecAxi[10],pArrBox[0]->getRight(),pArrBox[1]->getRight());
       D3DXVec3Cross(&arrVecAxi[11],pArrBox[0]->getRight(),pArrBox[1]->getUp());
       D3DXVec3Cross(&arrVecAxi[12],pArrBox[0]->getUp(),pArrBox[1]->getFront());
       D3DXVec3Cross(&arrVecAxi[13],pArrBox[0]->getUp(),pArrBox[1]->getRight());
       D3DXVec3Cross(&arrVecAxi[14],pArrBox[0]->getUp(),pArrBox[1]->getUp());
    
       // start a loop for walking each potential separation - axis
       for(int l=0;l<15;++l){
        // declare and init scope variables
        float rad = 0.0f;
    
        // jump to the next loop if the separation axis is zero
        if(arrVecAxi[l].x == 0.0f && arrVecAxi[l].y == 0.0f && arrVecAxi[l].z == 0.0f) continue;
    
        // start a loop for walking each involved bounding - box
        for(int m=0;m<2;++m){
         // calculate the radius of the projected interval
         KB_Vector3 *pVecSze = pArrBox[m]->getSize();
         rad += fabs(D3DXVec3Dot(pArrBox[m]->getRight(),&arrVecAxi[l]))*pVecSze->x/2.0f;
         rad += fabs(D3DXVec3Dot(pArrBox[m]->getUp(),&arrVecAxi[l]))*pVecSze->y/2.0f;
         rad += fabs(D3DXVec3Dot(pArrBox[m]->getFront(),&arrVecAxi[l]))*pVecSze->z/2.0f;
        }
    
        // compute the ray from one box - center to the other
        D3DXVec3Subtract(&vecRay,pArrBox[1]->getPosition(),pArrBox[0]->getPosition());
    
        // check if the projected intervals overlap
        if(fabs(D3DXVec3Dot(&vecRay,&arrVecAxi[l])) > rad){
         // define that a separation - axis were found and break the loop
         bSep = true;
         break;
        }
        // otherwise
        else{
         // calculate the mtd of the current separation - axis
         D3DXVec3Scale(&vecMtdTmp,&arrVecAxi[l],rad-fabs(D3DXVec3Dot(&vecRay,&arrVecAxi[l]))+0.1f);    
    
         // check if the current vector is shorter than the actual
         if(!l || (D3DXVec3Length(&vecMtdTmp) < D3DXVec3Length(&vecMtd))){
          // set the temporary MTD to the actual MTD
          vecMtd = vecMtdTmp;
    
          // normalize the ray
          D3DXVec3Normalize(&vecRay,&vecRay);
    
          // check if the opposite face is the shorted distance
          if(acosf(D3DXVec3Dot(&vecRay,&arrVecAxi[l])) > D3DX_PI/2.0f)
           // inverse the mtd - vector by multiplying it by -1
           D3DXVec3Scale(&vecMtd,&vecMtd,-1.0f);
         }
        }
       }
    
       // check if no separation - axis could be found
       if(!bSep){
        // call the onTrigger - event for the active window
        this->pWnd->onTrigger(pTri1,pTri2,&vecMtd);
    
        // call the onTrigger - event for the assigned components 
        if(pTri1->isComponentAssigned()) pTri1->getComponent()->onTrigger(pTri1,pTri2,&vecMtd);
        if(pTri2->isComponentAssigned()) pTri2->getComponent()->onTrigger(pTri1,pTri2,&vecMtd);
       }
      }
     }
    }
    // --------------------------------------------------------------------------------------------
    

    @Vertexwahn
    SAT steht für Separation Axis Theorem und wird verwendet, um eine mögliche Kollision zweier Oriented Bounding Boxes zu berechnen. Der MTD ist die Minimal Translation Distance, welcher ich in Form eines Vektors implementiert habe, den man einfach zum vorhandenen Positionsvektor der zweiten Bounding Box addieren muss, um diese aus der ersten zu entfernen.

    P.S.
    Ich muss mich echt wundern, dass plötzlich alle so still werden, wenn plötzlich eine Frage gestellt wird, welche nichts mit irgendwelchen Rendertricks zu tun haben. Ich meine, wie implementiert ihr den die Kollisionserkennung? Doch hoffentlich nicht mit BoundingSpheres? 😮

    Ich sollte mich vielleicht nicht so weit aus dem Fenster lehnen, denn ich habe selber noch kein einziges eigenes Spiel geschrieben, bin aber kurz davor, mein erstes fertigzustellen... Nach 2 Jahren Entwicklungszeit...
    Aber Ich werde einfach das Gefühl nicht los, dass 99 Prozent der hier Anwesenden noch nie über das Anzeigen und Texturieren von ein paar Meshes + vielleicht noch eine ResourceManager hinausgekommen ist. Anders kann ich mir die Tatsache nicht erklären, dass so gut wie gar niemand diesen Algorithmus kennt...



  • Hi,

    also im Moment habe ich leider zu wenig Zeit mir die MDT Berechnung anzuschauen, aber eine Quelle kann ich Dir geben:

    http://uk.geocities.com/olivier_rebellion/Cube3D.zip

    Da findet sich ein Tutorial was SAT ausgesprochen gut erklärt. Auch die Berechnung der MDT wird dort behandelt. Letztes Mal als ich es ausprobierte war dort allerdings ein Bug weil die Berechnung des Radius bzw. des Überlappungskriteriums nicht ganz korrekt war. Es geht dort auch um bewegte Polyhedra, nicht nur statische.

    Es ist aber nicht richtig, dass SAT nur für Obb vs Obb ist. Es ist generell für alle Volumen anwendbar, allerdings gibt es für einfache Volumen oftmals schnellere Verfahren. Für Obb ist es allerdings wohl die noch schnellste Methode. Aber man kann das Verfahren auch auf generelle Polyhedra anwenden, also auch auf beliebige Tri-Meshes. Da dürfte es allerdings so langsam sein, dass das keinen Sinn macht 🙂

    Ciao,
    Stefan



  • Ishildur schrieb:

    Ich muss mich echt wundern, dass plötzlich alle so still werden, wenn plötzlich eine Frage gestellt wird, welche nichts mit irgendwelchen Rendertricks zu tun haben. Ich meine, wie implementiert ihr den die Kollisionserkennung?

    Welche Kollisionserkennung?!?!? 🤡 👍



  • ???



  • Ishildur schrieb:

    ???

    Das sollte ein Witz sein o_O


Anmelden zum Antworten