Skip to content

Commit

Permalink
Implement roll function using quaternions
Browse files Browse the repository at this point in the history
  • Loading branch information
rohanjulka19 committed Jun 15, 2024
1 parent 89fea5c commit de8708d
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 20 deletions.
1 change: 1 addition & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ import './webgl/p5.Camera';
import './webgl/p5.DataArray';
import './webgl/p5.Geometry';
import './webgl/p5.Matrix';
import './webgl/p5.Quat';
import './webgl/p5.RendererGL.Immediate';
import './webgl/p5.RendererGL';
import './webgl/p5.RendererGL.Retained';
Expand Down
59 changes: 39 additions & 20 deletions src/webgl/p5.Camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -2461,11 +2461,22 @@ p5.Camera = class Camera {
}

/**
* Rolling rotates the camera view in forward direction.
* Rotates the camera in a clockwise/counter-clockwise direction.
*
* Rolling rotates the camera without changing its orientation. The rotation
* happens in the camera’s "local" space.
*
* The parameter, `angle`, is the angle the camera should rotate. Passing a
* positive angle, as in `myCamera.pan(0.001)`, rotates the camera in clockwise direction.
* Passing a negative angle, as in `myCamera.pan(-0.001)`, rotates the
* camera in clockwise direction.
*
* Note: Angles are interpreted based on the current
* <a href="#/p5/angleMode">angleMode()</a>.
*
* @method roll
* @param {Number} angle amount to rotate camera in current
* <a href="#/p5/angleMode">angleMode</a> units.
* Greater than 0 values rotate counterclockwise (to the left).
* @example
* <div>
* <code>
Expand All @@ -2475,47 +2486,55 @@ p5.Camera = class Camera {
* function setup() {
* createCanvas(100, 100, WEBGL);
* normalMaterial();
* // Create a p5.Camera object.
* cam = createCamera();
* // set initial pan angle
* cam.roll(-0.8);
* }
*
* function draw() {
* background(200);
*
* // pan camera according to angle 'delta'
* // Roll camera according to angle 'delta'
* cam.roll(delta);
*
* // every 160 frames, switch direction
* if (frameCount % 160 === 0) {
* delta *= -1;
* }
*
* rotateX(frameCount * 0.01);
* translate(0, 0, -100);
* translate(0, 0, 0);
* box(20);
* translate(0, 0, 35);
* translate(0, 25, 0);
* box(20);
* translate(0, 0, 35);
* translate(0, 26, 0);
* box(20);
* translate(0, 0, 35);
* translate(0, 27, 0);
* box(20);
* translate(0, 0, 35);
* translate(0, 28, 0);
* box(20);
* translate(0, 0, 35);
* translate(0,29, 0);
* box(20);
* translate(0, 0, 35);
* translate(0, 30, 0);
* box(20);
* }
* </code>
* </div>
*
* @alt
* camera view pans in forward direction across a series boxes.
* camera view rotates in counter clockwise direction with vertically stacked boxes in front of it.
*/
roll(amount) {
const local = this._getLocalAxes();
this._rotateView(amount, local.z[0], local.z[1], local.z[2]);
const axisQuaternion = p5.Quat.fromAxisAngle(
this._renderer._pInst._toRadians(amount),
local.z[0], local.z[1], local.z[2]);
const upQuat = new p5.Quat(0, this.upX, this.upY, this.upZ);
const newUpVector = upQuat.rotateBy(axisQuaternion);
this.camera(
this.eyeX,
this.eyeY,
this.eyeZ,
this.centerX,
this.centerY,
this.centerZ,
newUpVector.x,
newUpVector.y,
newUpVector.z
);
}

/**
Expand Down
71 changes: 71 additions & 0 deletions src/webgl/p5.Quat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import p5 from '../core/main';

/**
* A class to describe a Quaternion
* for vector rotations in the p5js webgl renderer.
* @class p5.Quat
* @constructor
* @param {Number} [w] Scalar part of the quaternion
* @param {Number} [x] x component of imaginary part of quaternion
* @param {Number} [y] y component of imaginary part of quaternion
* @param {Number} [z] z component of imaginary part of quaternion
*/
p5.Quat = class {
constructor(w, x, y, z) {
this.w = w;
this.vec = new p5.Vector(x, y, z);
}

/**
* Returns a Quaternion for the
* axis angle representation of the rotation
*
* @method fromAxisAngle
* @param {Number} [angle] Angle with which the points needs to be rotated
* @param {Number} [x] x component of the axis vector
* @param {Number} [y] y component of the axis vector
* @param {Number} [z] z component of the axis vector
* @chainable
*/
static fromAxisAngle(angle, x, y, z) {
const w = Math.cos(angle/2);
const vec = new p5.Vector(x, y, z).normalize().mult(Math.sin(angle/2));
return new p5.Quat(w, vec.x, vec.y, vec.z);
}

conjugate() {
return new p5.Quat(this.w, -this.vec.x, -this.vec.y, -this.vec.z);
}

/**
* Multiplies a quaternion with other quaternion.
* @method mult
* @param {p5.Quat} [quat] quaternion to multiply with the quaternion calling the method.
* @chainable
*/
multiply(quat) {
/* eslint-disable max-len */
return new p5.Quat(
this.w * quat.w - this.vec.x * quat.vec.x - this.vec.y * quat.vec.y - this.vec.z - quat.vec.z,
this.w * quat.vec.x + this.vec.x * quat.w + this.vec.y * quat.vec.z - this.vec.z * quat.vec.y,
this.w * quat.vec.y - this.vec.x * quat.vec.z + this.vec.y * quat.w + this.vec.z * quat.vec.x,
this.w * quat.vec.z + this.vec.x * quat.vec.y - this.vec.y * quat.vec.x + this.vec.z * quat.w
);
/* eslint-enable max-len */
}

/**
* Rotates the Quaternion by the quaternion passed
* which contains the axis of roation and angle of rotation
*
* @method rotateBy
* @param {p5.Quat} [axesQuat] axis quaternion which contains
* the axis of rotation and angle of rotation
* @chainable
*/
rotateBy(axesQuat) {
return axesQuat.multiply(this).multiply(axesQuat.conjugate()).vec;
}
};

export default p5.Quat;

0 comments on commit de8708d

Please sign in to comment.