2016-06-28 8 views
0

Wir arbeiten gerade an einer einfachen 3D-Engine mit OpenGL und fast alles ist bereit für unsere Abschlusspräsentation. Ich arbeite normalerweise mit MSVC2015 x64 Compiler und alles funktioniert gut, Build-Geschwindigkeit ist schnell und ausführbare Leistung zu. Jedoch seit den letzten Änderungen, die wir gemacht haben, ist der Physik-Thread auf MinGW 4.9.2 x86 extrem langsam und einige Variablen wie Delta sind seltsamerweise 0, obwohl der Thread funktioniert.Qt MinGW QThread Leistung schlecht

Wenn ich zurück zu MSVC, funktioniert es wie ein Charme Es ist schwer zu beschreiben, also entschuldige ich mich.

Heres ein GIF für eine bessere Verständlichkeit: http://imgur.com/Isgqkcz

Wie Sie sehen können, bewegen sich die Kugeln unglaublich abgehackt. Auf MSVC bewegen sie sich perfekt glatt und Delta ist normalerweise 0.007831ms. Auf MinGW Delta ist 0ms und manchmal, nur manchmal seine extrem hoch wie ~ 5ms. Wir haben absolut keine Ahnung, was es verursacht. Ich vermute, der Compiler optimiert etwas? Ich habe keine Ahnung ...

void PhysicsThread::run(){ 
    qDebug() << "SUCCESSFULLY STARTED UP PHYSICS-SIMULATION"; 
    forever{ 
     mutex.lock(); 
     qDebug() << "RUNNING PHYSICS-SIMULATION"; 
     runSimulation(); 
     if(stop){ 
      mutex.unlock(); 
      break; 
     } 
     if(bPause){ 
      pauseManager.wait(&mutex); 
     } 
     mutex.unlock(); 
    } 
} 

