diff options
author | Matthew Kosarek <mattkae@protonmail.com> | 2021-07-25 20:20:10 -0400 |
---|---|---|
committer | Matthew Kosarek <mattkae@protonmail.com> | 2021-07-25 20:20:10 -0400 |
commit | 05c4522e5ff424c65aab7cd36c7a15313630ac61 (patch) | |
tree | 4b1f5310029728d46fe3464a500400a2e89fbf13 | |
parent | 26d073d768c1a0560fa4358246acd1e308eff7b6 (diff) |
(mkosarek) Fix for wrong timestep
-rwxr-xr-x | 2d/_collisions/polygon_polygon/dist/output.wasm | bin | 58079 -> 58262 bytes | |||
-rw-r--r-- | 2d/_collisions/polygon_polygon/main.cpp | 2 | ||||
-rw-r--r-- | 2d/rigidbody/rigidbody_1.html | 2 | ||||
-rwxr-xr-x | 2d/rigidbody/rigidbody_1/dist/output.wasm | bin | 48801 -> 49033 bytes | |||
-rw-r--r-- | 2d/rigidbody/rigidbody_1/main.cpp | 7 | ||||
-rw-r--r-- | 2d/rigidbody/rigidbody_1/snippet3.cpp | 2 | ||||
-rwxr-xr-x | 2d/rigidbody/rigidbody_2/dist/output.wasm | bin | 50226 -> 50452 bytes | |||
-rw-r--r-- | 2d/rigidbody/rigidbody_2/main.cpp | 2 | ||||
-rwxr-xr-x | 2d/rigidbody/rigidbody_3/dist/output.wasm | bin | 49458 -> 49653 bytes | |||
-rw-r--r-- | 2d/rigidbody/rigidbody_3/main.cpp | 2 | ||||
-rw-r--r-- | 3d/rigidbody.html | 51 | ||||
-rw-r--r-- | 3d/rigidbody.html.content | 51 | ||||
-rwxr-xr-x | 3d/rigidbody/dist/output.wasm | bin | 43167 -> 48113 bytes | |||
-rw-r--r-- | 3d/rigidbody/main.cpp | 110 | ||||
-rw-r--r-- | resources.html.content | 12 | ||||
-rw-r--r-- | shared_cpp/mathlib.cpp | 28 | ||||
-rw-r--r-- | shared_cpp/mathlib.h | 10 |
17 files changed, 222 insertions, 57 deletions
diff --git a/2d/_collisions/polygon_polygon/dist/output.wasm b/2d/_collisions/polygon_polygon/dist/output.wasm Binary files differindex a047d19..055fbb7 100755 --- a/2d/_collisions/polygon_polygon/dist/output.wasm +++ b/2d/_collisions/polygon_polygon/dist/output.wasm diff --git a/2d/_collisions/polygon_polygon/main.cpp b/2d/_collisions/polygon_polygon/main.cpp index 620edaa..9cb3eb2 100644 --- a/2d/_collisions/polygon_polygon/main.cpp +++ b/2d/_collisions/polygon_polygon/main.cpp @@ -72,7 +72,7 @@ struct Rigidbody { float32 impulseDtSeconds = nextTimeAppliedSeconds - i.timeAppliedSeconds; Vector2 forceToApply = i.force * (impulseDtSeconds / i.timeOfApplicationSeconds); - force += forceToApply * impulseDtSeconds; + force += forceToApply; i.timeAppliedSeconds = nextTimeAppliedSeconds; diff --git a/2d/rigidbody/rigidbody_1.html b/2d/rigidbody/rigidbody_1.html index b98d292..0d50904 100644 --- a/2d/rigidbody/rigidbody_1.html +++ b/2d/rigidbody/rigidbody_1.html @@ -200,7 +200,7 @@ <span class="code_comment">// to calculate the fractional amount of force that was applied in this frame.</span> <span class="code_keyword">float32</span> impulseDtSeconds = nextTimeAppliedSeconds - i.timeAppliedSeconds; <span class="code_keyword">Vector2</span> forceToApply = i.force * (impulseDtSeconds / i.timeOfApplicationSeconds); - force += forceToApply * impulseDtSeconds; + force += forceToApply; i.timeAppliedSeconds = nextTimeAppliedSeconds; } diff --git a/2d/rigidbody/rigidbody_1/dist/output.wasm b/2d/rigidbody/rigidbody_1/dist/output.wasm Binary files differindex f6625a9..b9f4c37 100755 --- a/2d/rigidbody/rigidbody_1/dist/output.wasm +++ b/2d/rigidbody/rigidbody_1/dist/output.wasm diff --git a/2d/rigidbody/rigidbody_1/main.cpp b/2d/rigidbody/rigidbody_1/main.cpp index 88c322c..a327fee 100644 --- a/2d/rigidbody/rigidbody_1/main.cpp +++ b/2d/rigidbody/rigidbody_1/main.cpp @@ -61,8 +61,7 @@ struct Rigidbody { float32 impulseDtSeconds = nextTimeAppliedSeconds - i.timeAppliedSeconds; Vector2 forceToApply = i.force * (impulseDtSeconds / i.timeOfApplicationSeconds); - force += forceToApply * impulseDtSeconds; - + force += forceToApply; i.timeAppliedSeconds = nextTimeAppliedSeconds; } @@ -301,8 +300,8 @@ EM_BOOL onMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void return true; } - pointer.force.x = static_cast<float32>(mouseEvent->movementX) * 100000.f; - pointer.force.y = static_cast<float32>(-mouseEvent->movementY) * 100000.f; + pointer.force.x = static_cast<float32>(mouseEvent->movementX) * 1000.f; + pointer.force.y = static_cast<float32>(-mouseEvent->movementY) * 1000.f; pointer.body.position.x = static_cast<float32>(mouseEvent->targetX); pointer.body.position.y = static_cast<float32>(600.f - mouseEvent->targetY); diff --git a/2d/rigidbody/rigidbody_1/snippet3.cpp b/2d/rigidbody/rigidbody_1/snippet3.cpp index 4727a9a..d3ecc4f 100644 --- a/2d/rigidbody/rigidbody_1/snippet3.cpp +++ b/2d/rigidbody/rigidbody_1/snippet3.cpp @@ -31,7 +31,7 @@ struct Rigidbody { // to calculate the fractional amount of force that was applied in this frame. float32 impulseDtSeconds = nextTimeAppliedSeconds - i.timeAppliedSeconds; Vector2 forceToApply = i.force * (impulseDtSeconds / i.timeOfApplicationSeconds); - force += forceToApply * impulseDtSeconds; + force += forceToApply; i.timeAppliedSeconds = nextTimeAppliedSeconds; } diff --git a/2d/rigidbody/rigidbody_2/dist/output.wasm b/2d/rigidbody/rigidbody_2/dist/output.wasm Binary files differindex 29c319a..fb79e45 100755 --- a/2d/rigidbody/rigidbody_2/dist/output.wasm +++ b/2d/rigidbody/rigidbody_2/dist/output.wasm diff --git a/2d/rigidbody/rigidbody_2/main.cpp b/2d/rigidbody/rigidbody_2/main.cpp index 123cf7e..44a3c53 100644 --- a/2d/rigidbody/rigidbody_2/main.cpp +++ b/2d/rigidbody/rigidbody_2/main.cpp @@ -69,7 +69,7 @@ struct Rigidbody { float32 impulseDtSeconds = nextTimeAppliedSeconds - i.timeAppliedSeconds; Vector2 forceToApply = i.force * (impulseDtSeconds / i.timeOfApplicationSeconds); - force += forceToApply * impulseDtSeconds; + force += forceToApply; // New! Increment the torque for each force torque += i.pointOfApplication.getPerp().dot(forceToApply); diff --git a/2d/rigidbody/rigidbody_3/dist/output.wasm b/2d/rigidbody/rigidbody_3/dist/output.wasm Binary files differindex b89435a..0a8a974 100755 --- a/2d/rigidbody/rigidbody_3/dist/output.wasm +++ b/2d/rigidbody/rigidbody_3/dist/output.wasm diff --git a/2d/rigidbody/rigidbody_3/main.cpp b/2d/rigidbody/rigidbody_3/main.cpp index e34f444..2a0af24 100644 --- a/2d/rigidbody/rigidbody_3/main.cpp +++ b/2d/rigidbody/rigidbody_3/main.cpp @@ -72,7 +72,7 @@ struct Rigidbody { float32 impulseDtSeconds = nextTimeAppliedSeconds - i.timeAppliedSeconds; Vector2 forceToApply = i.force * (impulseDtSeconds / i.timeOfApplicationSeconds); - force += forceToApply * impulseDtSeconds; + force += forceToApply; torque += i.pointOfApplication.getPerp().dot(forceToApply); i.timeAppliedSeconds = nextTimeAppliedSeconds; diff --git a/3d/rigidbody.html b/3d/rigidbody.html index db91bd0..68244de 100644 --- a/3d/rigidbody.html +++ b/3d/rigidbody.html @@ -69,26 +69,37 @@ <article> <h1>Rigidbody in 3D</h1> <section> - <section> - <h2> - Live Example - </h2> - <div class="opengl_canvas_container"> - <canvas id="gl_canvas" width="800" height="600"></canvas> - <button id="gl_canvas_play" class="play_button"> - Play - </button> - <button id="gl_canvas_stop" class="stop_button"> - Stop - </button> - </div> - - <footer id="references"> - <h2>References</h2> - <ul> - </ul> - </footer> - </section> + <section> + <h2>Quaternion Time</h2> + <p> + I hate to start off the article like this. I really do. But it really wouldn't be a discussion of 3D simulation if we didn't jump right into quaternions. Before I start, however, I recommend you take a look at <a href='https://www.3dgep.com/understanding-quaternions'>this article</a>. Quaternions have been written about over and over throughout the years (and I have read many articles about them over and over throughout the years), so I will not waste your time describing every single detail here. The article that I linked to should provide you enough information to begin to understand what quaternions are and why they're important. That being said, I will provide a brief intro to quaternions here, as well as my own C++ implementation of their algebra. (This article is also quite useful: <a href='http://danceswithcode.net/engineeringnotes/quaternions/quaternions.html'>Dance's With Code Website</a>) + <br/><br/> + + </p> + </section> + <section> + <h2> + Live Example + </h2> + <p> + <button id='force_apply'>Click Me</button> + </p> + <div class="opengl_canvas_container"> + <canvas id="gl_canvas" width="800" height="600"></canvas> + <button id="gl_canvas_play" class="play_button"> + Play + </button> + <button id="gl_canvas_stop" class="stop_button"> + Stop + </button> + </div> + + <footer id="references"> + <h2>References</h2> + <ul> + </ul> + </footer> + </section> </article> </main> </body> diff --git a/3d/rigidbody.html.content b/3d/rigidbody.html.content index 8bbf294..5a3eca2 100644 --- a/3d/rigidbody.html.content +++ b/3d/rigidbody.html.content @@ -17,24 +17,35 @@ <article> <h1>Rigidbody in 3D</h1> <section> - <section> - <h2> - Live Example - </h2> - <div class="opengl_canvas_container"> - <canvas id="gl_canvas" width="800" height="600"></canvas> - <button id="gl_canvas_play" class="play_button"> - Play - </button> - <button id="gl_canvas_stop" class="stop_button"> - Stop - </button> - </div> - - <footer id="references"> - <h2>References</h2> - <ul> - </ul> - </footer> - </section> + <section> + <h2>Quaternion Time</h2> + <p> + I hate to start off the article like this. I really do. But it really wouldn't be a discussion of 3D simulation if we didn't jump right into quaternions. Before I start, however, I recommend you take a look at <a href='https://www.3dgep.com/understanding-quaternions'>this article</a>. Quaternions have been written about over and over throughout the years (and I have read many articles about them over and over throughout the years), so I will not waste your time describing every single detail here. The article that I linked to should provide you enough information to begin to understand what quaternions are and why they're important. That being said, I will provide a brief intro to quaternions here, as well as my own C++ implementation of their algebra. (This article is also quite useful: <a href='http://danceswithcode.net/engineeringnotes/quaternions/quaternions.html'>Dance's With Code Website</a>) + <br/><br/> + + </p> + </section> + <section> + <h2> + Live Example + </h2> + <p> + <button id='force_apply'>Click Me</button> + </p> + <div class="opengl_canvas_container"> + <canvas id="gl_canvas" width="800" height="600"></canvas> + <button id="gl_canvas_play" class="play_button"> + Play + </button> + <button id="gl_canvas_stop" class="stop_button"> + Stop + </button> + </div> + + <footer id="references"> + <h2>References</h2> + <ul> + </ul> + </footer> + </section> </article> diff --git a/3d/rigidbody/dist/output.wasm b/3d/rigidbody/dist/output.wasm Binary files differindex 98d25e5..8ebe0dd 100755 --- a/3d/rigidbody/dist/output.wasm +++ b/3d/rigidbody/dist/output.wasm diff --git a/3d/rigidbody/main.cpp b/3d/rigidbody/main.cpp index c83018b..90c6bc8 100644 --- a/3d/rigidbody/main.cpp +++ b/3d/rigidbody/main.cpp @@ -13,17 +13,96 @@ #include <cmath> #include <cfloat> +struct Impulse { + Vector3 force = { 0, 0, 0 }; + Vector3 pointOfApplication = { 0, 0, 0 }; + float32 timeOfApplicationSeconds = 0.016f; + float32 timeAppliedSeconds = 0.f; + bool isDead = false; +}; + +const int32 MAX_IMPULSES = 4; + struct Rigidbody3d { + int32 numImpulses = 0; + Impulse activeImpulses[MAX_IMPULSES]; Vector3 velocity; Vector3 position; + float32 mass = 1.f; + + Vector3 rotationalVelocity; + Quaternion rotation; + float32 momentOfInertia = 1.f; + + void reset() { + numImpulses = 0; + velocity = { 0, 0, 0}; + rotationalVelocity = { 0, 0, 0 }; + } + + void applyImpulse(Impulse i) { + if (numImpulses > MAX_IMPULSES) { + printf("Unable to apply impulse. Buffer full.\n"); + return; + } + + activeImpulses[numImpulses] = i; + numImpulses++; + } + + void update(float32 deltaTimeSeconds) { + // Apply gravity + //velocity += (Vector3 { 0.f, -9.8f, 0.f } * deltaTimeSeconds); + + Vector3 force = { 0.f, 0.f, 0.f }; + Vector3 torque = { 0.f, 0.f, 0.f }; + for (int32 idx = 0; idx < numImpulses; idx++) { + Impulse& i = activeImpulses[idx]; - void update(float32 dtSeconds) { + float32 nextTimeAppliedSeconds = i.timeAppliedSeconds + deltaTimeSeconds; + if (nextTimeAppliedSeconds >= i.timeOfApplicationSeconds) { + nextTimeAppliedSeconds = i.timeOfApplicationSeconds; + i.isDead = true; + } + + float32 impulseDtSeconds = nextTimeAppliedSeconds - i.timeAppliedSeconds; + Vector3 forceToApply = i.force * (impulseDtSeconds / i.timeOfApplicationSeconds); + force += forceToApply; + + force.printDebug("Force applied\n"); + + torque += i.pointOfApplication.cross(force).dot(forceToApply); + i.timeAppliedSeconds = nextTimeAppliedSeconds; + } + Vector3 acceleration = force / mass; + velocity += (acceleration * deltaTimeSeconds); + position += (velocity * deltaTimeSeconds); + + Vector3 rotationalAcceleration = torque / momentOfInertia; + rotationalVelocity += (rotationalAcceleration * deltaTimeSeconds); + + Quaternion rotationVelocityQuat = { 0, rotationalVelocity.x, rotationalVelocity.y, rotationalVelocity.z }; + Quaternion dqDt = (rotationVelocityQuat * rotation) * 0.5f; + rotation = rotation + (dqDt * deltaTimeSeconds); + + for (int32 idx = 0; idx < numImpulses; idx++) { + if (activeImpulses[idx].isDead) { + for (int j = idx + 1; j < numImpulses; j++) { + activeImpulses[j - 1] = activeImpulses[j]; + } + + idx = idx - 1; + numImpulses--; + } + } } }; struct Cube { Mesh3d mesh; + Rigidbody3d body; + float32 scale = 10.f; void load(Renderer3d* renderer) { Vertex3d cubeVertices[] = { @@ -87,12 +166,18 @@ struct Cube { mesh.load(&cubeVertices[0], 8, cubeIndices, 36, renderer); + + body.position = Vector3 { 0.f, 0.f, 0.f }; + body.velocity = Vector3 { 0.f, 0.f, 0.f }; + mesh.model = Mat4x4().scale(scale); + + float32 singleFaceArea = scale * scale; + body.momentOfInertia = (body.mass * singleFaceArea) / 6.f; } void update(float32 dtSeconds) { - float32 multiplier = (PI / 8.f) * dtSeconds; - Vector3 currentRotation = Vector3 { multiplier, multiplier, multiplier }; - mesh.model = mesh.model.rotate(currentRotation.x, currentRotation.y, currentRotation.z); + body.update(dtSeconds); + mesh.model = mesh.model.translate(body.position) * body.rotation.toMatrix(); } void render(Renderer3d* renderer) { @@ -106,6 +191,7 @@ struct Cube { EM_BOOL onPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData); EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData); +EM_BOOL onForceApplicationRequested(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData); void load(); void update(float32 time, void* userData); @@ -122,14 +208,17 @@ int main() { context.init("#gl_canvas"); emscripten_set_click_callback("#gl_canvas_play", NULL, false, onPlayClicked); emscripten_set_click_callback("#gl_canvas_stop", NULL, false, onStopClicked); + emscripten_set_click_callback("#force_apply", NULL, false, onForceApplicationRequested); return 0; } void load() { renderer.load(&context); + cube.scale = 12.f; + cube.body.mass = 100.f; cube.load(&renderer); - camera.projection = Mat4x4().getPerspectiveProjection(0.1f, 100.f, PI / 2.f, 800.f / 600.f); - camera.view = Mat4x4().translate({ 0, 0, -10 }); + camera.projection = Mat4x4().getPerspectiveProjection(0.1f, 10000.f, DEG_TO_RAD(60.f), 800.f / 600.f); + camera.view = Mat4x4().translate({ 0, 0, -250 }); mainLoop.run(update); } @@ -162,3 +251,12 @@ EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, voi unload(); return true; } + +EM_BOOL onForceApplicationRequested(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) { + printf("Force applied\n"); + Impulse base; + base.force = { 0, 1000, 0 }; + base.pointOfApplication = { 0, 1, 0 }; + cube.body.applyImpulse(base); + return true; +} diff --git a/resources.html.content b/resources.html.content new file mode 100644 index 0000000..2b3aef1 --- /dev/null +++ b/resources.html.content @@ -0,0 +1,12 @@ +<article> + <h1>Resources</h1> + <section> + <p>Here are a set of books and resources that I have found particularly helpful in forming my understanding of physics engines. I highly recommend going through all of these resource.</p> + </section> + <section> + <h2>Mathematics</h2> + <ul> + <li><a href='http://canvas.projekti.info/ebooks/Mathematics%20for%203D%20Game%20Programming%20and%20Computer%20Graphics,%20Third%20Edition.pdf'>Mathematics for 3D Game Programming and Computer Graphics, Third Edition</a>: a great resource on foundational mathematics for computer graphics. I am linking to the free pdf version here so that you can test drive it, but I highly recommend having a physical copy of this book on your shelf. It is a simple and elegant reference for all things computer graphics.</li> + </ul> + </section> +</article> diff --git a/shared_cpp/mathlib.cpp b/shared_cpp/mathlib.cpp index b7748fe..fb09cd9 100644 --- a/shared_cpp/mathlib.cpp +++ b/shared_cpp/mathlib.cpp @@ -155,6 +155,13 @@ Vector3 Vector3::operator+(const Vector3& v2) { return add(v2); } +Vector3& Vector3::operator+=(Vector3 other) { + x += other.x; + y += other.y; + z += other.z; + return *this; +} + Vector3 Vector3::operator-(const Vector3& v2) { return subtract(v2); } @@ -167,6 +174,14 @@ Vector3 Vector3::operator*(float value) { return scale(value); } +Vector3 Vector3::operator/(const Vector3& v2) { + return { + x / v2.x, + y / v2.y, + z / v2.z + }; +} + Vector3 Vector3::operator*(const Vector3& v2) { return { x * v2.x, @@ -623,3 +638,16 @@ Mat4x4 Quaternion::toMatrix() const { float Quaternion::dot(const Quaternion& other) const { return w * other.w + x * other.x + y * other.y + z * other.z; } + +Quaternion quaternionFromRotation(Vector3 axis, float angleRadians) { + float halfAngleRadians = angleRadians / 2.f; + float cosHalfAngRad = cosf(halfAngleRadians); + float sinHalfAngRad = sinf(halfAngleRadians); + + return { + cosHalfAngRad, + axis.x * sinHalfAngRad, + axis.y * sinHalfAngRad, + axis.z * sinHalfAngRad + }; +} diff --git a/shared_cpp/mathlib.h b/shared_cpp/mathlib.h index d550e90..e3c6875 100644 --- a/shared_cpp/mathlib.h +++ b/shared_cpp/mathlib.h @@ -18,6 +18,8 @@ #define ABS(x) (x < 0 ? -x : x) #define SIGN(x) (x < 0 ? -1 : 1) #define PI 3.141592653589793238463 +#define DEG_TO_RAD(x) (x * (PI / 180.f)) +#define RAD_TO_DEG(x) (x * (180.f / PI)) struct Vector2 { float x = 0; @@ -58,10 +60,12 @@ struct Vector3 { Vector3 normalize(); Vector3 operator+(const Vector3& v2); + Vector3& operator+=(Vector3 other); Vector3 operator-(const Vector3& v2); Vector3 operator-(); Vector3 operator*(float value); Vector3 operator*(const Vector3& v2); + Vector3 operator/(const Vector3& v2); float operator[](int index); void printDebug(const char* name); @@ -75,7 +79,7 @@ struct Vector4 { Vector4(); Vector4(float value); - Vector4(float inX = 0.f, float inY = 0.f, float inZ = 0.f, float inW = 1.f); + Vector4(float inX, float inY, float inZ, float inW); Vector4 fromColor(float r, float g, float b, float a); Vector4 toNormalizedColor(); @@ -126,10 +130,10 @@ struct Mat4x4 { }; struct Quaternion { + float w = 0; float x = 0; float y = 0; float z = 0; - float w = 0; float operator [](int index); Quaternion operator*(const Quaternion& other) const; @@ -142,3 +146,5 @@ struct Quaternion { float length() const; float dot(const Quaternion& other) const; }; + +Quaternion quaternionFromRotation(Vector3 axis, float angleRadians); |