From 026abdb98ad30209df0e88795f25b1f74556585e Mon Sep 17 00:00:00 2001 From: Matthew Kosarek Date: Thu, 25 Feb 2021 20:50:12 -0500 Subject: Updated the sidebar for usability's sake --- frontend/_rigidbody/2d/part_1.html | 93 ---------------- frontend/_rigidbody/2d/part_2.html | 66 ------------ frontend/_rigidbody/2d/part_3.html | 71 ------------ frontend/_rigidbody/2d/rigidbody_1.js | 117 -------------------- frontend/_rigidbody/2d/rigidbody_2.js | 146 ------------------------- frontend/_rigidbody/2d/rigidbody_3a.js | 190 --------------------------------- frontend/_rigidbody/2d/rigidbody_3b.js | 188 -------------------------------- 7 files changed, 871 deletions(-) delete mode 100644 frontend/_rigidbody/2d/part_1.html delete mode 100644 frontend/_rigidbody/2d/part_2.html delete mode 100644 frontend/_rigidbody/2d/part_3.html delete mode 100644 frontend/_rigidbody/2d/rigidbody_1.js delete mode 100644 frontend/_rigidbody/2d/rigidbody_2.js delete mode 100644 frontend/_rigidbody/2d/rigidbody_3a.js delete mode 100644 frontend/_rigidbody/2d/rigidbody_3b.js (limited to 'frontend/_rigidbody/2d') 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 @@ - - - - - - - - - - Physics for Games - - - - - - - - - -
-

Physics for Games

-
-
- -
-

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/_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 @@ - - - - - - - - - - Physics for Games - - - - - - - - - -
-

Physics for Games

-
-
- -
-

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
  • -
-
-
- - - -
-
- - - -
- -
-
- - -
-
-
-
- - \ 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 @@ - - - - - - - - - - Physics for Games - - - - - - - - - - -
-

Physics for Games

-
-
- -
-

Part 3: Collisions

-
-

Implementation

-

- 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. -

-
- -
-
- - -
-
- - -
-
-
-

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. -

-
- -
- -
- - -
-
-
-
- - \ 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 @@ -/// -/// -/// -/// -/// -/// - -(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 @@ -/// -/// -/// -/// -/// -/// - -(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 @@ -/// -/// -/// -/// -/// -/// - -(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 @@ -/// -/// -/// -/// -/// -/// - -(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 -- cgit v1.2.1