From ece2b67aa689aee0b881bac17a62c16e0469bc56 Mon Sep 17 00:00:00 2001 From: Matthew Kosarek Date: Sun, 21 Feb 2021 18:32:04 -0500 Subject: Proper support for favicons, rigid body intersections are no longer broken, palinko game --- frontend/2d_part_1.html | 126 +++++++------ frontend/2d_part_2.html | 71 +++---- frontend/2d_part_3.html | 60 ++++-- frontend/_rigidbody/circle.js | 12 +- frontend/_rigidbody/pill.js | 0 frontend/_rigidbody/rigidbody_1.js | 211 ++++++++++----------- frontend/_rigidbody/rigidbody_2.js | 260 +++++++++++++------------- frontend/_rigidbody/rigidbody_3.js | 158 ---------------- frontend/_rigidbody/rigidbody_3a.js | 189 +++++++++++++++++++ frontend/_rigidbody/rigidbody_3b.js | 192 +++++++++++++++++++ frontend/dog-114-203766.png | Bin 8343 -> 0 bytes frontend/dog-120-203766.png | Bin 8262 -> 0 bytes frontend/dog-144-203766.png | Bin 9834 -> 0 bytes frontend/dog-152-203766.png | Bin 8748 -> 0 bytes frontend/dog-16-203766.png | Bin 969 -> 0 bytes frontend/dog-24-203766.png | Bin 1203 -> 0 bytes frontend/dog-32-203766.png | Bin 1742 -> 0 bytes frontend/dog-48-203766.png | Bin 3026 -> 0 bytes frontend/dog-512-203766.png | Bin 41072 -> 0 bytes frontend/dog-57-203766.png | Bin 3686 -> 0 bytes frontend/dog-64-203766.png | Bin 4111 -> 0 bytes frontend/dog-72-203766.png | Bin 4493 -> 0 bytes frontend/favicon.ico | Bin 32038 -> 0 bytes frontend/favicon/favicon.ico | Bin 0 -> 32038 bytes frontend/favicon/little-penguin-114-27563.png | Bin 0 -> 28726 bytes frontend/favicon/little-penguin-120-27563.png | Bin 0 -> 27274 bytes frontend/favicon/little-penguin-144-27563.png | Bin 0 -> 31335 bytes frontend/favicon/little-penguin-152-27563.png | Bin 0 -> 25239 bytes frontend/favicon/little-penguin-16-27563.png | Bin 0 -> 1600 bytes frontend/favicon/little-penguin-24-27563.png | Bin 0 -> 3033 bytes frontend/favicon/little-penguin-32-27563.png | Bin 0 -> 4649 bytes frontend/favicon/little-penguin-48-27563.png | Bin 0 -> 8985 bytes frontend/favicon/little-penguin-57-27563.png | Bin 0 -> 11380 bytes frontend/favicon/little-penguin-64-27563.png | Bin 0 -> 13108 bytes frontend/favicon/little-penguin-72-27563.png | Bin 0 -> 14528 bytes frontend/index.css | 15 +- frontend/index.html | 59 +++--- frontend/index.js | 16 +- frontend/readme.txt | 26 --- frontend/rigidbody.html | 33 +--- 40 files changed, 821 insertions(+), 607 deletions(-) create mode 100644 frontend/_rigidbody/pill.js delete mode 100644 frontend/_rigidbody/rigidbody_3.js create mode 100644 frontend/_rigidbody/rigidbody_3a.js create mode 100644 frontend/_rigidbody/rigidbody_3b.js delete mode 100644 frontend/dog-114-203766.png delete mode 100644 frontend/dog-120-203766.png delete mode 100644 frontend/dog-144-203766.png delete mode 100644 frontend/dog-152-203766.png delete mode 100644 frontend/dog-16-203766.png delete mode 100644 frontend/dog-24-203766.png delete mode 100644 frontend/dog-32-203766.png delete mode 100644 frontend/dog-48-203766.png delete mode 100644 frontend/dog-512-203766.png delete mode 100644 frontend/dog-57-203766.png delete mode 100644 frontend/dog-64-203766.png delete mode 100644 frontend/dog-72-203766.png delete mode 100644 frontend/favicon.ico create mode 100644 frontend/favicon/favicon.ico create mode 100644 frontend/favicon/little-penguin-114-27563.png create mode 100644 frontend/favicon/little-penguin-120-27563.png create mode 100644 frontend/favicon/little-penguin-144-27563.png create mode 100644 frontend/favicon/little-penguin-152-27563.png create mode 100644 frontend/favicon/little-penguin-16-27563.png create mode 100644 frontend/favicon/little-penguin-24-27563.png create mode 100644 frontend/favicon/little-penguin-32-27563.png create mode 100644 frontend/favicon/little-penguin-48-27563.png create mode 100644 frontend/favicon/little-penguin-57-27563.png create mode 100644 frontend/favicon/little-penguin-64-27563.png create mode 100644 frontend/favicon/little-penguin-72-27563.png delete mode 100644 frontend/readme.txt (limited to 'frontend') diff --git a/frontend/2d_part_1.html b/frontend/2d_part_1.html index 312611a..830f201 100644 --- a/frontend/2d_part_1.html +++ b/frontend/2d_part_1.html @@ -7,6 +7,7 @@ Physics for Games + @@ -26,68 +27,71 @@ 2D - Rotational Forces 2D - Collision Forces -
-

Part 1: Linear Forces

-

- The first - and perhaps easiest - part of implementing any rigid body physics system is getting the entities in your scene to move in response to linear forces. - With this implementation alone, you can achieve an interesting level of realism in your 2D (and even 3D) scene. -

-

- Let's begin by recalling the relationships between acceleration, velocity, and position. -

-

- Knowing all this, you should be able to understand the following source code fairly easily; -

-                        
-function update(dtSeconds) {
-    // Add up the forces acting on the circle
-    const GRAVITY = 9.8;
-    const lGravityForce = vec2(0, -1.0 * (lCircle.mass * GRAVITY));
-    lCircle.force = addVec2(lCircle.force, lGravityForce);
-
-    // Figure out acceleration (a = F / m)
-    const lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass);
-
-    // Calculate the new velocity: v = v0 + a * t
-    lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, dtSeconds));
-
-    // Update the position based on velocity: x = x0 + v * t
-    lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, dtSeconds));
-
-    // Update the model matrix accordingly
-    lCircle.model = translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0);
-
-    // Reset the force vector for the next update
-    lCircle.force = vec2()
-}
-                        
-                    
-

-
- -
-
    -
  • Linear Force:N/A
  • -
  • Linear Acceleration:N/A
  • -
  • Linear Velocity:N/A
  • -
  • Linear Position:N/A
  • -
-
-
- - - -
- -
+
+
+

Part 1: Linear Forces

+

+ The first - and perhaps easiest - part of implementing any rigid body physics system is getting the entities in your scene to move in response to linear forces. + With this implementation alone, you can achieve an interesting level of realism in your 2D (and even 3D) scene. +

+

+ Let's begin by recalling the relationships between acceleration, velocity, and position. +

+

+ Knowing all this, you should be able to understand the following source code fairly easily; +

+                            
+    function update(dtSeconds) {
+        // Add up the forces acting on the circle
+        const GRAVITY = 9.8;
+        const lGravityForce = vec2(0, -1.0 * (lCircle.mass * GRAVITY));
+        lCircle.force = addVec2(lCircle.force, lGravityForce);
+    
+        // Figure out acceleration (a = F / m)
+        const lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass);
+    
+        // Calculate the new velocity: v = v0 + a * t
+        lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, dtSeconds));
+    
+        // Update the position based on velocity: x = x0 + v * t
+        lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, dtSeconds));
+    
+        // Update the model matrix accordingly
+        lCircle.model = translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0);
+    
+        // Reset the force vector for the next update
+        lCircle.force = vec2()
+    }
+                            
+                        
+

+
+ +
+
    +
  • Linear Force:N/A
  • +
  • Linear Acceleration:N/A
  • +
  • Linear Velocity:N/A
  • +
  • Linear Position:N/A
  • +
