Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions src/webgl/p5.Camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -1720,23 +1720,21 @@ p5.Camera.prototype._orbit = function(dTheta, dPhi, dRadius) {
let camTheta = Math.atan2(diffX, diffZ); // equatorial angle
let camPhi = Math.acos(Math.max(-1, Math.min(1, diffY / camRadius))); // polar angle

// add change
camTheta += dTheta;
camPhi += dPhi;
camRadius += dRadius;
let newUpY = this.upY > 0 ? 1 : -1;
// add change according to the direction of newupY
camTheta += newUpY * dTheta;
camPhi += newUpY * dPhi;
// if camPhi becomes >= PI or <= 0,
// upY of camera need to be flipped to the other side
if (camPhi <= 0 || camPhi >= Math.PI) {
newUpY *= -1;
}

camRadius += dRadius;
// prevent zooming through the center:
if (camRadius < 0) {
camRadius = 0.1;
}

// prevent rotation over the zenith / under bottom
if (camPhi > Math.PI) {
camPhi = Math.PI;
} else if (camPhi <= 0) {
camPhi = 0.001;
}

// from https://github.com/mrdoob/three.js/blob/dev/src/math/Vector3.js#L628-L632
const _x = Math.sin(camPhi) * camRadius * Math.sin(camTheta);
const _y = Math.cos(camPhi) * camRadius;
Expand All @@ -1750,7 +1748,7 @@ p5.Camera.prototype._orbit = function(dTheta, dPhi, dRadius) {
this.centerY,
this.centerZ,
0,
1,
newUpY,
0
);
};
Expand Down
73 changes: 49 additions & 24 deletions test/unit/webgl/p5.Camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,34 +449,59 @@ suite('p5.Camera', function() {

assert.deepEqual(myCam.cameraMatrix.mat4, expectedMatrix);
});
test('_orbit() ensures altitude phi <= PI', function() {
test('_orbit() ensures myCam.upY switches direction (from 1 to -1) at camPhi <= 0', function() {
// the following should produce the upY with inverted direction(from 1 to -1)
// when camPhi changes from positive to negative or zero
myCam._orbit(0, -Math.PI, 0);
// upY should switch from 1(dPhi=0) to -1 (dPhi=-PI)
// myCam.upY should be -1
assert(myCam.upY === -1);
});
test('_orbit() ensures myCam.upY switches direction (from -1 to 1) at camPhi <= 0', function() {
// the following should produce the upY with inverted direction(from -1 to 1)
// when camPhi changes from negative to positive or zero
myCam._orbit(0, -Math.PI, 0);
myCam._orbit(0, Math.PI, 0);
// upY should switch from -1(dPhi=-PI) to 1 (dPhi=PI)
// myCam.upY should be 1
assert(myCam.upY === 1);
});
test('_orbit() ensures myCam.upY switches direction (from 1 to -1) at camPhi >= PI', function() {
// the following should produce the upY with inverted direction(from 1 to -1)
// when camPhi reaches PI
myCam._orbit(0, Math.PI, 0);
// upY should switch from 1(dPhi=0) to -1 (dPhi=PI)
// myCam.upY should be -1
assert(myCam.upY === -1);
});
test('_orbit() ensures myCam.upY switches direction (from -1 to 1) at camPhi >= PI', function() {
// the following should produce the upY with inverted direction(from -1 to 1)
// when camPhi reaches PI
myCam._orbit(0, Math.PI, 0);
myCam._orbit(0, -Math.PI, 0);
// upY should switch from -1(dPhi=PI) to 1 (dPhi=-PI)
// myCam.upY should be 1
assert(myCam.upY === 1);
});
test('_orbit() ensures camera can do multiple continuous 360deg rotations', function() {
// the following should produce two camera objects having same properties.
myCam._orbit(0, Math.PI, 0);
var myCamCopy = myCam.copy();

// the following should produce the same values because phi is capped at PI
myCamCopy._orbit(0, 10, 0);
myCam._orbit(0, 20, 0);

assert.deepEqual(myCam.cameraMatrix.mat4, myCamCopy.cameraMatrix.mat4);
});
test('_orbit() ensures altitude phi > 0', function() {
var myCamCopy = myCam.copy();

// the following should produce the same values because phi is restricted
// to > 0
myCamCopy._orbit(0, -10, 0);
myCam._orbit(0, -20, 0);

assert.deepEqual(myCam.cameraMatrix.mat4, myCamCopy.cameraMatrix.mat4);
myCamCopy._orbit(0, Math.PI, 0);
myCamCopy._orbit(0, Math.PI, 0);
for (let i = 0; i < myCamCopy.cameraMatrix.mat4.length; i++) {
expect(
myCamCopy.cameraMatrix.mat4[i]).to.be.closeTo(
myCam.cameraMatrix.mat4[i], 0.001);
}
});
test('_orbit() ensures radius > 0', function() {
// the following should produce two camera objects having same properties.
myCam._orbit(0, Math.PI, 0);
var myCamCopy = myCam.copy();

// the following should produce the same values because radius is
// restricted to > 0
myCamCopy._orbit(0, 0, -200);
myCam._orbit(0, 0, -300);

assert.deepEqual(myCam.cameraMatrix.mat4, myCamCopy.cameraMatrix.mat4);
myCamCopy._orbit(0, 0, -100);
myCam._orbit(0, 0, -250);
assert.deepEqual(myCam.cameraMatrix.mat4, myCamCopy.cameraMatrix.mat4, 'deep equal is failing');
});
});

Expand Down