void PhysicsThread::runSimulation(){ 
    auto startTime = std::chrono::high_resolution_clock::now(); 

    // Collision Border 
    for(int i = 0 ; i < pobjectsSphere.size() ; i++) { 

     PhysicsSphere* op = pobjectsSphere.at(i); 
     if(op->getIsMovable()){ 
      if(op->getX()-(op->getSize()) < minx){ 
       if(op->getVelocityX() < 0){ 
        op->setVelocityX(-op->getVelocityX()); 
       }else{ 
        op->setVelocityX(op->getVelocityX()); 
       } 
      }else if(op->getX()+(op->getSize()) > maxx) { 
       if(op->getVelocityX() > 0){ 
        op->setVelocityX(-op->getVelocityX()); 
       }else{ 
        op->setVelocityX(op->getVelocityX()); 
       } 
      } 

      if(op->getY()-(op->getSize()) < miny){ 
       if(op->getVelocityY() < 0){ 
        op->setVelocityY(-op->getVelocityY() * op->getRemainingEnergy()); 
       }else{ 
        op->setVelocityY(op->getVelocityY()); 
       } 
      }else{ 
       if(op->getY()+(op->getSize()) > maxy){ 
        if(op->getVelocityY() > 0){ 
         op->setVelocityY(-op->getVelocityY()); 
        }else{ 
         op->setVelocityY(op->getVelocityY()); 
        } 
       } 

       // Gravity 
       op->setVelocityY(op->getVelocityY() + g*deltaTimeMS*op->getMass()); 
      } 

      if(op->getZ()-(op->getSize()) < minz){ 
       if(op->getVelocityZ() < 0){ 
        op->setVelocityZ(-op->getVelocityZ()); 
       }else{ 
        op->setVelocityZ(op->getVelocityZ()); 
       } 
      }else if(op->getZ()+(op->getSize()) > maxz){ 
       if(op->getVelocityZ() > 0){ 
        op->setVelocityZ(-op->getVelocityZ()); 
       }else{ 
        op->setVelocityZ(op->getVelocityZ()); 
       } 
      } 
     } 
    } 

    // Collision Sphere on Sphere 
    for(int i = 0 ; i < pobjectsSphere.size() ; i++) { 
     PhysicsSphere* op1 = pobjectsSphere.at(i); 
     for(int j = i ; j < pobjectsSphere.size() ; j++) { 
      PhysicsSphere* op2 = pobjectsSphere.at(j); 

      // Sphere on Sphere 
      if(i != j && Collision::SphereVersusSphere(op1->getX() ,op1->getY() ,op1->getZ() ,op1->getSize() ,op2->getX() ,op2->getY() ,op2->getZ() ,op2->getSize())){ 

       double tempX (op1->getX() - op2->getX()); 
       double tempY (op1->getY() - op2->getY()); 
       double tempZ (op1->getZ() - op2->getZ()); 

       double norm = sqrt(tempX*tempX + tempY*tempY + tempZ*tempZ); 

       tempX = tempX/norm; 
       tempY = tempY/norm; 
       tempZ = tempZ/norm; 

       double a1 = (op1->getVelocityX() * tempX) + (op1->getVelocityY() * tempY) + (op1->getVelocityZ() * tempZ); 
       double a2 = (op2->getVelocityX() * tempX) + (op2->getVelocityY() * tempY) + (op2->getVelocityZ() * tempZ); 

       double optimizedP = (2.0 * (a1 - a2))/(op1->getMass() + op2->getMass()); 

       // fix 
       optimizedP = std::abs(optimizedP); 

       // 0.9 Verlusst 
       if(op1->getIsMovable()){ 
        op1->setVelocityX(op1->getVelocityX() + (optimizedP * op2->getMass() * tempX) * (op1->getRemainingEnergy()*op2->getRemainingEnergy())); 
        op1->setVelocityY(op1->getVelocityY() + (optimizedP * op2->getMass() * tempY) * (op1->getRemainingEnergy()*op2->getRemainingEnergy())); 
        op1->setVelocityZ(op1->getVelocityZ() + (optimizedP * op2->getMass() * tempZ) * (op1->getRemainingEnergy()*op2->getRemainingEnergy())); 
       } 

       if(op2->getIsMovable()){ 
        op2->setVelocityX(op2->getVelocityX() - (optimizedP * op1->getMass() * tempX) * (op1->getRemainingEnergy()*op2->getRemainingEnergy())); 
        op2->setVelocityY(op2->getVelocityY() - (optimizedP * op1->getMass() * tempY) * (op1->getRemainingEnergy()*op2->getRemainingEnergy())); 
        op2->setVelocityZ(op2->getVelocityZ() - (optimizedP * op1->getMass() * tempZ) * (op1->getRemainingEnergy()*op2->getRemainingEnergy())); 
       } 

       if(!op1->getIsMovable() && op2->getIsMovable()){ 
        op2->setX(op2->getX() - op1->getVelocityX() * deltaTimeMS); 
        op2->setY(op2->getY() - op1->getVelocityY() * deltaTimeMS); 
        op2->setZ(op2->getZ() - op1->getVelocityZ() * deltaTimeMS); 

        op1->setVelocityX(0.0); 
        op1->setVelocityY(0.0); 
        op1->setVelocityZ(0.0); 

       }else if(op1->getIsMovable() && !op2->getIsMovable()){ 
        op1->setX(op1->getX() - op2->getVelocityX() * deltaTimeMS); 
        op1->setY(op1->getY() - op2->getVelocityY() * deltaTimeMS); 
        op1->setZ(op1->getZ() - op2->getVelocityZ() * deltaTimeMS); 

        op2->setVelocityX(0.0); 
        op2->setVelocityY(0.0); 
        op2->setVelocityZ(0.0); 
       } 


       op1->setX(op1->getX() + op1->getVelocityX() * deltaTimeMS); 
       op1->setY(op1->getY() + op1->getVelocityY() * deltaTimeMS); 
       op1->setZ(op1->getZ() + op1->getVelocityZ() * deltaTimeMS); 

       op2->setX(op2->getX() + op2->getVelocityX() * deltaTimeMS); 
       op2->setY(op2->getY() + op2->getVelocityY() * deltaTimeMS); 
       op2->setZ(op2->getZ() + op2->getVelocityZ() * deltaTimeMS); 
      } 
     } 
    } 

    for(int i = 0 ; i < pobjectsSphere.size() ; i++) { 
     PhysicsSphere* op1 = pobjectsSphere.at(i); 
     for(int j = 0 ; j < pobjectsBox.size() ; j++) { 
      PhysicsBox* op2 = pobjectsBox.at(j); 



      if(Collision::SphereVersusBox(op1->getX() ,op1->getY() ,op1->getZ() ,op1->getSize() ,op2->getMinX()+op2->getX() ,op2->getMinY()+op2->getY() ,op2->getMinZ()+op2->getZ() ,op2->getMaxX()+op2->getX() ,op2->getMaxY()+op2->getY() ,op2->getMaxZ()+op2->getZ())){ 

       if((op1->getX()+op1->getSize()) > op2->getMinX() && op1->getX() < op2->getMinX()+op2->getX()){ 

        if(op1->getVelocityX() > 0){ 
         op1->setVelocityX(-op1->getVelocityX()); 
        } 
       } 
       if((op1->getX()-op1->getSize()) < op2->getMaxX() && op1->getX() > op2->getMaxX()+op2->getX()){ 
        if(op1->getVelocityX() < 0){ 
         op1->setVelocityX(-op1->getVelocityX()); 
        } 
       } 

       if((op1->getY()+op1->getSize()) > op2->getMinY() && op1->getY() < op2->getMinY()+op2->getY()){ 
        if(op1->getVelocityY() > 0){ 
         op1->setVelocityY(-op1->getVelocityY()); 
        } 
       } 
       if((op1->getY()-op1->getSize()) < op2->getMaxY() && op1->getY() > op2->getMaxY()+op2->getY()){ 

        if(op1->getVelocityY() < 0){ 
         op1->setVelocityY(-op1->getVelocityY()); 
        } 
       } 

       if((op1->getZ()+op1->getSize()) > op2->getMinZ() && op1->getZ() < op2->getMinZ()+op2->getZ()){ 
        if(op1->getVelocityZ() > 0){ 
         op1->setVelocityZ(-op1->getVelocityZ()); 
        } 
       } 
       if((op1->getZ()-op1->getSize()) < op2->getMaxZ() && op1->getZ() > op2->getMaxZ()+op2->getZ()){ 
        if(op1->getVelocityZ() < 0){ 
         op1->setVelocityZ(-op1->getVelocityZ()); 
        } 
       } 
      } 
     } 
    } 

    // Move 
    for(int i = 0 ; i < pobjectsSphere.size() ; i++) { 
     PhysicsSphere* op = pobjectsSphere.at(i); 
     if(op->getIsMovable()){ 
      op->setX(op->getX() + op->getVelocityX()*deltaTimeMS); 
      op->setY(op->getY() + op->getVelocityY()*deltaTimeMS); 
      op->setZ(op->getZ() + op->getVelocityZ()*deltaTimeMS); 
     }else{ 
      op->setVelocityX(0.0); 
      op->setVelocityY(0.0); 
      op->setVelocityZ(0.0); 
     } 

    } 
    if(pauseTickTime > 0.0){ 
     this->msleep(pauseTickTime); 
    } 
    auto endTime = std::chrono::high_resolution_clock::now(); 
    std::chrono::duration<double> time = endTime - startTime; 
    deltaTimeNS = std::chrono::duration_cast<std::chrono::nanoseconds>(time).count(); 
    deltaTimeMS = deltaTimeNS/1000000.0; 
    //qDebug() << "DeltaT NS: " << deltaTimeNS << " DeltaT MS: " << deltaTimeMS; 
} 