+
+
+ + + +
+ +
+
+ +
- - -
+ +
\ No newline at end of file diff --git a/frontend/2d_part_2.html b/frontend/2d_part_2.html index 01a7767..845985c 100644 --- a/frontend/2d_part_2.html +++ b/frontend/2d_part_2.html @@ -7,6 +7,7 @@ Physics for Games + @@ -26,41 +27,43 @@ 2D - Rotational Forces 2D - Collision Forces -
-

Part 2: Rotational Forces

-

- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -

-
- -
-
    -
  • Angular Force:N/A
  • -
  • Angular Acceleration:N/A
  • -
  • Angular Velocity:N/A
  • -
  • Angular Position:N/A
  • -
-
-
- - - -
-
- - - -
- -
+
+
+

Part 2: Rotational Forces

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +

+
+ +
+
    +
  • Angular Force:N/A
  • +
  • Angular Acceleration:N/A
  • +
  • Angular Velocity:N/A
  • +
  • Angular Position:N/A
  • +
+
+
+ + + +
+
+ + + +
+ +
+
+ +
- - -
+
diff --git a/frontend/2d_part_3.html b/frontend/2d_part_3.html index ae00c9b..6e46843 100644 --- a/frontend/2d_part_3.html +++ b/frontend/2d_part_3.html @@ -7,13 +7,15 @@ Physics for Games + - + +
@@ -26,26 +28,46 @@ 2D - Rotational Forces 2D - Collision Forces -
-

Part 3: Collisions

-

- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -

-
- -
-
- - +
+
+

Part 3: Collisions

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +

+
+ +
+
+ + +
+ +
- - -
+ +
+

Fun Example: Plinko Game

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +

