Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In p5.Camera.slerp, change the eye-center distance interpolation to be logarithmically based #6259

Merged
merged 2 commits into from Jul 9, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/webgl/p5.Camera.js
Expand Up @@ -1648,7 +1648,8 @@ p5.Camera = class Camera {
* When applying this function, all cameras involved must have exactly the same projection
* settings. For example, if one is perspective, ortho, frustum, the other two must also be
* perspective, ortho, frustum respectively. However, if all cameras have ortho settings,
* only orbitControl's change of the projection settings is permissive.
* interpolation is possible if the ratios of left, right, top and bottom are equal to each other.
* For example, when it is changed by orbitControl().
*
* @method slerp
* @param {p5.Camera} cam0 first p5.Camera
Expand Down Expand Up @@ -1755,11 +1756,14 @@ p5.Camera = class Camera {

// For this cameras is ortho, assume that cam0 and cam1 are also ortho
// and interpolate the elements of the projection matrix.
// Use logarithmic interpolation for interpolation.
if (this.projMatrix.mat4[15] !== 0) {
this.projMatrix.mat4[0] =
(1 - amt) * cam0.projMatrix.mat4[0] + amt * cam1.projMatrix.mat4[0];
cam0.projMatrix.mat4[0] *
Math.pow(cam1.projMatrix.mat4[0] / cam0.projMatrix.mat4[0], amt);
this.projMatrix.mat4[5] =
(1 - amt) * cam0.projMatrix.mat4[5] + amt * cam1.projMatrix.mat4[5];
cam0.projMatrix.mat4[5] *
Math.pow(cam1.projMatrix.mat4[5] / cam0.projMatrix.mat4[5], amt);
// If the camera is active, make uPMatrix reflect changes in projMatrix.
if (this._isActive()) {
this._renderer.uPMatrix.mat4 = this.projMatrix.mat4.slice();
Expand All @@ -1773,10 +1777,10 @@ p5.Camera = class Camera {
const center1 = new p5.Vector(cam1.centerX, cam1.centerY, cam1.centerZ);

// Calculate the distance between eye and center for each camera.
// Then linearly interpolate them by amt.
// Logarithmically interpolate these with amt.
const dist0 = p5.Vector.dist(eye0, center0);
const dist1 = p5.Vector.dist(eye1, center1);
const lerpedDist = (1 - amt) * dist0 + amt * dist1;
const lerpedDist = dist0 * Math.pow(dist1 / dist0, amt);

// Next, calculate the ratio to interpolate the eye and center by a constant
// ratio for each camera. This ratio is the same for both. Also, with this ratio
Expand Down
30 changes: 15 additions & 15 deletions test/unit/webgl/p5.Camera.js
Expand Up @@ -814,25 +814,25 @@ suite('p5.Camera', function() {
myCam = myp5.createCamera();
const cam0 = myCam.copy();
const cam1 = myCam.copy();
cam1._orbit(Math.PI * 0.8, 0, 0);
cam1._orbit(Math.PI * 0.8, 0, 0.08);
const cam2 = myCam.copy();
cam2._orbit(0, Math.PI * 0.7, 0);
cam2._orbit(0, Math.PI * 0.7, 0.07);

// Prepare cameras supposed to be obtained by slerp cam0 and cam1.
const cam3 = myCam.copy();
cam3._orbit(Math.PI * 0.3, 0, 0);
cam3._orbit(Math.PI * 0.3, 0, 0.03);
const cam4 = myCam.copy();
cam4._orbit(-Math.PI * 0.7, 0, 0);
cam4._orbit(-Math.PI * 0.7, 0, -0.07);
const cam5 = myCam.copy();
cam5._orbit(Math.PI * 1.1, 0, 0);
cam5._orbit(Math.PI * 1.1, 0, 0.11);

// Prepare cameras supposed to be obtained by slerp cam0 and cam2.
const cam6 = myCam.copy();
cam6._orbit(0, Math.PI * 0.3, 0);
cam6._orbit(0, Math.PI * 0.3, 0.03);
const cam7 = myCam.copy();
cam7._orbit(0, -Math.PI * 0.4, 0);
cam7._orbit(0, -Math.PI * 0.4, -0.04);
const cam8 = myCam.copy();
cam8._orbit(0, Math.PI * 1.1, 0);
cam8._orbit(0, Math.PI * 1.1, 0.11);

// Compare these views with the view set by slerp().
myCam.slerp(cam0, cam1, 3/8);
Expand All @@ -853,15 +853,15 @@ suite('p5.Camera', function() {
myCam = myp5.createCamera();
const cam0 = myCam.copy();
const cam1 = myCam.copy();
cam1._orbitFree(Math.PI * 0.8, Math.PI * 0.6, 0);
cam1._orbitFree(Math.PI * 0.8, Math.PI * 0.6, 0.08);

// Prepare cameras supposed to be obtained by slerp cam0 and cam1.
const cam2 = myCam.copy();
cam2._orbitFree(Math.PI * 0.4, Math.PI * 0.3, 0);
cam2._orbitFree(Math.PI * 0.4, Math.PI * 0.3, 0.04);
const cam3 = myCam.copy();
cam3._orbitFree(-Math.PI * 0.2, -Math.PI * 0.15, 0);
cam3._orbitFree(-Math.PI * 0.2, -Math.PI * 0.15, -0.02);
const cam4 = myCam.copy();
cam4._orbitFree(Math.PI * 1.2, Math.PI * 0.9, 0);
cam4._orbitFree(Math.PI * 1.2, Math.PI * 0.9, 0.12);

// Compare these views with the view set by slerp().
myCam.slerp(cam0, cam1, 1/2);
Expand Down Expand Up @@ -913,15 +913,15 @@ suite('p5.Camera', function() {
myCam.slerp(cam0, cam1, 0.3);

// Next, check the 0th and 5th entries of the projection matrix
// to make sure they are interpolated.
// to make sure it is logarithmically interpolated.
const p0_0 = cam0.projMatrix.mat4[0];
const p1_0 = cam1.projMatrix.mat4[0];
expect(myCam.projMatrix.mat4[0])
.to.be.closeTo(0.7 * p0_0 + 0.3 * p1_0, 0.00001);
.to.be.closeTo(p0_0 * Math.pow(p1_0 / p0_0, 0.3), 0.00001);
const p0_5 = cam0.projMatrix.mat4[5];
const p1_5 = cam1.projMatrix.mat4[5];
expect(myCam.projMatrix.mat4[5])
.to.be.closeTo(0.7 * p0_5 + 0.3 * p1_5, 0.00001);
.to.be.closeTo(p0_5 * Math.pow(p1_5 / p0_5, 0.3), 0.00001);
});
});

Expand Down