Diese Frage hat eine wichtige Frage und eine kleine Frage. Ich glaube, ich habe in beiden Fragen Recht, aber nicht beides.
Für meine Physikschleife verwende ich als erstes eine Gravitationskraft auf mein TotalForce
für ein starres Körperobjekt. Ich überprüfe dann mit meinem TotalForce
und meinem Velocity
auf Kollisionen. Mein TotalForce
wird nach jeder Physikschleife auf (0, 0, 0)
zurückgesetzt, obwohl ich mein velocity
behalten werde.
Ich bin mit der Durchführung einer Kollisionsprüfung zwischen einer beweglichen Kugel und einer statischen Ebene vertraut, wenn nur Geschwindigkeit verwendet wird. Was aber, wenn ich außer velocity
noch andere Kräfte habe, wie zum Beispiel die Gravitation? Ich stelle die anderen Kräfte in TotalForces
(im Moment habe ich nur Schwerkraft). Um dies zu kompensieren, tue ich
Dies kann jedoch problematisch sein für die Art, wie ich dachte, dass es sich um einen ruhenden Kontakt handeln sollte. Ich dachte, ruhender Kontakt wurde von
berechnet %Vor% Wo dist
ist
(Als Referenz bedeutet das offensichtliche denom * dist > 0.0f
, dass sich die Kugel von der Ebene weg bewegt)
Dies kann jedoch niemals wahr sein. Auch wenn es scheinbar "ruhenden Kontakt" gibt. Dies liegt daran, dass meine forces
Berechnung immer mindestens eine y von -9,8 (meine Schwerkraft) hat. Wenn Sie sich in Richtung einer Ebene mit einer Normalen von (0, 1, 0) bewegen, wird ein y von denom
von -9,8 erzeugt.
Meine Frage ist
1) Berechne ich den Ruhekontakt korrekt mit dem, was ich mit meinen ersten zwei Code-Snippets erwähnt habe?
Wenn ja,
2) Wie sollen meine "anderen Kräfte" wie die Schwerkraft genutzt werden? Ist meine Verwendung von TotalForces
falsch?
Als Referenz ist mein Zeitschritt
%Vor%BEARBEITEN
Da es so aussieht, als ob einige vorgeschlagene Änderungen meinen Kollisionscode ändern, erkläre ich hier meine Kollisionszustände
%Vor% Sie sollten if(fabs(dist) < 0.0001f) { /* collided */ }
verwenden, um Gleitkommazahlen zu erhalten. Sie würden sicherlich nicht genau 0.0f bei den meisten Winkeln oder Kontakt erhalten.
Der Wert von dist
wenn negativ, ist in der Tat die tatsächliche Menge, die Sie benötigen, um den Körper zurück auf die Oberfläche des Flugzeugs zu verschieben, falls es durch die ebene Oberfläche geht. sphere.position = sphere.position - plane.Normal * fabs(dist);
Sobald Sie es wieder auf die Oberfläche gebracht haben, können Sie es optional in die entgegengesetzte Richtung um die Ebenennormale zurückspringen lassen; oder einfach im Flugzeug bleiben.
parallel_vec = Vec3.dot(plane.normal, -sphere.velocity);
perpendicular_vec = sphere.velocity - parallel_vec;
bounce_velocity = parallel - perpendicular_vec;
Sie können nicht blind tun totalforce = external_force + velocity
, es sei denn, alles hat Einheitsmasse.
BEARBEITEN :
Vector3 planeToSphere = sphere.point - plane.point;
float dist = Vector3.dot(plane.normal, planeToSphere) - plane.radius;
if(dist < 0)
{
// collided.
}
Ich schlage vor, dass Sie zuerst mehr Mathe studieren, wenn dies der Teil ist, den Sie nicht kennen.
NB: Entschuldigung, die Formatierung ist durcheinander ... Ich kann sie nicht als Codeblock markieren.
BEARBEITEN 2 : Basierend auf meinem Verständnis für Ihren Code, benennen Sie Ihre Variablen entweder schlecht oder wie ich bereits erwähnt habe, müssen Sie Ihre mathematische und physikalische Theorie überarbeiten. Diese Zeile macht nichts nützliches.
float denom = Vec3Dot(&plane->GetNormal(), &forces);
A zu jedem Zeitpunkt kann eine Kraft auf die Kugel in irgendeiner Richtung unabhängig von der Bewegungsrichtung sein. so berechnet der Wert im Wesentlichen die Höhe der Kraft in Richtung der ebenen Fläche, sagt aber nichts darüber aus, ob der Ball das Flugzeug treffen wird. z.B. Schwerkraft ist abwärts, aber ein Ball kann eine Aufwärtsgeschwindigkeit haben und eine Ebene darüber treffen. Sie müssen stattdessen Vec3Dot(plane.normal, velocity)
verwenden.
Alternativ haben Ihnen Mark Phariss und Gerhard Powell bereits die physikalische Gleichung für lineare Kinematik gegeben, mit der Sie zukünftige Positionen, Geschwindigkeit und Zeit des Aufpralls direkt berechnen können.
z.B. s = 0.5 * (u + v) * t;
gibt die Verschiebung nach der zukünftigen Zeit t an. Vergleichen Sie diese Verschiebung mit der Entfernung von der Ebene und Sie erhalten, ob die Kugel die Ebene treffen wird. Also noch einmal, ich schlage vor, Sie lesen auf Ссылка und die einfachen Sachen zuerst dann Ссылка .
Noch eine andere Methode, wenn Sie erwarten oder annehmen, dass keine anderen Kräfte auf die Kugel einwirken, dann führen Sie einen Strahlen / Flugzeug-Kollisionstest durch, um die Zeit t zu finden, in der er auf die Ebene trifft. In diesem Fall lesen Sie Ссылка .
Es wird immer eine Schwerkraft von -9,8y auf die Kugel wirken. Im Fall einer schwebenden Kugel führt dies zu einer Abwärtsbeschleunigung (die Nettokraft ist nicht Null). Im Falle der auf der Ebene ruhenden Kugel führt dies dazu, dass die Ebene eine Normalkraft auf die Kugel ausübt. Wenn das Flugzeug mit der ruhenden Kugel perfekt horizontal wäre, würde diese Normalkraft genau + 9,8 betragen, was die Schwerkraft vollständig aufheben würde. Für eine ruhende Kugel auf einer nicht-horizontalen Ebene ist die Normalkraft 9.8y * cos(angle)
(Winkel liegt zwischen -90 und +90 Grad).
Die Dinge werden komplizierter, wenn eine sich bewegende Kugel auf eine Ebene trifft, da die Normalkraft von der Geschwindigkeit und den Materialeigenschaften der Ebene / Kugel abhängt. Abhängig von den Anforderungen Ihrer Anwendung könnten Sie dies entweder ignorieren oder einige Dinge mit den normalen Kräften ausprobieren und sehen, wie es funktioniert.
Für Ihre spezifischen Fragen:
dist == 0.0f
, dh die Kugel und die Ebene, in Kontakt kommen. Ich gehe davon aus, dass Ihre Kollision berücksichtigt, dass die Kugel sich in einem beliebigen physikalischen Zeitschritt über die Ebene bewegen kann. dist == 0.0f
) suche und wenn wahr, addiere die Normalkraft zur Kugel. Im einfachen Fall einer fallenden Kugel auf eine nahe horizontale Ebene (Winkel zwischen -90 und +90 Grad) wäre es nur sphereTotalForces += Vector3D(0, 9.8 * cos(angle), 0)
. Bearbeiten:
Von hier kann Ihre Gleichung für dist
den Abstand vom Rand der Kugel zur Ebene nicht berechnen korrekt sein, abhängig von den Details Ihres Problems und des Codes (der nicht angegeben ist). Wenn Ihr Flugzeug den Ursprung durchläuft, lautet die richtige Gleichung:
Dies ist das gleiche wie Ihre Gleichung, wenn plane->d == sphereRadius
. Beachten Sie, dass wenn das Flugzeug nicht im Ursprung ist, verwenden Sie:
Die genaue Lösung für dieses Problem beinhaltet einige ziemlich ernsthafte Mathematik. Wenn Sie eine ungefähre Lösung wünschen, empfehlen Sie stark , sie schrittweise zu entwickeln.
1) Stellen Sie sicher, dass Ihre Sim ohne Schwerkraft funktioniert. Der Ball muss durch den Raum reisen und unelastische (oder teilweise elastische) Kollisionen mit gewinkelten, reibungsfreien Oberflächen haben.
2) Einführung der Schwerkraft. Dies wird ballistische Trajektorien von geraden Linien in Parabel ändern und gleiten einführen, aber es wird nicht viel Einfluss auf Kollisionen haben.
3) Führen Sie statische und kinetische Reibung (unabhängig) ein. Dies wird die Dynamik des Gleitens verändern. Mach dir keine Sorgen über Reibung in Kollisionen für den Moment.
4) Geben Sie die Kugelgeschwindigkeit und ein Trägheitsmoment an. Das ist ein großer Schritt. Stellen Sie sicher, dass Sie Drehmomente darauf anwenden und realistische Winkelbeschleunigungen erhalten können. Beachten Sie, dass das realistische Verhalten einer sich drehenden Masse kontraintuitiv sein kann.
5) Schiebe den Ball unter der Schwerkraft auf eine ebene Fläche. Wenn Sie alles richtig gemacht haben, wird seine Winkelgeschwindigkeit allmählich zunehmen und seine lineare Geschwindigkeit allmählich abnehmen, bis es in eine Rolle zerbricht. Experimentieren Sie, indem Sie dem Ball einen ersten Spin geben ("draw", "follow" oder "english").
6) Versuchen Sie dasselbe, aber auf einer geneigten Oberfläche. Dies ist ein relativ kleiner Schritt.
Wenn Sie so weit kommen, haben Sie eine ziemlich realistische Sim. Versuchen Sie nicht, einen der Schritte zu überspringen, Sie werden sich nur Kopfschmerzen zufügen.
Antworten auf Ihre Physikprobleme:
%Vor%Wenn Sie eine Kollision haben, ändern Sie die beiden Geschwindigkeiten auf 0 (oder v und u = - (u * 0.7), wenn Sie bouncen wollen).
Da Geschwindigkeit = 0 ist, steht der Ball still.
Wenn es sich um 2D oder 3D handelt, ändern Sie einfach die Geschwindigkeit in Richtung der Normalen der Oberfläche auf 0 und behalten Sie die Parallelgeschwindigkeit bei. Das wird dazu führen, dass der Ball auf der Oberfläche rollt.
Du musst den Ball an die Oberfläche bewegen, wenn er die Oberfläche schneidet. Sie können eine Kollisionsdistanz auf einen kleinen Betrag (zum Beispiel 0,001) setzen, um sicherzustellen, dass sie ruhig bleibt.
Bearbeiten:
NeHe ist eine erstaunliche Quelle für Game Engine Design: Hier ist eine Seite zur Kollisionserkennung mit sehr guten Beschreibungen: Ссылка
Bearbeiten 2: (Von NeHe)
%Vor%Ich schlage danach vor, auch Erin Cato Artikel (der Autor von Box2D) und Glenn Fiedler Artikel zu sehen. Schwerkraft ist eine starke Beschleunigung und führt zu starken Kräften. Fehlerhafte Simulationen sind aufgrund schwebender Ungenauigkeiten, variabler Zeitschritte und Euler-Integration sehr schnell möglich. Die Neupositionierung der Kugel auf der ebenen Fläche ist für den Fall, dass sie sich selbst durch die Ebene zu bohren beginnt, obligatorisch. Ich habe mich selbst bemerkt, dass es besser ist, dies nur zu tun, wenn die Geschwindigkeit der Kugel der Flächennormalen entgegengesetzt ist im 3D-Rendering zu vermeiden: Backfaced-Ebenen nicht berücksichtigen).
auch, die meisten Physik-Engine stoppt die Simulation auf ruhenden Körpern, und die meisten Spiele berücksichtigen nie Schwerkraft während der Bewegung, nur wenn sie fallen. Sie verwenden "Navigationsnetze" und benutzerdefinierte Systeme, solange sie sicher sind, dass das simulierte Objekt an seinem "Boden" klebt.
Ich kenne keinen makellosen Physik-Simulator da draußen, es wird immer eine Integrationsexplosion geben, eine verpasste Kollision (Suche nach "Sweeped Collision") .... es bedarf einer Menge empirischer Feinabstimmung.
Ich schlage auch vor, dass Sie nach "Impulsen" suchen, was eine Methode ist, um zu vermeiden, dass die Geschwindigkeit manuell angefahren wird, wenn eine Kollision auftritt.
Werfen Sie auch einen Blick darauf, "was jeder Informatiker über Fließkomma-Punkte wissen sollte"
viel Glück, Sie betraten ein Minenfeld, zufällig nicht verständlich, Finger beißen Bereich der numerischen Informatik:)
Für höhere Wiedergabetreue (würde Ihr Hauptproblem nicht lösen), würde ich Ihren Zeitschritt auf
ändern %Vor% Du hast erwähnt, dass die Kugel ein starrer Körper war; modellierst du auch das Flugzeug als starr? Wenn ja, hätten Sie eine unendliche Punktkraft im Moment des Kontakts & amp; perfekt elastische Kollision ohne explizite Impulsdissipation.Kraft & amp; Geschwindigkeit kann nicht summiert werden (inkompatible Einheiten); Wenn Sie nur versuchen, die Kinematik zu modellieren, können Sie die Masse ignorieren und mit Beschleunigung & amp; Geschwindigkeit nur.
Wenn man annimmt, dass die Kugel einfach auf eine horizontale Ebene mit einer vollkommen unelastischen Kollision (kein Bounce) fällt, könnte man [N.B., ich weiß nicht wirklich C-Syntax, also wird dies Pythonic sein]
%Vor%Wenn Sie der Kollision etwas Elastizität hinzufügen (etwa halben Schwung erhalten), wäre es eher wie
%Vor%Tags und Links algorithm c++ physics game-physics