+
+ +
+ +
+ + +
+
diff --git a/frontend/_rigidbody/circle.js b/frontend/_rigidbody/circle.js index 35044e3..1cec7ce 100644 --- a/frontend/_rigidbody/circle.js +++ b/frontend/_rigidbody/circle.js @@ -1,3 +1,6 @@ +/// +/// + const BYTES_PER_FLOAT = 4; /** @@ -42,13 +45,14 @@ function circle(pGl, pRadius, pSegments, pColorList, pInitialPosition, pMass) { vertexCount: vertexCount, prevPos: vec2(), position: pInitialPosition || vec2(), + prevVelocity: vec2(), velocity: vec2(), force: vec2(), torque: 0, - mass: pMass || 1, + mass: pMass === undefined ? 1 : pMass, rotationVelocity: 0, rotationRadians: 0, - model: mat4(), + model: translateMatrix(mat4(), pInitialPosition ? pInitialPosition.x : 0, pInitialPosition ? pInitialPosition.y : 0, 0), radius: pRadius }; } @@ -106,4 +110,8 @@ function getIntersectionDataForCircles(pFirst, pSecond) { firstPointOfApplication: subVec2(lMedianIntersectingPoint, pFirst.position), secondPointOfApplication: subVec2(lMedianIntersectingPoint, pSecond.position) } +} + +function freeCircle(pGl, pCircle) { + pGl.deleteBuffer(pCircle.buffer); } \ No newline at end of file diff --git a/frontend/_rigidbody/pill.js b/frontend/_rigidbody/pill.js new file mode 100644 index 0000000..e69de29 diff --git a/frontend/_rigidbody/rigidbody_1.js b/frontend/_rigidbody/rigidbody_1.js index c5e4f0a..697822d 100644 --- a/frontend/_rigidbody/rigidbody_1.js +++ b/frontend/_rigidbody/rigidbody_1.js @@ -5,110 +5,113 @@ /// /// -function main() { - // Define Constants - const CIRCLE_RADIUS = 16; - const GRAVITY = 9.8; - - // Retrieve context - const lProgramContext = getContext('#rigidbody_1'); - - if (lProgramContext.gl === null) { - console.error('Unable to initialize WebGL. Your browser or machine may not support it.'); - return; - } - - lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); - lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); - - function run() { - console.log('Running Rigid Body 1'); - lProgramContext.load().then(function(pProgramInfo) { - const lCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [{ x: 0.3, y: 0.3, z: 0.3, w: 1 }], vec2(lProgramContext.width / 2.0, lProgramContext.height / 2.0)); - - function update(pDeltaTimeSeconds) { - // Physics updates - const lGravityForce = vec2(0, -1.0 * (lCircle.mass * GRAVITY)); - - // Add up the forces acting on the circle - lCircle.force = addVec2(lCircle.force, lGravityForce); - - // Figure out acceleration (a = F / m) - const lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass); - - // Calculate the new velocity: v = v0 + a * t - lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds)); - - // Update the position based on velocity: x = x0 + v * t - lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, pDeltaTimeSeconds)); - - // Update the model matrix accordingly - lCircle.model = translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0); - - // Report the current state to the frontend - $('#rigidbody_1_force_field').text(vec2str(lCircle.force)); - $('#rigidbody_1_acceleration_field').text(vec2str(lCurrentAcceleration)); - $('#rigidbody_1_velocity_field').text(vec2str(lCircle.velocity)); - $('#rigidbody_1_position_field').text(vec2str(lCircle.position)); - - // Reset the circle's force vector - lCircle.force = vec2(); - - // Render Code only - lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque - lProgramContext.gl.clearDepth(1.0); // Clear everything - lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST); // Enable depth testing - lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL); // Near things obscure far things - lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT); - - lProgramContext.gl.useProgram(pProgramInfo.program); - lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective); - lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.model, false, lCircle.model); - - renderCircle(lProgramContext.gl, pProgramInfo, lCircle); - } - - function addForce(ev) { - ev.preventDefault(); - ev.stopPropagation(); - - let lXValue = $(this).find('.vec2_x_input').val(), - lYValue = $(this).find('.vec2_y_input').val(); - - if (lXValue.length === 0) { - lXValue = 0; +(function() { + + function main() { + // Define Constants + const CIRCLE_RADIUS = 16; + const GRAVITY = 9.8; + + // Retrieve context + const lProgramContext = getContext('#rigidbody_1'); + + if (lProgramContext.gl === null) { + console.error('Unable to initialize WebGL. Your browser or machine may not support it.'); + return; + } + + lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); + lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); + + function run() { + console.log('Running Rigid Body 1'); + lProgramContext.load().then(function(pProgramInfo) { + const lCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [{ x: 0.3, y: 0.3, z: 0.3, w: 1 }], vec2(lProgramContext.width / 2.0, lProgramContext.height / 2.0)); + + function update(pDeltaTimeSeconds) { + // Physics updates + const lGravityForce = vec2(0, -1.0 * (lCircle.mass * GRAVITY)); + + // Add up the forces acting on the circle + lCircle.force = addVec2(lCircle.force, lGravityForce); + + // Figure out acceleration (a = F / m) + const lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass); + + // Calculate the new velocity: v = v0 + a * t + lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds)); + + // Update the position based on velocity: x = x0 + v * t + lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, pDeltaTimeSeconds)); + + // Update the model matrix accordingly + lCircle.model = translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0); + + // Report the current state to the frontend + $('#rigidbody_1_force_field').text(vec2str(lCircle.force)); + $('#rigidbody_1_acceleration_field').text(vec2str(lCurrentAcceleration)); + $('#rigidbody_1_velocity_field').text(vec2str(lCircle.velocity)); + $('#rigidbody_1_position_field').text(vec2str(lCircle.position)); + + // Reset the circle's force vector + lCircle.force = vec2(); + + // Render Code only + lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque + lProgramContext.gl.clearDepth(1.0); // Clear everything + lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST); // Enable depth testing + lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL); // Near things obscure far things + lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT); + + lProgramContext.gl.useProgram(pProgramInfo.program); + lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective); + lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.model, false, lCircle.model); + + renderCircle(lProgramContext.gl, pProgramInfo, lCircle); } - - if (lYValue.length === 0) { - lYValue = 5000; + + function addForce(ev) { + ev.preventDefault(); + ev.stopPropagation(); + + let lXValue = $(this).find('.vec2_x_input').val(), + lYValue = $(this).find('.vec2_y_input').val(); + + if (lXValue.length === 0) { + lXValue = 0; + } + + if (lYValue.length === 0) { + lYValue = 5000; + } + + console.log('Applying force: ' + lXValue + ', ' + lYValue); + lCircle.force = addVec2(lCircle.force, vec2(Number(lXValue), Number(lYValue))); } - - console.log('Applying force: ' + lXValue + ', ' + lYValue); - lCircle.force = addVec2(lCircle.force, vec2(Number(lXValue), Number(lYValue))); - } - - function cleanup() { - lProgramContext.gl.deleteBuffer(lCircle.buffer); - lProgramContext.gl.deleteProgram(pProgramInfo.program); - lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); - lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); - } - - function reset() { - lExitRequestFunc(); - lProgramContext.reset(); - $('#rigidbody_1_force_submit_button').unbind('submit').submit(false); - } - - const lExitRequestFunc = requestUpdateLoop(update, cleanup); - lProgramContext.stopButton.on('click', reset); - $('#rigidbody_1_force_submit_button').submit(addForce); - }); + + function cleanup() { + lProgramContext.gl.deleteBuffer(lCircle.buffer); + lProgramContext.gl.deleteProgram(pProgramInfo.program); + lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); + lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); + } + + function reset() { + lExitRequestFunc(); + lProgramContext.reset(); + $('#rigidbody_1_force_submit_button').unbind('submit').submit(false); + } + + const lExitRequestFunc = requestUpdateLoop(update, cleanup); + lProgramContext.stopButton.on('click', reset); + $('#rigidbody_1_force_submit_button').submit(addForce); + }); + } + + lProgramContext.playButton.on('click', run); + $('#rigidbody_1_force_submit_button').submit(false); + } - - lProgramContext.playButton.on('click', run); - $('#rigidbody_1_force_submit_button').submit(false); - -} - -$(document).ready(main); \ No newline at end of file + + $(document).ready(main); +})() \ No newline at end of file diff --git a/frontend/_rigidbody/rigidbody_2.js b/frontend/_rigidbody/rigidbody_2.js index 1c6b79f..c878c1a 100644 --- a/frontend/_rigidbody/rigidbody_2.js +++ b/frontend/_rigidbody/rigidbody_2.js @@ -4,140 +4,142 @@ /// /// -function main() { - // Define Constants - const CIRCLE_RADIUS = 16; - const GRAVITY = 9.8; - - // Retrieve context - const lProgramContext = getContext('#rigidbody_2'); - - if (lProgramContext.gl === null) { - console.error('Unable to initialize WebGL. Your browser or machine may not support it.'); - return; - } - - lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); - lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); - - function run() { - console.log('Running Rigid Body 2'); - lProgramContext.load().then(function(pProgramInfo) { - const lCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [ - { x: 1, y: 1, z: 0, w: 1 }, - { x: 1, y: 0, z: 1, w: 1 }, - { x: 0, y: 1, z: 1, w: 1 }, - { x: 0, y: 1, z: 0, w: 1 } - ], vec2(lProgramContext.width / 2.0, lProgramContext.height / 2.0)); - - function update(pDeltaTimeSeconds) { - // Same physics updates from part 1 - applyForce(vec2(0, -1.0 * (lCircle.mass * GRAVITY))); - const lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass); - lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds)); - lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, pDeltaTimeSeconds)); - lCircle.force = vec2(); - - // Angular code starts here - - // Retrieve the moment of inertia for our shape (Ours is a circle by default) - const lMomentOfInertia = getMomentOfInertia(lCircle); - - // Calculate the angular acceperation (omega = T / I) - const lAngularAcceleration = lCircle.torque / lMomentOfInertia; - - // Calculate the rotation in radians - lCircle.rotationVelocity += lAngularAcceleration * pDeltaTimeSeconds; - lCircle.rotationRadians += lCircle.rotationVelocity * pDeltaTimeSeconds; - lCircle.torque = 0; - - // Calculate the model as previously, but this time, also rotate it - lCircle.model = rotateMatrix2d(translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0), lCircle.rotationRadians); - - // Render Code only - lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); - lProgramContext.gl.clearDepth(1.0); - lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST); - lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL); - lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT); - - lProgramContext.gl.useProgram(pProgramInfo.program); - lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective); - lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.model, false, lCircle.model); - - renderCircle(lProgramContext.gl, pProgramInfo, lCircle); - } - - const TORQUE_MULTIPLIER = 100.0; // TODO: This may be unncessary - - function applyForce(pForceVector, pPointOfApplication) { - if (pPointOfApplication !== undefined) { - const lOriginToPointOfApp = subVec2(vec2(), pPointOfApplication), // The point of application is relative to the model (i.e. the center of the circle, not the scene) - lPerpVec = vec2(-lOriginToPointOfApp.y, lOriginToPointOfApp.x); // Retrieve the perpendicular vector +(function() { + function main() { + // Define Constants + const CIRCLE_RADIUS = 16; + const GRAVITY = 9.8; - // Calculate the torque from the perp dot (T = r_perp . F) - lCircle.torque += TORQUE_MULTIPLIER * dot2(lPerpVec, pForceVector); - } - - lCircle.force = addVec2(lCircle.force, pForceVector); - } - - function cleanup() { - lProgramContext.gl.deleteBuffer(lCircle.buffer); - lProgramContext.gl.deleteProgram(pProgramInfo.program); - lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); - lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); - } - - function reset() { - lExitRequestFunc(); - lProgramContext.reset(); - $('#rigidbody_2_force_submit_button').unbind('submit').submit(false); - } - - const lExitRequestFunc = requestUpdateLoop(update, cleanup); - lProgramContext.stopButton.on('click', reset); - $('#rigidbody_2_force_submit_button').submit(function(pEv) { - pEv.preventDefault(); - pEv.stopPropagation(); - - // Read in the force vector from the form - const lForceGroup = $('#rigidbody_2_force_input'), - lPositionGroup = $('#rigidbody_2_position_input'); - - let lForceVectorX = lForceGroup.find('.vec2_x_input').val(), - lForceVectorY = lForceGroup.find('.vec2_y_input').val(); - - if (lForceVectorX.length === 0) { - lForceVectorX = 0; + // Retrieve context + const lProgramContext = getContext('#rigidbody_2'); + + if (lProgramContext.gl === null) { + console.error('Unable to initialize WebGL. Your browser or machine may not support it.'); + return; + } + + lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); + lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); + + function run() { + console.log('Running Rigid Body 2'); + lProgramContext.load().then(function(pProgramInfo) { + const lCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [ + { x: 1, y: 1, z: 0, w: 1 }, + { x: 1, y: 0, z: 1, w: 1 }, + { x: 0, y: 1, z: 1, w: 1 }, + { x: 0, y: 1, z: 0, w: 1 } + ], vec2(lProgramContext.width / 2.0, lProgramContext.height / 2.0)); + + function update(pDeltaTimeSeconds) { + // Same physics updates from part 1 + applyForce(vec2(0, -1.0 * (lCircle.mass * GRAVITY))); + const lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass); + lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds)); + lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, pDeltaTimeSeconds)); + lCircle.force = vec2(); + + // Angular code starts here + + // Retrieve the moment of inertia for our shape (Ours is a circle by default) + const lMomentOfInertia = getMomentOfInertia(lCircle); + + // Calculate the angular acceperation (omega = T / I) + const lAngularAcceleration = lCircle.torque / lMomentOfInertia; + + // Calculate the rotation in radians + lCircle.rotationVelocity += lAngularAcceleration * pDeltaTimeSeconds; + lCircle.rotationRadians += lCircle.rotationVelocity * pDeltaTimeSeconds; + lCircle.torque = 0; + + // Calculate the model as previously, but this time, also rotate it + lCircle.model = rotateMatrix2d(translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0), lCircle.rotationRadians); + + // Render Code only + lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); + lProgramContext.gl.clearDepth(1.0); + lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST); + lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL); + lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT); + + lProgramContext.gl.useProgram(pProgramInfo.program); + lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective); + lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.model, false, lCircle.model); + + renderCircle(lProgramContext.gl, pProgramInfo, lCircle); } - - if (lForceVectorY.length === 0) { - lForceVectorY = 5000; + + const TORQUE_MULTIPLIER = 100.0; // TODO: This may be unncessary + + function applyForce(pForceVector, pPointOfApplication) { + if (pPointOfApplication !== undefined) { + const lOriginToPointOfApp = subVec2(vec2(), pPointOfApplication), // The point of application is relative to the model (i.e. the center of the circle, not the scene) + lPerpVec = vec2(-lOriginToPointOfApp.y, lOriginToPointOfApp.x); // Retrieve the perpendicular vector + + // Calculate the torque from the perp dot (T = r_perp . F) + lCircle.torque += TORQUE_MULTIPLIER * dot2(lPerpVec, pForceVector); + } + + lCircle.force = addVec2(lCircle.force, pForceVector); } - - // Read in the point of application vector from the form - let lPositionGroupX = lPositionGroup.find('.vec2_x_input').val(), - lPositionGroupY = lPositionGroup.find('.vec2_y_input').val(); - - if (lPositionGroupX.length === 0) { - lPositionGroupX = -Math.sqrt(2) / 2; + + function cleanup() { + lProgramContext.gl.deleteBuffer(lCircle.buffer); + lProgramContext.gl.deleteProgram(pProgramInfo.program); + lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); + lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); } - - if (lPositionGroupY.length === 0) { - lPositionGroupY = -Math.sqrt(2) / 2; + + function reset() { + lExitRequestFunc(); + lProgramContext.reset(); + $('#rigidbody_2_force_submit_button').unbind('submit').submit(false); } - - const lForceVector = vec2(Number(lForceVectorX), Number(lForceVectorY)); - const lPointOfApplication = scaleVec2(normalize2(vec2(Number(lPositionGroupX), Number(lPositionGroupY))), lCircle.radius); - - applyForce(lForceVector, lPointOfApplication); + + const lExitRequestFunc = requestUpdateLoop(update, cleanup); + lProgramContext.stopButton.on('click', reset); + $('#rigidbody_2_force_submit_button').submit(function(pEv) { + pEv.preventDefault(); + pEv.stopPropagation(); + + // Read in the force vector from the form + const lForceGroup = $('#rigidbody_2_force_input'), + lPositionGroup = $('#rigidbody_2_position_input'); + + let lForceVectorX = lForceGroup.find('.vec2_x_input').val(), + lForceVectorY = lForceGroup.find('.vec2_y_input').val(); + + if (lForceVectorX.length === 0) { + lForceVectorX = 0; + } + + if (lForceVectorY.length === 0) { + lForceVectorY = 5000; + } + + // Read in the point of application vector from the form + let lPositionGroupX = lPositionGroup.find('.vec2_x_input').val(), + lPositionGroupY = lPositionGroup.find('.vec2_y_input').val(); + + if (lPositionGroupX.length === 0) { + lPositionGroupX = -Math.sqrt(2) / 2; + } + + if (lPositionGroupY.length === 0) { + lPositionGroupY = -Math.sqrt(2) / 2; + } + + const lForceVector = vec2(Number(lForceVectorX), Number(lForceVectorY)); + const lPointOfApplication = scaleVec2(normalize2(vec2(Number(lPositionGroupX), Number(lPositionGroupY))), lCircle.radius); + + applyForce(lForceVector, lPointOfApplication); + }); }); - }); + } + + lProgramContext.playButton.on('click', run); + $('#rigidbody_2_force_submit_button').submit(false); } - lProgramContext.playButton.on('click', run); - $('#rigidbody_2_force_submit_button').submit(false); -} - -$(document).ready(main); \ No newline at end of file + $(document).ready(main); +})() \ No newline at end of file diff --git a/frontend/_rigidbody/rigidbody_3.js b/frontend/_rigidbody/rigidbody_3.js deleted file mode 100644 index 0316268..0000000 --- a/frontend/_rigidbody/rigidbody_3.js +++ /dev/null @@ -1,158 +0,0 @@ -/// -/// -/// -/// -/// - -function main() { - // Define Constants - const CIRCLE_RADIUS = 16; - const GRAVITY = 9.8; - const COF_OF_RESTITUITION = 0.7; - - // Retrieve context - const lProgramContext = getContext('#rigidbody_3'); - - if (lProgramContext.gl === null) { - console.error('Unable to initialize WebGL. Your browser or machine may not support it.'); - return; - } - - lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); - lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); - - function run() { - console.log('Running Rigid Body 3'); - lProgramContext.load().then(function(pProgramInfo) { - // Circile initialization - const horizontalCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [ - { x: 1, y: 1, z: 0, w: 1 }, - { x: 1, y: 0, z: 1, w: 1 }, - { x: 0, y: 1, z: 1, w: 1 }, - { x: 0, y: 1, z: 0, w: 1 } - ], vec2(400, lProgramContext.height / 2.0)); - - const verticalCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [ - { x: 1, y: 0, z: 0, w: 1 }, - { x: 0, y: 1, z: 0, w: 1 }, - { x: 0, y: 0, z: 1, w: 1 } - ], vec2(lProgramContext.width / 2.0, lProgramContext.height / 2.0 + 100)); - - horizontalCircle.velocity = vec2(-100, 0); - verticalCircle.velocity = vec2(0, -100); - - lTimeStepScale = $('#time_step_slider').val(); - - /** - * Run the update method of a single circle - * - * @param {circle} pCircle - * @param {number} pDeltaTimeSeconds - */ - function updateCircle(pCircle, pDeltaTimeSeconds) { - // Same physics updates from part 1 - applyForce(pCircle, vec2(0, -1.0 * (pCircle.mass * GRAVITY))); - const lCurrentAcceleration = scaleVec2(pCircle.force, 1.0 / pCircle.mass); - pCircle.velocity = addVec2(pCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds)); - pCircle.prevPos = { ...pCircle.position }; - pCircle.position = addVec2(pCircle.position, scaleVec2(pCircle.velocity, pDeltaTimeSeconds)); - pCircle.force = vec2(); - - // Same physics updates from part 2 - const lMomentOfInertia = getMomentOfInertia(pCircle); - const lAngularAcceleration = pCircle.torque / lMomentOfInertia; - pCircle.rotationVelocity += lAngularAcceleration * pDeltaTimeSeconds; - pCircle.rotationRadians += pCircle.rotationVelocity * pDeltaTimeSeconds; - pCircle.torque = 0; - - pCircle.model = rotateMatrix2d(translateMatrix(mat4(), pCircle.position.x, pCircle.position.y, 0), pCircle.rotationRadians); - } - - function update(pDeltaTimeSeconds) { - pDeltaTimeSeconds = pDeltaTimeSeconds * lTimeStepScale; - updateCircle(horizontalCircle, pDeltaTimeSeconds); - updateCircle(verticalCircle, pDeltaTimeSeconds); - collision(); - render(); - } - - function collision() { - if (!doCirclesIntersect(horizontalCircle, verticalCircle)) { - return false; - } - - const lIntersectionResult = getIntersectionDataForCircles(horizontalCircle, verticalCircle); - - console.log('We have a collision'); - const lRelativeVelocity = lIntersectionResult.relativeVelocity, - lCollisionNormal = lIntersectionResult.collisionNormal, - lFirstPerp = getPerp2(lIntersectionResult.firstPointOfApplication), - lSecondPerp = getPerp2(lIntersectionResult.secondPointOfApplication); - - console.log(lIntersectionResult); - - const lNumerator = dot2(scaleVec2(lRelativeVelocity, -(1.0 + COF_OF_RESTITUITION)), lCollisionNormal); - const lLinearDenomPart = dot2(lCollisionNormal, (scaleVec2(lCollisionNormal, 1 / horizontalCircle.mass + 1 / verticalCircle.mass))); - const lRotationalDenomPart = (Math.pow(dot2(lFirstPerp, lCollisionNormal), 2) / getMomentOfInertia(horizontalCircle)) - + (Math.pow(dot2(lSecondPerp, lCollisionNormal), 2) / getMomentOfInertia(verticalCircle)) - - const lImpulseMagnitude = lNumerator / (lLinearDenomPart + lRotationalDenomPart); - - horizontalCircle.velocity = addVec2(horizontalCircle.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / horizontalCircle.mass)); - verticalCircle.velocity = subVec2(verticalCircle.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / verticalCircle.mass)); - - horizontalCircle.rotationVelocity = horizontalCircle.rotationVelocity + dot2(lFirstPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / getMomentOfInertia(horizontalCircle); - verticalCircle.rotationVelocity = verticalCircle.rotationVelocity - dot2(lSecondPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / getMomentOfInertia(verticalCircle); - - return true; - } - - function render() { - lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); - lProgramContext.gl.clearDepth(1.0); - lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST); - lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL); - lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT); - lProgramContext.gl.useProgram(pProgramInfo.program); - lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective); - - renderCircle(lProgramContext.gl, pProgramInfo, horizontalCircle); - renderCircle(lProgramContext.gl, pProgramInfo, verticalCircle); - } - - const TORQUE_MULTIPLIER = 100.0; // TODO: This may be unncessary - function applyForce(pCircle, pForceVector, pPointOfApplication) { - if (pPointOfApplication !== undefined) { - const lOriginToPointOfApp = subVec2(vec2(), pPointOfApplication), - lPerpVec = vec2(-lOriginToPointOfApp.y, lOriginToPointOfApp.x); - - pCircle.torque += TORQUE_MULTIPLIER * dot2(lPerpVec, pForceVector); - } - - pCircle.force = addVec2(pCircle.force, pForceVector); - } - - function cleanup() { - lProgramContext.gl.deleteBuffer(horizontalCircle.buffer); - lProgramContext.gl.deleteBuffer(verticalCircle.buffer); - lProgramContext.gl.deleteProgram(pProgramInfo.program); - lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); - lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); - } - - function reset() { - lExitRequestFunc(); - lProgramContext.reset(); - $('#time_step_slider').unbind('change'); - } - - const lExitRequestFunc = requestUpdateLoop(update, cleanup); - lProgramContext.stopButton.on('click', reset); - $('#time_step_slider').on('change', function() { lTimeStepScale = $(this).val(); }); - }); - } - - lProgramContext.playButton.on('click', run); -} - -$(document).ready(main); \ No newline at end of file diff --git a/frontend/_rigidbody/rigidbody_3a.js b/frontend/_rigidbody/rigidbody_3a.js new file mode 100644 index 0000000..74d309b --- /dev/null +++ b/frontend/_rigidbody/rigidbody_3a.js @@ -0,0 +1,189 @@ +/// +/// +/// +/// +/// + +(function() { + function main() { + // Define Constants + const CIRCLE_RADIUS = 16; + const GRAVITY = 9.8; + const COF_OF_RESTITUITION = 0.7; + + // Retrieve context + const lProgramContext = getContext('#rigidbody_3a'); + + if (lProgramContext.gl === null) { + console.error('Unable to initialize WebGL. Your browser or machine may not support it.'); + return; + } + + lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); + lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); + + function run() { + console.log('Running Rigid Body 3a'); + lProgramContext.load().then(function(pProgramInfo) { + // Circile initialization + const horizontalCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [ + { x: 1, y: 1, z: 0, w: 1 }, + { x: 1, y: 0, z: 1, w: 1 }, + { x: 0, y: 1, z: 1, w: 1 }, + { x: 0, y: 1, z: 0, w: 1 } + ], vec2(400, lProgramContext.height / 2.0)); + + const verticalCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [ + { x: 1, y: 0, z: 0, w: 1 }, + { x: 0, y: 1, z: 0, w: 1 }, + { x: 0, y: 0, z: 1, w: 1 } + ], vec2(lProgramContext.width / 2.0, lProgramContext.height / 2.0 + 100)); + + horizontalCircle.velocity = vec2(-100, 0); + verticalCircle.velocity = vec2(0, -100); + + lTimeStepScale = $('#time_step_slider').val(); + + /** + * Run the update method of a single circle + * + * @param {circle} pCircle + * @param {number} pDeltaTimeSeconds + */ + function updateCircle(pCircle, pDeltaTimeSeconds) { + // Same physics updates from part 1 + applyForce(pCircle, vec2(0, -1.0 * (pCircle.mass * GRAVITY))); + const lCurrentAcceleration = scaleVec2(pCircle.force, 1.0 / pCircle.mass); + pCircle.prevVelocity = pCircle.velocity; + pCircle.velocity = addVec2(pCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds)); + pCircle.prevPos = { ...pCircle.position }; + pCircle.position = addVec2(pCircle.position, scaleVec2(pCircle.velocity, pDeltaTimeSeconds)); + pCircle.force = vec2(); + + // Same physics updates from part 2 + const lMomentOfInertia = getMomentOfInertia(pCircle); + const lAngularAcceleration = pCircle.torque / lMomentOfInertia; + pCircle.rotationVelocity += lAngularAcceleration * pDeltaTimeSeconds; + pCircle.rotationRadians += pCircle.rotationVelocity * pDeltaTimeSeconds; + pCircle.torque = 0; + + pCircle.model = rotateMatrix2d(translateMatrix(mat4(), pCircle.position.x, pCircle.position.y, 0), pCircle.rotationRadians); + } + + function update(pDeltaTimeSeconds) { + pDeltaTimeSeconds = pDeltaTimeSeconds * lTimeStepScale; + updateCircle(horizontalCircle, pDeltaTimeSeconds); + updateCircle(verticalCircle, pDeltaTimeSeconds); + collision(pDeltaTimeSeconds); + render(); + } + + function collision(pDeltaTimeSeconds) { + if (!doCirclesIntersect(horizontalCircle, verticalCircle)) { + return false; + } + + // We have an intersection! Let's try and figure out precisely when that happened. + let lSubdividedDeltaTime = pDeltaTimeSeconds; + let lSubdivideHorizontalBall = undefined, + lSubdivideVerticalBall = undefined; + + do { + lSubdivideHorizontalBall = JSON.parse(JSON.stringify(horizontalCircle)); + lSubdivideHorizontalBall.position = {...horizontalCircle.prevPos}; + lSubdivideHorizontalBall.velocity = {...horizontalCircle.prevVelocity}; + + lSubdivideVerticalBall = JSON.parse(JSON.stringify(verticalCircle)); + lSubdivideVerticalBall.position = {...verticalCircle.prevPos}; + lSubdivideVerticalBall.velocity = {...verticalCircle.prevVelocity}; + + lSubdividedDeltaTime = lSubdividedDeltaTime / 2.0; + updateCircle(lSubdivideHorizontalBall, lSubdividedDeltaTime); + updateCircle(lSubdivideVerticalBall, lSubdividedDeltaTime); + + if (lSubdividedDeltaTime === 0) { + console.error('This should NOT be happening'); + break; + } + } while (doCirclesIntersect(lSubdivideHorizontalBall, lSubdivideVerticalBall)) + + const lIntersectionResult = getIntersectionDataForCircles(lSubdivideHorizontalBall, lSubdivideVerticalBall); + + console.log('We have a collision'); + const lRelativeVelocity = lIntersectionResult.relativeVelocity, + lCollisionNormal = lIntersectionResult.collisionNormal, + lFirstPerp = getPerp2(lIntersectionResult.firstPointOfApplication), + lSecondPerp = getPerp2(lIntersectionResult.secondPointOfApplication); + + const lNumerator = dot2(scaleVec2(lRelativeVelocity, -(1.0 + COF_OF_RESTITUITION)), lCollisionNormal); + const lLinearDenomPart = dot2(lCollisionNormal, (scaleVec2(lCollisionNormal, 1 / horizontalCircle.mass + 1 / verticalCircle.mass))); + const lRotationalDenomPart = (Math.pow(dot2(lFirstPerp, lCollisionNormal), 2) / getMomentOfInertia(horizontalCircle)) + + (Math.pow(dot2(lSecondPerp, lCollisionNormal), 2) / getMomentOfInertia(verticalCircle)) + + const lImpulseMagnitude = lNumerator / (lLinearDenomPart + lRotationalDenomPart); + + horizontalCircle.position = lSubdivideHorizontalBall.position; + verticalCircle.position = lSubdivideVerticalBall.position; + + horizontalCircle.velocity = addVec2(horizontalCircle.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / horizontalCircle.mass)); + verticalCircle.velocity = subVec2(verticalCircle.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / verticalCircle.mass)); + + horizontalCircle.rotationVelocity = horizontalCircle.rotationVelocity + dot2(lFirstPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / getMomentOfInertia(horizontalCircle); + verticalCircle.rotationVelocity = verticalCircle.rotationVelocity - dot2(lSecondPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / getMomentOfInertia(verticalCircle); + + updateCircle(horizontalCircle, pDeltaTimeSeconds - lSubdividedDeltaTime); + updateCircle(verticalCircle, pDeltaTimeSeconds - lSubdividedDeltaTime); + + return true; + } + + function render() { + lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); + lProgramContext.gl.clearDepth(1.0); + lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST); + lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL); + lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT); + lProgramContext.gl.useProgram(pProgramInfo.program); + lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective); + + renderCircle(lProgramContext.gl, pProgramInfo, horizontalCircle); + renderCircle(lProgramContext.gl, pProgramInfo, verticalCircle); + } + + const TORQUE_MULTIPLIER = 100.0; // TODO: This may be unncessary + function applyForce(pCircle, pForceVector, pPointOfApplication) { + if (pPointOfApplication !== undefined) { + const lOriginToPointOfApp = subVec2(vec2(), pPointOfApplication), + lPerpVec = vec2(-lOriginToPointOfApp.y, lOriginToPointOfApp.x); + + pCircle.torque += TORQUE_MULTIPLIER * dot2(lPerpVec, pForceVector); + } + + pCircle.force = addVec2(pCircle.force, pForceVector); + } + + function cleanup() { + lProgramContext.gl.deleteBuffer(horizontalCircle.buffer); + lProgramContext.gl.deleteBuffer(verticalCircle.buffer); + lProgramContext.gl.deleteProgram(pProgramInfo.program); + lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); + lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); + } + + function reset() { + lExitRequestFunc(); + lProgramContext.reset(); + $('#time_step_slider').unbind('change'); + } + + const lExitRequestFunc = requestUpdateLoop(update, cleanup); + lProgramContext.stopButton.on('click', reset); + $('#time_step_slider').on('change', function() { lTimeStepScale = $(this).val(); }); + }); + } + + lProgramContext.playButton.on('click', run); + } + + $(document).ready(main); +})() \ No newline at end of file diff --git a/frontend/_rigidbody/rigidbody_3b.js b/frontend/_rigidbody/rigidbody_3b.js new file mode 100644 index 0000000..df81582 --- /dev/null +++ b/frontend/_rigidbody/rigidbody_3b.js @@ -0,0 +1,192 @@ +/// +/// +/// +/// +/// +/// + +(function() { + // Define Constants + const GRAVITY = 50.0; + const COF_OF_RESTITUITION = 0.2; + + var lProgramContext = undefined; + + function main() { + lProgramContext = getContext('#rigidbody_3b'); + + if (lProgramContext.gl === null) { + console.error('Unable to initialize WebGL. Your browser or machine may not support it.'); + return; + } + + lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); + lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); + lProgramContext.playButton.on('click', run); + } + + function run() { + console.log('Running Rigid Body 3b'); + lProgramContext.load().then(function(pProgramInfo) { + const lNumHorizontalPegs = lProgramContext.width / 80.0, + lNumVerticalPegs = lProgramContext.height / 80.0, + lBall = circle(lProgramContext.gl, 16.0, 16, + [ { x: 1, y: 0, z: 0, w: 1 }, { x: 0, y: 1, z: 0, w: 1 }, { x: 0, y: 0, z: 1, w: 1 } ], + vec2(38 * 8, lProgramContext.height - 24.0), 10.0), + lPegList = []; + + lBall.velocity = vec2(0, -50.0); + + // Generate a peg. These pegs will NOT be updated, so that they + // dont' fall due to gravity. + for (let lRowIdx = 1; lRowIdx < lNumVerticalPegs - 1; lRowIdx++) { + for (let lColIdx = 0; lColIdx < lNumHorizontalPegs -1; lColIdx++) { + lPegList.push(circle(lProgramContext.gl, + 16.0, 16, + [ { x: 165.0 / 255.0, y: 42.0 / 255.0, z: 42.0 / 255.0, w: 1.0 }], + vec2((lColIdx + 1) * 80.0, lRowIdx * 80.0), + 10000 // Real big so it's almost negligble + )); + } + } + + function updateCircle(pCircle, pDeltaTimeSeconds) { + // Same physics updates from part 1 + applyForce(pCircle, vec2(0, -1.0 * (pCircle.mass * GRAVITY))); + const lCurrentAcceleration = scaleVec2(pCircle.force, 1.0 / pCircle.mass); + pCircle.prevVelocity = pCircle.velocity; + pCircle.velocity = addVec2(pCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds)); + pCircle.prevPos = { ...pCircle.position }; + pCircle.position = addVec2(pCircle.position, scaleVec2(pCircle.velocity, pDeltaTimeSeconds)); + pCircle.force = vec2(); + + // Same physics updates from part 2 + + const lMomentOfInertia = getMomentOfInertia(pCircle); + const lAngularAcceleration = pCircle.torque / lMomentOfInertia; + pCircle.rotationVelocity += lAngularAcceleration * pDeltaTimeSeconds; + pCircle.rotationRadians += pCircle.rotationVelocity * pDeltaTimeSeconds; + pCircle.torque = 0; + + pCircle.model = rotateMatrix2d(translateMatrix(mat4(), pCircle.position.x, pCircle.position.y, 0), pCircle.rotationRadians); + } + + function update(pDeltaTimeSeconds) { + updateCircle(lBall, pDeltaTimeSeconds); + collision(pDeltaTimeSeconds); + render(); + } + + function collision(pDeltaTimeSeconds) { + for (let lPegIdx = 0; lPegIdx < lPegList.length; lPegIdx++) { + const lPeg = lPegList[lPegIdx]; + + if (!doCirclesIntersect(lPeg, lBall)) { + continue; + } + + // We have an intersection! Let's try and figure out precisely when that happened. + let lSubdividedDeltaTime = pDeltaTimeSeconds; + + // Create a ball and move it back to the balls previous position + let lSubdividedBall = undefined; + + do { + // Move the subdivided ball back to the previous position, and then + // advance its position by increasingly smaller timestep. This could be pretty + // slow in some circumstances, and it most definitely does not prevent tunneling, + // but - for now - this is not so bad. + lSubdividedBall = JSON.parse(JSON.stringify(lBall)); + lSubdividedBall.position = {...lBall.prevPos}; + lSubdividedBall.velocity = {...lBall.prevVelocity}; + lSubdividedDeltaTime = lSubdividedDeltaTime / 2.0; + updateCircle(lSubdividedBall, lSubdividedDeltaTime); + if (lSubdividedDeltaTime === 0) { + console.error('This should NOT be happening'); + break; + } + } while (doCirclesIntersect(lPeg, lSubdividedBall)) + + // The ball is no longer intersecting at the time presented here. That means this is + // (nearly) the precise point of intersection. + + const lIntersectionResult = getIntersectionDataForCircles(lPeg, lSubdividedBall); + + console.log(lIntersectionResult); + + const lRelativeVelocity = lIntersectionResult.relativeVelocity, + lCollisionNormal = lIntersectionResult.collisionNormal, + lFirstPerp = getPerp2(lIntersectionResult.firstPointOfApplication), + lSecondPerp = getPerp2(lIntersectionResult.secondPointOfApplication); + + const lNumerator = dot2(scaleVec2(lRelativeVelocity, -(1.0 + COF_OF_RESTITUITION)), lCollisionNormal); + const lLinearDenomPart = dot2(lCollisionNormal, (scaleVec2(lCollisionNormal, 1 / lBall.mass))); + const lRotationalDenomPart = (Math.pow(dot2(lFirstPerp, lCollisionNormal), 2) / getMomentOfInertia(lPeg)) + + (Math.pow(dot2(lSecondPerp, lCollisionNormal), 2) / getMomentOfInertia(lBall)) + + const lImpulseMagnitude = lNumerator / (lLinearDenomPart + lRotationalDenomPart); + + lBall.position = lSubdividedBall.position; // Move the ball back to its proper subdivided position + lBall.velocity = subVec2(lBall.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / lBall.mass)); + lBall.rotationVelocity = lBall.rotationVelocity - dot2(lSecondPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / getMomentOfInertia(lBall); + + console.log(lBall.rotationVelocity); + + // Now we update in our new direction with the remaining time that we have left. + updateCircle(lBall, pDeltaTimeSeconds - lSubdividedDeltaTime); + + break; + } + } + + function render() { + lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); + lProgramContext.gl.clearDepth(1.0); + lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST); + lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL); + lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT); + lProgramContext.gl.useProgram(pProgramInfo.program); + lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective); + + lPegList.forEach(function(pCircle) { + renderCircle(lProgramContext.gl, pProgramInfo, pCircle); + }); + + renderCircle(lProgramContext.gl, pProgramInfo, lBall); + } + + const TORQUE_MULTIPLIER = 100.0; // TODO: This may be unncessary + function applyForce(pCircle, pForceVector, pPointOfApplication) { + if (pPointOfApplication !== undefined) { + const lOriginToPointOfApp = subVec2(vec2(), pPointOfApplication), + lPerpVec = vec2(-lOriginToPointOfApp.y, lOriginToPointOfApp.x); + + pCircle.torque += TORQUE_MULTIPLIER * dot2(lPerpVec, pForceVector); + } + + pCircle.force = addVec2(pCircle.force, pForceVector); + } + + function cleanup() { + lPegList.forEach(function(pCircle) { freeCircle(lProgramContext.gl, pCircle); }); + freeCircle(lProgramContext.gl, lBall); + + lProgramContext.gl.deleteProgram(pProgramInfo.program); + lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); + lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT); + } + + function reset() { + lExitRequestFunc(); + lProgramContext.reset(); + $('#time_step_slider').unbind('change'); + } + + const lExitRequestFunc = requestUpdateLoop(update, cleanup); + lProgramContext.stopButton.on('click', reset); + $('#time_step_slider').on('change', function() { lTimeStepScale = $(this).val(); }); + }); + } + + $(document).ready(main); +})() \ No newline at end of file diff --git a/frontend/dog-114-203766.png b/frontend/dog-114-203766.png deleted file mode 100644 index 1bed84f..0000000 Binary files a/frontend/dog-114-203766.png and /dev/null differ diff --git a/frontend/dog-120-203766.png b/frontend/dog-120-203766.png deleted file mode 100644 index 8630006..0000000 Binary files a/frontend/dog-120-203766.png and /dev/null differ diff --git a/frontend/dog-144-203766.png b/frontend/dog-144-203766.png deleted file mode 100644 index f99123a..0000000 Binary files a/frontend/dog-144-203766.png and /dev/null differ diff --git a/frontend/dog-152-203766.png b/frontend/dog-152-203766.png deleted file mode 100644 index c0e2c85..0000000 Binary files a/frontend/dog-152-203766.png and /dev/null differ diff --git a/frontend/dog-16-203766.png b/frontend/dog-16-203766.png deleted file mode 100644 index bed9af9..0000000 Binary files a/frontend/dog-16-203766.png and /dev/null differ diff --git a/frontend/dog-24-203766.png b/frontend/dog-24-203766.png deleted file mode 100644 index b70836f..0000000 Binary files a/frontend/dog-24-203766.png and /dev/null differ diff --git a/frontend/dog-32-203766.png b/frontend/dog-32-203766.png deleted file mode 100644 index 46b6f77..0000000 Binary files a/frontend/dog-32-203766.png and /dev/null differ diff --git a/frontend/dog-48-203766.png b/frontend/dog-48-203766.png deleted file mode 100644 index ba10a5b..0000000 Binary files a/frontend/dog-48-203766.png and /dev/null differ diff --git a/frontend/dog-512-203766.png b/frontend/dog-512-203766.png deleted file mode 100644 index 814c34e..0000000 Binary files a/frontend/dog-512-203766.png and /dev/null differ diff --git a/frontend/dog-57-203766.png b/frontend/dog-57-203766.png deleted file mode 100644 index 0ee3c44..0000000 Binary files a/frontend/dog-57-203766.png and /dev/null differ diff --git a/frontend/dog-64-203766.png b/frontend/dog-64-203766.png deleted file mode 100644 index d28a1be..0000000 Binary files a/frontend/dog-64-203766.png and /dev/null differ diff --git a/frontend/dog-72-203766.png b/frontend/dog-72-203766.png deleted file mode 100644 index 25c5c50..0000000 Binary files a/frontend/dog-72-203766.png and /dev/null differ diff --git a/frontend/favicon.ico b/frontend/favicon.ico deleted file mode 100644 index 7c96d7e..0000000 Binary files a/frontend/favicon.ico and /dev/null differ diff --git a/frontend/favicon/favicon.ico b/frontend/favicon/favicon.ico new file mode 100644 index 0000000..53a7c84 Binary files /dev/null and b/frontend/favicon/favicon.ico differ diff --git a/frontend/favicon/little-penguin-114-27563.png b/frontend/favicon/little-penguin-114-27563.png new file mode 100644 index 0000000..51730fa Binary files /dev/null and b/frontend/favicon/little-penguin-114-27563.png differ diff --git a/frontend/favicon/little-penguin-120-27563.png b/frontend/favicon/little-penguin-120-27563.png new file mode 100644 index 0000000..50b8538 Binary files /dev/null and b/frontend/favicon/little-penguin-120-27563.png differ diff --git a/frontend/favicon/little-penguin-144-27563.png b/frontend/favicon/little-penguin-144-27563.png new file mode 100644 index 0000000..39eedc2 Binary files /dev/null and b/frontend/favicon/little-penguin-144-27563.png differ diff --git a/frontend/favicon/little-penguin-152-27563.png b/frontend/favicon/little-penguin-152-27563.png new file mode 100644 index 0000000..f003d59 Binary files /dev/null and b/frontend/favicon/little-penguin-152-27563.png differ diff --git a/frontend/favicon/little-penguin-16-27563.png b/frontend/favicon/little-penguin-16-27563.png new file mode 100644 index 0000000..6e0581f Binary files /dev/null and b/frontend/favicon/little-penguin-16-27563.png differ diff --git a/frontend/favicon/little-penguin-24-27563.png b/frontend/favicon/little-penguin-24-27563.png new file mode 100644 index 0000000..2d047d3 Binary files /dev/null and b/frontend/favicon/little-penguin-24-27563.png differ diff --git a/frontend/favicon/little-penguin-32-27563.png b/frontend/favicon/little-penguin-32-27563.png new file mode 100644 index 0000000..1850a4a Binary files /dev/null and b/frontend/favicon/little-penguin-32-27563.png differ diff --git a/frontend/favicon/little-penguin-48-27563.png b/frontend/favicon/little-penguin-48-27563.png new file mode 100644 index 0000000..4ecf57a Binary files /dev/null and b/frontend/favicon/little-penguin-48-27563.png differ diff --git a/frontend/favicon/little-penguin-57-27563.png b/frontend/favicon/little-penguin-57-27563.png new file mode 100644 index 0000000..2ba0965 Binary files /dev/null and b/frontend/favicon/little-penguin-57-27563.png differ diff --git a/frontend/favicon/little-penguin-64-27563.png b/frontend/favicon/little-penguin-64-27563.png new file mode 100644 index 0000000..45b7595 Binary files /dev/null and b/frontend/favicon/little-penguin-64-27563.png differ diff --git a/frontend/favicon/little-penguin-72-27563.png b/frontend/favicon/little-penguin-72-27563.png new file mode 100644 index 0000000..9bea6de Binary files /dev/null and b/frontend/favicon/little-penguin-72-27563.png differ diff --git a/frontend/index.css b/frontend/index.css index 40c74bd..c8cc394 100644 --- a/frontend/index.css +++ b/frontend/index.css @@ -79,7 +79,7 @@ nav > a:hover { 100% { transform: rotate(360deg); } } -section > p { +article > p { padding-left: 2rem; padding-right: 2rem; } @@ -122,7 +122,7 @@ section > p { /* WebGL container styling from here on. */ -section .opengl_canvas_container { +article .opengl_canvas_container { position: relative; width: 100%; text-align: center; @@ -131,7 +131,7 @@ section .opengl_canvas_container { justify-content: center; } -section .opengl_canvas_container .play_button { +article .opengl_canvas_container .play_button { all: unset; font-size: 2rem; width: 128px; @@ -149,11 +149,11 @@ section .opengl_canvas_container .play_button { justify-content: center; } -section .opengl_canvas_container .play_button:hover { +article .opengl_canvas_container .play_button:hover { cursor: pointer; } -section .opengl_canvas_container .stop_button { +article .opengl_canvas_container .stop_button { all: unset; font-size: 1rem; background-color: red; @@ -167,14 +167,15 @@ section .opengl_canvas_container .stop_button { display: none; } -section .opengl_canvas_container .stop_button:hover { +article .opengl_canvas_container .stop_button:hover { cursor: pointer; } -section pre { +article pre { width: 90%; overflow-x: auto; padding-left: 2rem; + font-size: 0.9rem; } .opengl_canvas_sidebar { diff --git a/frontend/index.html b/frontend/index.html index 1694121..c62696d 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -7,6 +7,7 @@ Physics for Games +
@@ -19,34 +20,36 @@ 2D - Rotational Forces 2D - Collision Forces -
-