Antwort

0

Es ist nichts falsch mit entweder QThread oder mingw, sind Sie das Problem misdiagnosing. Denken Sie daran, dass QThread ein sehr einfaches Handle für einen nativen Thread ist. Es hatte nichts damit zu tun, was du siehst.

Ihre Zeitschrittlogik ist grundlegend fehlerhaft. Sie gehen davon aus, dass sich startTime und endTime unterscheiden. Sie müssen nicht - Sie haben gerade einen Testfall für sich selbst gemacht, der dies demonstriert. Es gibt nichts in der API der Uhr, die Sie verwenden, die garantiert, dass Sie Ergebnisse erhalten, die sich unterscheiden, wenn Sie es zweimal aufrufen.

Ihre Physik-Engine sollte mit einem konstanten Zeitschritt und einer internen Zeit arbeiten, die Sie bei jedem Zeitschritt hinzufügen. Wenn Sie die Simulation starten, stellen Sie die Motorzeit auf Systemzeit ein. Dann berechnen Sie die Schritte im Motor so lange, wie sie hinter der Echtzeit zurückbleiben. Sobald dies der Fall ist, führen Sie eine Aktualisierung der Anzeige durch. Und wiederholen.

+0

Ich nehme an, Sie beziehen sich auf Glenn Fiedlers Artikel "Free the Physics"? Eigentlich habe ich den Schuldigen dafür verantwortlich gemacht, dass mein Delta 0 war. Ostd :: chrono :: high_resolution_clock kann ein Synonym für system_clock sein. Dies scheint der Fall mit dem MinGW-Compiler zu sein, daher war die Genauigkeit viel niedriger, was dazu führte, dass sich das Delta nicht änderte. Wie auch immer, danke für den Tipp, ich werde den Physikartikel überprüfen und den Physikcode umgestalten! –

+0

@KevinKuegler Auch hier zählt nichts. Ihre Annahme, dass zwei Aufrufe zum Erhalt des Uhrzeitwerts unterschiedlich sind, ist grundsätzlich falsch **. Schlimmer noch, das muss nicht einmal eine monotone Uhr sein, also kann Ihre Uhr rückwärts gehen - normalerweise auf Kontextwechsel. –

+0

@KevinKuegler Wenn Ihre Aufgabe aus irgendeinem Grund verzögert wird, erhalten Sie möglicherweise Zeitdeltas, die sehr lang sind und das Ergebnis des Simulationsschritts nutzlos machen. Ich beziehe mich nicht auf irgendjemandes Artikel, ich beziehe mich nur auf die Tatsache, dass Ihre Implementierung auf einem sehr grundlegenden Niveau gebrochen wird. Bekämpfe es nicht. Mach es richtig. Es wird viel einfacher sein. –