///
///
///
///
///
///
///
///
(function() {
var programContext,
rectangleObject,
lineObjectList,
programInfo,
exitRequestFunc;
function main() {
programContext = getContext('#rectangle_line_collision');
if (programContext.gl === null) {
console.error('Unable to initialize WebGL. Your browser or machine may not support it.');
return;
}
programContext.gl.clearColor(0.1, 0.15, 0.2, 1.0);
programContext.gl.clear(programContext.gl.COLOR_BUFFER_BIT);
programContext.playButton.on('click', run);
}
function run() {
console.log('Running Rectangle-Line Collisions');
programContext.load().then(function(pProgramInfo) {
programInfo = pProgramInfo;
rectangleObject = rectangle(programContext.gl, {
width: 50,
height: 50,
mass: 1,
color: { x: 0.3, y: 0.5, z: 0.1, w: 0.7 },
position: vec2(programContext.width / 2.0 - 100, programContext.height / 2.0 + 100)
});
rectangleObject.velocity = vec2(0, -50);
lineObjectList = [];
lineObjectList.push(line2({ x: 100, y: 100 }, { x: programContext.width - 100, y: 200 }, programContext.gl,
{ x: 1, y: 0, z: 0, w: 1 }, 10000000.0));
lineObjectList.push(line2({ x: 100, y: 200 }, { x: programContext.width - 100, y: 100 }, programContext.gl,
{ x: 1, y: 1, z: 0, w: 1 }, 10000000.0));
lineObjectList.push(line2({ x: 100, y: 0 }, { x: 100, y: programContext.height }, programContext.gl,
{ x: 0, y: 1, z: 0, w: 1 }, 10000000.0));
lineObjectList.push(line2({ x: programContext.width - 100, y: 0 }, { x: programContext.width - 100, y: programContext.height }, programContext.gl,
{ x: 0, y: 1, z: 0, w: 1 }, 10000000.0));
exitRequestFunc = requestUpdateLoop(update, cleanup);
programContext.stopButton.on('click', reset);
});
}
function update(pDeltaTimeSeconds) {
pDeltaTimeSeconds = pDeltaTimeSeconds;
updateRigidBody2(rectangleObject, pDeltaTimeSeconds);
collision(pDeltaTimeSeconds);
render();
}
function collision(pDeltaTimeSeconds) {
for (var lineIdx = 0; lineIdx < lineObjectList.length; lineIdx++) {
var lLine = lineObjectList[lineIdx];
if (areIntersecting(rectangleObject, lLine, pDeltaTimeSeconds)) {
break;
}
}
}
function doesPointIntersect(pPoint, pLine) {
const EPSILON = 0.98;
return distanceFromPoint2ToLine2(pPoint, pLine) <= EPSILON;
}
function getIntersectionInformation(pRectangle, pCollisionPoint, pLine) {
var lCollisionNormal = pLine.normal,
lRectCollisionPoint_WorldCoords = multMat4ByVec2(pRectangle.model, pCollisionPoint),
lRectPosition = pRectangle.position,
lTrueRectCollisionPoint = normalize2(subVec2(lRectPosition, lRectCollisionPoint_WorldCoords));
console.log(lTrueRectCollisionPoint);
return {
relativeVelocity: subVec2(pRectangle.velocity, pLine.velocity),
collisionNormal: lCollisionNormal,
rectangleCollisionPoint: lTrueRectCollisionPoint
}
}
function areIntersecting(pRectangle, pLine, pDeltaTimeSeconds) {
var lCollisionPoint = undefined,
lCheckCollision = function(pRectangle) {
var lLowerLeft = multMat4ByVec2(pRectangle.model, vec2(-pRectangle.width / 2.0, -pRectangle.height / 2.0)),
lUpperLeft = multMat4ByVec2(pRectangle.model, vec2(-pRectangle.width / 2.0, pRectangle.height / 2.0)),
lUpperRight = multMat4ByVec2(pRectangle.model, vec2(pRectangle.width / 2.0, pRectangle.height / 2.0)),
lLowerRight = multMat4ByVec2(pRectangle.model, vec2(pRectangle.width / 2.0, -pRectangle.height / 2.0));
if (doesPointIntersect(lLowerLeft, pLine)) {
lCollisionPoint = vec2(-pRectangle.width / 2.0, -pRectangle.height / 2.0);
return true;
} else if (doesPointIntersect(lUpperLeft, pLine)) {
lCollisionPoint = vec2(-pRectangle.width / 2.0, pRectangle.height / 2.0);
return true;
} else if (doesPointIntersect(lUpperRight, pLine)) {
lCollisionPoint = vec2(pRectangle.width / 2.0, pRectangle.height / 2.0);
return true;
} else if (doesPointIntersect(lLowerRight, pLine)) {
lCollisionPoint = vec2(pRectangle.width / 2.0, -pRectangle.height / 2.0);
return true;
}
return false;
};
if (!lCheckCollision(pRectangle)) {
return;
}
// Subdivide until we find the exact moment where we intersected
var lSubdividedDeltaTime = pDeltaTimeSeconds,
lSubRectangle = undefined;
do {
lSubRectangle = JSON.parse(JSON.stringify(pRectangle));
lSubRectangle.position = {...pRectangle.prevPos};
lSubRectangle.velocity = {...pRectangle.prevVelocity};
lSubRectangle.getMomentOfInertia = pRectangle.getMomentOfInertia;
lSubdividedDeltaTime = lSubdividedDeltaTime / 2.0;
updateRigidBody2(lSubRectangle, lSubdividedDeltaTime);
if (lSubdividedDeltaTime === 0) {
console.error('This should NOT be happening');
break;
}
} while (lCheckCollision(lSubRectangle));
var lIntersectionResult = getIntersectionInformation(lSubRectangle, lCollisionPoint, pLine),
lRelativeVelocity = lIntersectionResult.relativeVelocity,
lCollisionNormal = lIntersectionResult.collisionNormal,
lRectPerp = getPerp2(lIntersectionResult.rectangleCollisionPoint);
const lNumerator = dot2(scaleVec2(lRelativeVelocity, -(1.0 + 1.0)), lCollisionNormal);
const lLinearDenomPart = dot2(lCollisionNormal, (scaleVec2(lCollisionNormal, 1.0 / pRectangle.mass)));
const lRotationalDenomPart = (Math.pow(dot2(lRectPerp, lCollisionNormal), 2) / pRectangle.getMomentOfInertia());
const lImpulseMagnitude = lNumerator / (lLinearDenomPart + lRotationalDenomPart);
pRectangle.position = lSubRectangle.position;
pRectangle.velocity = addVec2(lSubRectangle.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / pRectangle.mass));
pRectangle.rotationVelocity = lSubRectangle.rotationVelocity + dot2(lRectPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / pRectangle.getMomentOfInertia();
updateRigidBody2(pRectangle, pDeltaTimeSeconds - lSubdividedDeltaTime);
return true;
}
function render() {
programContext.gl.clearColor(0.1, 0.15, 0.2, 1.0);
programContext.gl.clearDepth(1.0);
programContext.gl.enable(programContext.gl.DEPTH_TEST);
programContext.gl.depthFunc(programContext.gl.LEQUAL);
programContext.gl.clear(programContext.gl.COLOR_BUFFER_BIT | programContext.gl.DEPTH_BUFFER_BIT);
programContext.gl.useProgram(programInfo.program);
programContext.gl.uniformMatrix4fv(programInfo.uniformLocations.projection, false, programContext.perspective);
programInfo.renderShape(rectangleObject);
lineObjectList.forEach(function(lineObject) {
renderLine2(programContext.gl, programInfo, lineObject);
});
}
function cleanup() {
programContext.gl.deleteBuffer(rectangleObject.buffer);
lineObjectList.forEach(function(lineObject) {
programContext.gl.deleteBuffer(lineObject.buffer);
});
programContext.gl.deleteProgram(programInfo.program);
programContext.gl.clearColor(0.1, 0.15, 0.2, 1.0);
programContext.gl.clear(programContext.gl.COLOR_BUFFER_BIT);
}
function reset() {
exitRequestFunc();
programContext.reset();
}
$(document).ready(main);
})()