Introduction: Rigid Body Physics

-

- You're most likely here because you have some interest in the world of rigid body physics. Maybe you have some knowledge of rendering via OpenGL or Vulkan, - and you want to begin watching your up-until-now static scene come to life. Well, you're in the right place! In the course of this tutorial series I will walk - you through the entirety of a 2D rigid body physics system entirely in the web. All of this information will be extendable to other languages, but we will use - JavaScript and WebGL in these blog posts. Additionally, much of the information presented here can be extended to 3 dimensions, but 3D carries some complications - with it, that we will discuss in future blog posts. -

-

- In implementing a rigidy body physics system, we're primarily interested in two sub-fields of physics, namely dynamics and kinematics. Although I'm - far as can be from being an expert in either of these fields, I will explain - from a programmer's persepctive - what they mean to me: -

    -
  • - Kinematics is the study of how an object's movement changes over time. These are the classic position, velocity, and acceleration equations - that you're most likely familiar with from high school or college physics. -
  • -
  • - Dynamics is the study of whats causes kinematic movement. These are the classic force and momentum equations that you may already be familiar - with as well. -
  • -
-

-

- Finally, I must provide a disclaimer that all of rigid body systems are very math-y. You will need to know a decent amount of vector calculus and linear algebra to really understand - what's going on here. I am going to assume that you have this knowledge. If you don't already have this knowledge, I will try and provide some resources on the Books - n' References page of the website. -

