diff options
Diffstat (limited to 'frontend/_rigidbody/2d')
-rw-r--r-- | frontend/_rigidbody/2d/part_1.html | 93 | ||||
-rw-r--r-- | frontend/_rigidbody/2d/part_2.html | 66 | ||||
-rw-r--r-- | frontend/_rigidbody/2d/part_3.html | 71 | ||||
-rw-r--r-- | frontend/_rigidbody/2d/rigidbody_1.js | 117 | ||||
-rw-r--r-- | frontend/_rigidbody/2d/rigidbody_2.js | 146 | ||||
-rw-r--r-- | frontend/_rigidbody/2d/rigidbody_3a.js | 190 | ||||
-rw-r--r-- | frontend/_rigidbody/2d/rigidbody_3b.js | 188 |
7 files changed, 0 insertions, 871 deletions
diff --git a/frontend/_rigidbody/2d/part_1.html b/frontend/_rigidbody/2d/part_1.html deleted file mode 100644 index ec0acbf..0000000 --- a/frontend/_rigidbody/2d/part_1.html +++ /dev/null @@ -1,93 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8"> - <script src="/scripts/jquery-3.5.1.min.js"></script> - <script src="/index.js"></script> - <link rel="stylesheet" href="/index.css"> - <link rel="shortcut icon" href="/favicon/favicon.ico" type="image/x-icon"> - <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,300" rel="stylesheet" type="text/css"> - <title>Physics for Games</title> - - <script src="/_shared/math/vec2.js"></script> - <script src="/_shared/math/mat4.js"></script> - <script src="/_shared/math/circle.js"></script> - <script src="/_shared/2d/shader.js"></script> - <script src="/_shared/2d/program_common.js"></script> - <script src="rigidbody_1.js"></script> - </head> - <body> - <header> - <h1>Physics for Games</h1> - </header> - <main> - <nav> - </nav> - <section> - <h1>Part 1: Linear Forces</h1> - <article> - <p> - 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. - </p> - <p> - Let's begin by recalling the relationships between acceleration, velocity, and position. - </p> - <p> - Knowing all this, you should be able to understand the following source code fairly easily; - <pre> - <code> - <span class="code_keyword">function</span> update(dtSeconds) { - <span class="code_comment">// Add up the forces acting on the circle</span> - <span class="code_keyword">const</span> GRAVITY = 9.8; - <span class="code_keyword">const</span> lGravityForce = vec2(0, -1.0 * (lCircle.mass * <span class="code_constant">GRAVITY</span>)); - lCircle.force = addVec2(lCircle.force, lGravityForce); - - <span class="code_comment">// Figure out acceleration (a = F / m)</span> - <span class="code_keyword">const</span> lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass); - - <span class="code_comment">// Calculate the new velocity: v = v0 + a * t</span> - lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, dtSeconds)); - - <span class="code_comment">// Update the position based on velocity: x = x0 + v * t</span> - lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, dtSeconds)); - - <span class="code_comment">// Update the model matrix accordingly</span> - lCircle.model = translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0); - - <span class="code_comment">// Reset the force vector for the next update</span> - lCircle.force = vec2() - } - </code> - </pre> - </p> - <div id="rigidbody_1" class="opengl_canvas_container"> - <canvas width="640" height="480"></canvas> - <div class="opengl_canvas_sidebar"> - <ul class="opengl_value_tracker"> - <li><b>Linear Force:</b><span id="rigidbody_1_force_field">N/A</span></li> - <li><b>Linear Acceleration:</b><span id="rigidbody_1_acceleration_field">N/A</span></li> - <li><b>Linear Velocity:</b><span id="rigidbody_1_velocity_field">N/A</span></li> - <li><b>Linear Position:</b><span id="rigidbody_1_position_field">N/A</span></li> - </ul> - <form id="rigidbody_1_force_submit_button" style="text-align: right; padding: 0.5rem;"> - <div class="vec2_input_group"> - <label>Force Vector</label> - <input class="vec2_x_input" type="number" placeholder="X (Default 0)"/> - <input class="vec2_y_input" type="number" placeholder="Y (Default 5000 N)"/> - </div> - <input type="submit" value="Apply Force"></input> - </form> - </div> - <button class="play_button"> - Play - </button> - <button class="stop_button"> - Stop - </button> - </div> - </article> - </section> - </main> - </body> -</html>
\ No newline at end of file diff --git a/frontend/_rigidbody/2d/part_2.html b/frontend/_rigidbody/2d/part_2.html deleted file mode 100644 index 0291290..0000000 --- a/frontend/_rigidbody/2d/part_2.html +++ /dev/null @@ -1,66 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8"> - <script src="/scripts/jquery-3.5.1.min.js"></script> - <script src="/index.js"></script> - <link rel="stylesheet" href="/index.css"> - <link rel="shortcut icon" href="/favicon/favicon.ico" type="image/x-icon"> - <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,300" rel="stylesheet" type="text/css"> - <title>Physics for Games</title> - - <script src="/_shared/math/vec2.js"></script> - <script src="/_shared/math/mat4.js"></script> - <script src="/_shared/math/circle.js"></script> - <script src="/_shared/2d/shader.js"></script> - <script src="/_shared/2d/program_common.js"></script> - <script src="rigidbody_2.js"></script> - </head> - <body> - <header> - <h1>Physics for Games</h1> - </header> - <main> - <nav> - </nav> - <section> - <h1>Part 2: Rotational Forces</h1> - <article> - <p> - 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. - </p> - <div id="rigidbody_2" class="opengl_canvas_container"> - <canvas width="640" height="480"></canvas> - <div class="opengl_canvas_sidebar"> - <ul class="opengl_value_tracker"> - <li><b>Angular Force:</b><span id="rigidbody_2_force_field">N/A</span></li> - <li><b>Angular Acceleration:</b><span id="rigidbody_2_acceleration_field">N/A</span></li> - <li><b>Angular Velocity:</b><span id="rigidbody_2_velocity_field">N/A</span></li> - <li><b>Angular Position:</b><span id="rigidbody_2_position_field">N/A</span></li> - </ul> - <form id="rigidbody_2_force_submit_button" style="text-align: right; padding: 0.5rem;"> - <div id="rigidbody_2_force_input" class="vec2_input_group"> - <label>Force Vector</label> - <input class="vec2_x_input" type="number" placeholder="X (Default 0)"/> - <input class="vec2_y_input" type="number" placeholder="Y (Default 5000 N)"/> - </div> - <div id="rigidbody_2_position_input" class="vec2_input_group"> - <label>Point of Application (Unit Vector)</label> - <input class="vec2_x_input" type="number" placeholder="X (Default 2 Root 2)"/> - <input class="vec2_y_input" type="number" placeholder="Y (Default 2 Root 2)"/> - </div> - <input type="submit" value="Apply Force"></input> - </form> - </div> - <button class="play_button"> - Play - </button> - <button class="stop_button"> - Stop - </button> - </div> - </article> - </section> - </main> - </body> -</html>
\ No newline at end of file diff --git a/frontend/_rigidbody/2d/part_3.html b/frontend/_rigidbody/2d/part_3.html deleted file mode 100644 index c1479da..0000000 --- a/frontend/_rigidbody/2d/part_3.html +++ /dev/null @@ -1,71 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8"> - <script src="../../scripts/jquery-3.5.1.min.js"></script> - <script src="../../index.js"></script> - <link rel="stylesheet" href="../../index.css"> - <link rel="shortcut icon" href="../../favicon/favicon.ico" type="image/x-icon"> - <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,300" rel="stylesheet" type="text/css"> - <title>Physics for Games</title> - - <script src="/_shared/math/vec2.js"></script> - <script src="/_shared/math/mat4.js"></script> - <script src="/_shared/math/circle.js"></script> - <script src="/_shared/2d/shader.js"></script> - <script src="/_shared/2d/program_common.js"></script> - <script src="rigidbody_3a.js"></script> - <script src="rigidbody_3b.js"></script> - </head> - <body> - <header> - <h1>Physics for Games</h1> - </header> - <main> - <nav> - </nav> - <section> - <h1>Part 3: Collisions</h1> - <article> - <h2>Implementation</h2> - <p> - 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. - </p> - <div id="rigidbody_3a" class="opengl_canvas_container"> - <canvas width="640" height="480"></canvas> - <div class="opengl_canvas_sidebar"> - <div class="slider_container"> - <label for="time_step_slider">Time Step</label> - <input type="range" min="0.1" max="1.0" value="1.0" step="0.1" class="slider" id="time_step_slider"> - </div> - </div> - <button class="play_button"> - Play - </button> - <button class="stop_button"> - Stop - </button> - </div> - </article> - <article> - <h2>Plinko Game</h2> - <p> - 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. - </p> - <div id="rigidbody_3b" class="opengl_canvas_container"> - <canvas width="640" height="480"></canvas> - <div class="opengl_canvas_sidebar"> - - </div> - <button class="play_button"> - Play - </button> - <button class="stop_button"> - Stop - </button> - </div> - </article> - </section> - </main> - </body> -</html>
\ No newline at end of file diff --git a/frontend/_rigidbody/2d/rigidbody_1.js b/frontend/_rigidbody/2d/rigidbody_1.js deleted file mode 100644 index e49c7c9..0000000 --- a/frontend/_rigidbody/2d/rigidbody_1.js +++ /dev/null @@ -1,117 +0,0 @@ -/// <reference path="../../scripts/jquery-3.5.1.min.js"/> -/// <reference path="../../_shared/math/vec2.js" /> -/// <reference path="../../_shared/math/mat4.js" /> -/// <reference path="../../_shared/2d/shader.js" /> -/// <reference path="../../_shared/math/circle.js" /> -/// <reference path="../../_shared/2d/program_common.js" /> - -(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); - } - - 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))); - } - - 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); - - } - - $(document).ready(main); -})()
\ No newline at end of file diff --git a/frontend/_rigidbody/2d/rigidbody_2.js b/frontend/_rigidbody/2d/rigidbody_2.js deleted file mode 100644 index 4632b11..0000000 --- a/frontend/_rigidbody/2d/rigidbody_2.js +++ /dev/null @@ -1,146 +0,0 @@ -/// <reference path="../../scripts/jquery-3.5.1.min.js"/> -/// <reference path="../../_shared/math/vec2.js" /> -/// <reference path="../../_shared/math/mat4.js" /> -/// <reference path="../../_shared/2d/shader.js" /> -/// <reference path="../../_shared/math/circle.js" /> -/// <reference path="../../_shared/2d/program_common.js" /> - -(function() { - 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 - - // 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; - } - - 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); - } - - $(document).ready(main); -})()
\ No newline at end of file diff --git a/frontend/_rigidbody/2d/rigidbody_3a.js b/frontend/_rigidbody/2d/rigidbody_3a.js deleted file mode 100644 index d38f1da..0000000 --- a/frontend/_rigidbody/2d/rigidbody_3a.js +++ /dev/null @@ -1,190 +0,0 @@ -/// <reference path="../../scripts/jquery-3.5.1.min.js"/> -/// <reference path="../../_shared/math/vec2.js" /> -/// <reference path="../../_shared/math/mat4.js" /> -/// <reference path="../../_shared/2d/shader.js" /> -/// <reference path="../../_shared/math/circle.js" /> -/// <reference path="../../_shared/2d/program_common.js" /> - -(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/2d/rigidbody_3b.js b/frontend/_rigidbody/2d/rigidbody_3b.js deleted file mode 100644 index 803161a..0000000 --- a/frontend/_rigidbody/2d/rigidbody_3b.js +++ /dev/null @@ -1,188 +0,0 @@ -/// <reference path="../../scripts/jquery-3.5.1.min.js"/> -/// <reference path="../../_shared/math/vec2.js" /> -/// <reference path="../../_shared/math/mat4.js" /> -/// <reference path="../../_shared/2d/shader.js" /> -/// <reference path="../../_shared/math/circle.js" /> -/// <reference path="../../_shared/2d/program_common.js" /> - -(function() { - // Define Constants - const GRAVITY = 50.0; - const COF_OF_RESTITUITION = 0.9; - - 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 = 0; lRowIdx < lNumVerticalPegs - 1; lRowIdx++) { - for (let lColIdx = 0; lColIdx <= lNumHorizontalPegs; 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((lRowIdx % 2 ? 40 : 0) + (lColIdx) * 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); - - 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); - - // 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 |