2016-06-28 4 views
0

私たちは現在、OpenGLを搭載したシンプルな3Dエンジンに取り組んでおり、ほとんどのものが最終的な大学のプレゼンテーションの準備が整いました。私は通常、MSVC2015 x64コンパイラで動作し、すべて正常に動作し、ビルド速度は高速かつ実行可能なパフォーマンスです。 しかし、最新の変更以来、物理スレッドはMinGW 4.9.2 x86では非常に遅く、デルタのようないくつかの変数は、スレッドが動作していても奇妙に0です。Qt MinGW QThreadパフォーマンスが悪い

私はMSVCに戻っても、それは魅力的に機能します。説明するのは難しいので、お詫び申し上げます。良く分かりやすさのため

相続人GIF:http://imgur.com/Isgqkcz

あなたが見ることができるように、球が信じられないほど途切れ途切れに動いています。 MSVCでは完全に滑らかに動き、デルタは通常0.007831msです。 MinGWデルタでは0ms、場合によってはわずか5msのような極端に高い場合があります。それが何を引き起こすのか全く分かりません。私はコンパイラが何かを最適化すると思う?私は見当がつかない...

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; 
} 

答えて

0

QThreadかmingwのいずれかが、あなたが問題を誤診していると間違って何もありません。 QThreadは、ネイティブスレッドに対する非常に単純なハンドルであることに注意してください。あなたが見ているものとは何の関係もありませんでした。

あなたのタイムステップロジックに根本的な欠陥があります。あなたはstartTimeendTimeが異なると仮定しています。 これを証明するテストケースを作成したばかりです。使用しているクロックのAPIには何もありません。これは、2回呼び出すと結果が異なることを保証します。

物理エンジンは、一定の時間ステップと、毎回のステップに追加する内部時間で動作する必要があります。シミュレーションを開始するときは、エンジンの時間をシステム時間に設定します。その後、リアルタイムで遅れている限り、エンジンのステップを計算し続けます。それが追いついたら、ディスプレイのアップデートを実行します。そして繰り返してください。

+0

Glenn Fiedlersの記事「Free the Physics」を参照してください。 実際には私のデルタが0になった原因を見つけました。ostd :: chrono :: high_resolution_clockはsystem_clockの同義語にすることができます。 これはMinGWコンパイラの場合のようで、デルタが変更されないように精度が低下しました。とにかく、チップのおかげで、私は物理学の記事をチェックし、物理学のコードをリファクタリングします! –

+0

@KevinKuegler再び、この問題はありません。クロック値を取得するための2つの呼び出しが異なるという仮定は、基本的には間違っています**。さらに悪いことに、これは単調な時計である必要はないので、あなたの時計は逆方向に行くことができます - 通常はコンテキストスイッチです。 –

+0

@KevinKueglerさらに、何らかの理由でタスクが遅れてしまうと、非常に長い時間デルタが発生し、シミュレーションステップの結果が役に立たなくなる可能性があります。私は誰の記事にも言及していません、私はあなたの実装が非常に基本的なレベルで壊れているという事実を指しています。それと戦わないでください。ちゃんとして。はるかに簡単になるでしょう。 –

関連する問題