+
+
+

Introduction: Rigid Body Physics

+

+ You're most likely here because you have some interest in the world of rigid body physics. Maybe you have some knowledge of rendering via OpenGL or Vulkan, + and you want to begin watching your up-until-now static scene come to life. Well, you're in the right place! In the course of this tutorial series I will walk + you through the entirety of a 2D rigid body physics system entirely in the web. All of this information will be extendable to other languages, but we will use + JavaScript and WebGL in these blog posts. Additionally, much of the information presented here can be extended to 3 dimensions, but 3D carries some complications + with it, that we will discuss in future blog posts. +

+

+ In implementing a rigidy body physics system, we're primarily interested in two sub-fields of physics, namely dynamics and kinematics. Although I'm + far as can be from being an expert in either of these fields, I will explain - from a programmer's persepctive - what they mean to me: +

    +
  • + Kinematics is the study of how an object's movement changes over time. These are the classic position, velocity, and acceleration equations + that you're most likely familiar with from high school or college physics. +
  • +
  • + Dynamics is the study of whats causes kinematic movement. These are the classic force and momentum equations that you may already be familiar + with as well. +
  • +
+

+

+ Finally, I must provide a disclaimer that all of rigid body systems are very math-y. You will need to know a decent amount of vector calculus and linear algebra to really understand + what's going on here. I am going to assume that you have this knowledge. If you don't already have this knowledge, I will try and provide some resources on the Books + n' References page of the website. +

