Skip to content

Commit 3783dd8

Browse files
authored
Merge pull request #7598 from Forchapeatl/patch-9
Fix camera tilt function to prevent orientation flipping
2 parents 7982e2f + b6cb7a7 commit 3783dd8

File tree

2 files changed

+67
-4
lines changed

2 files changed

+67
-4
lines changed

src/webgl/p5.Camera.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2435,6 +2435,7 @@ p5.Camera = class Camera {
24352435
const rotation = p5.Matrix.identity(this._renderer._pInst);
24362436
rotation.rotate(this._renderer._pInst._toRadians(a), x, y, z);
24372437

2438+
// Apply the rotation matrix to the center vector
24382439
/* eslint-disable max-len */
24392440
const rotatedCenter = [
24402441
centerX * rotation.mat4[0] + centerY * rotation.mat4[4] + centerZ * rotation.mat4[8],
@@ -2443,21 +2444,28 @@ p5.Camera = class Camera {
24432444
];
24442445
/* eslint-enable max-len */
24452446

2446-
// add eye position back into center
2447+
// Translate the rotated center back to world coordinates
24472448
rotatedCenter[0] += this.eyeX;
24482449
rotatedCenter[1] += this.eyeY;
24492450
rotatedCenter[2] += this.eyeZ;
24502451

2452+
// Rotate the up vector to keep the correct camera orientation
2453+
/* eslint-disable max-len */
2454+
const upX = this.upX * rotation.mat4[0] + this.upY * rotation.mat4[4] + this.upZ * rotation.mat4[8];
2455+
const upY = this.upX * rotation.mat4[1] + this.upY * rotation.mat4[5] + this.upZ * rotation.mat4[9];
2456+
const upZ = this.upX * rotation.mat4[2] + this.upY * rotation.mat4[6] + this.upZ * rotation.mat4[10];
2457+
/* eslint-enable max-len */
2458+
24512459
this.camera(
24522460
this.eyeX,
24532461
this.eyeY,
24542462
this.eyeZ,
24552463
rotatedCenter[0],
24562464
rotatedCenter[1],
24572465
rotatedCenter[2],
2458-
this.upX,
2459-
this.upY,
2460-
this.upZ
2466+
upX,
2467+
upY,
2468+
upZ
24612469
);
24622470
}
24632471

test/unit/webgl/p5.Camera.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,61 @@ suite('p5.Camera', function() {
277277
assert.strictEqual(myCam.upY, orig.uy, 'up Y pos changed');
278278
assert.strictEqual(myCam.upZ, orig.uz, 'up Z pos changed');
279279
});
280+
281+
suite('Camera Tilt and Up Vector', function() {
282+
test('Tilt() correctly updates the up vector', function() {
283+
var orig = getVals(myCam); // Store original camera values
284+
285+
// Apply tilt to the camera
286+
myCam.tilt(30); // Tilt by 30 degrees
287+
288+
// Compute expected up vector (normalized)
289+
let forward = myp5.createVector(
290+
myCam.centerX - myCam.eyeX,
291+
myCam.centerY - myCam.eyeY,
292+
myCam.centerZ - myCam.eyeZ
293+
);
294+
let up = myp5.createVector(orig.ux, orig.uy, orig.uz);
295+
let right = p5.Vector.cross(forward, up);
296+
let expectedUp = p5.Vector.cross(right, forward).normalize();
297+
298+
// Verify that the up vector has changed
299+
assert.notStrictEqual(myCam.upX, orig.ux, 'upX should be updated');
300+
assert.notStrictEqual(myCam.upY, orig.uy, 'upY should be updated');
301+
assert.notStrictEqual(myCam.upZ, orig.uz, 'upZ should be updated');
302+
303+
// Verify up vector matches expected values within a small margin of error
304+
assert.closeTo(myCam.upX, expectedUp.x, 0.001, 'upX mismatch');
305+
assert.closeTo(myCam.upY, expectedUp.y, 0.001, 'upY mismatch');
306+
assert.closeTo(myCam.upZ, expectedUp.z, 0.001, 'upZ mismatch');
307+
});
308+
309+
test('Tilt() with negative angle correctly updates the up vector', function() {
310+
var orig = getVals(myCam); // Store original camera values
311+
312+
myCam.tilt(-30); // Tilt by -30 degrees
313+
314+
// Compute expected up vector (normalized)
315+
let forward = myp5.createVector(
316+
myCam.centerX - myCam.eyeX,
317+
myCam.centerY - myCam.eyeY,
318+
myCam.centerZ - myCam.eyeZ
319+
);
320+
let up = myp5.createVector(orig.ux, orig.uy, orig.uz);
321+
let right = p5.Vector.cross(forward, up);
322+
let expectedUp = p5.Vector.cross(right, forward).normalize();
323+
324+
// Verify that the up vector has changed
325+
assert.notStrictEqual(myCam.upX, orig.ux, 'upX should be updated');
326+
assert.notStrictEqual(myCam.upY, orig.uy, 'upY should be updated');
327+
assert.notStrictEqual(myCam.upZ, orig.uz, 'upZ should be updated');
328+
329+
// Verify up vector matches expected values within a small margin of error
330+
assert.closeTo(myCam.upX, expectedUp.x, 0.001, 'upX mismatch');
331+
assert.closeTo(myCam.upY, expectedUp.y, 0.001, 'upY mismatch');
332+
assert.closeTo(myCam.upZ, expectedUp.z, 0.001, 'upZ mismatch');
333+
});
334+
});
280335
});
281336

282337
suite('Rotation with angleMode(DEGREES)', function() {

0 commit comments

Comments
 (0)