+
diff --git a/frontend/index.js b/frontend/index.js index 0cbd896..f481bc6 100644 --- a/frontend/index.js +++ b/frontend/index.js @@ -1,10 +1,10 @@ /// -function main() { - console.log('Document ready.'); - const lPathName = window.location.pathname.length > 1 && window.location.pathname.startsWith('/') ? window.location.pathname.substr(1) : window.location.pathname; - console.log(lPathName); - $('nav').find('a[href="' + lPathName + '"').addClass('nav-selected'); -} - -$(document).ready(main); \ No newline at end of file +(function() { + function main() { + const lPathName = window.location.pathname.length > 1 && window.location.pathname.startsWith('/') ? window.location.pathname.substr(1) : window.location.pathname; + $('nav').find('a[href="' + lPathName + '"').addClass('nav-selected'); + } + + $(document).ready(main); +})() \ No newline at end of file diff --git a/frontend/readme.txt b/frontend/readme.txt deleted file mode 100644 index aa00c22..0000000 --- a/frontend/readme.txt +++ /dev/null @@ -1,26 +0,0 @@ -Thank you for downloading a favicon from Free Favicon! This favicon was created from an image at http://openclipart.org/ and converted to a favicon and other sizes for you to use in your projects. For more details about this image visit this page: https://openclipart.org/detail/203766/dog - -For more information about how you can use this image from OpenClipArt see this page: http://openclipart.org/may-clipart-be-used-comparison - -Here are the contents of this compressed package: - -* favicon.ico -- The favicon file (supports both 16*16 and 32*32 dimensions). You will need to rename this to favicon.ico and upload to your web site. - - * You can add a favicon to your web page by uploading favicon.ico to Root of your website and inserting the following HTML tag between the ... tags of your web page. - - - -* There are many different sized png files for use a icons for smartphones, tablets and desktop use. - -If you are having any problems installing your favicon we have tips on the Free Favicon blog. http://www.freefavicon.com/blog/ - -Thank you once again for download from Free Favicon! If you like your favicon we appreciate you taking the time to mention our service to others, blogging about us and of course by linking to us. - -We also encourage you to check out Backblaze online backup. We use Backblaze to backup our computers and keep our data safe. They offer a free 15 day trial and are the easiest online backup service we have used. - -Use this link http://www.freefavicon.com/blog/outgoing/backblaze.php to try Backblaze for Free! - -By signing up for Backblaze you help keep Free Favicon free! - -Thank you, -FreeFavicon.com \ No newline at end of file diff --git a/frontend/rigidbody.html b/frontend/rigidbody.html index d83e29e..f3616b5 100644 --- a/frontend/rigidbody.html +++ b/frontend/rigidbody.html @@ -15,7 +15,7 @@ - +
@@ -37,35 +37,6 @@

-
-

Introduction: Rigid Body Physics

-

- You're most likely here because you have some interest in the world of rigid body physics. Maybe you have some knowledge of rendering via OpenGL or Vulkan, - and you want to begin watching your up-until-now static scene come to life. Well, you're in the right place! In the course of this tutorial series I will walk - you through the entirety of a 2D rigid body physics system entirely in the web. All of this information will be extendable to other languages, but we will use - JavaScript and WebGL in these blog posts. Additionally, much of the information presented here can be extended to 3 dimensions, but 3D carries some complications - with it, that we will discuss in future blog posts. -

-

- In implementing a rigidy body physics system, we're primarily interested in two sub-fields of physics, namely dynamics and kinematics. Although I'm - far as can be from being an expert in either of these fields, I will explain - from a programmer's persepctive - what they mean to me: -

    -
  • - Kinematics is the study of how an object's movement changes over time. These are the classic position, velocity, and acceleration equations - that you're most likely familiar with from high school or college physics. -
  • -
  • - Dynamics is the study of whats causes kinematic movement. These are the classic force and momentum equations that you may already be familiar - with as well. -
  • -
-

-

- Finally, I must provide a disclaimer that all of rigid body systems are very math-y. You will need to know a decent amount of vector calculus and linear algebra to really understand - what's going on here. I am going to assume that you have this knowledge. If you don't already have this knowledge, I will try and provide some resources on the Books - n' References page of the website. -

-

Part 1: Linear Forces

@@ -172,7 +143,7 @@

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

-
+
-- cgit v1.2.1