camera: bank the view when the flight path curves
This commit is contained in:
1 parent
1fe214f403
commit
e8ff7ee714
2 files changed
+53
-3
No files matched your search
@@ -480,7 +480,18 @@ window.CONFIG = {
|
||||
aim: 'off', // 'off' | 'moon'
|
||||
// aim: 'moon' // look at the moon while flying the path
|
||||
aimEase: 0.94, // 0 = instant turn, 0.99 = very slow
|
||||
aimBob: 0.25 // share of the altitude bob kept while aiming
|
||||
aimBob: 0.25, // share of the altitude bob kept while aiming
|
||||
// Banking when the flight path curves. The camera keeps flying the
|
||||
// same path; roll only rotates the view around the forward axis.
|
||||
roll: {
|
||||
enabled: true,
|
||||
gain: 12, // turn-rate to bank-angle gain
|
||||
maxDeg: 12, // maximum bank angle
|
||||
ease: 0.92, // 0 = instant bank, 0.99 = very slow
|
||||
sign: -1 // flip to +1 if the bank direction feels inverted
|
||||
// roll: { enabled: false }
|
||||
// roll: { gain: 20, maxDeg: 18 }
|
||||
}
|
||||
// camera: { aim: 'moon' } // look at the moon
|
||||
},
|
||||
|
||||
|
||||
Vendored
+41
-2
@@ -1428,6 +1428,13 @@ var CAM_CFG = (window.CONFIG && window.CONFIG.camera) || {};
|
||||
var CAM_AIM_MOON = (CAM_CFG.aim === 'moon');
|
||||
var CAM_AIM_EASE = (typeof CAM_CFG.aimEase === 'number') ? Math.max(0, Math.min(0.999, CAM_CFG.aimEase)) : 0.94;
|
||||
var CAM_AIM_BOB = (typeof CAM_CFG.aimBob === 'number') ? Math.max(0, Math.min(1, CAM_CFG.aimBob)) : 0.25;
|
||||
var CAM_ROLL_CFG = CAM_CFG.roll || {};
|
||||
var CAM_ROLL_ON = CAM_ROLL_CFG.enabled !== false;
|
||||
var CAM_ROLL_GAIN = (typeof CAM_ROLL_CFG.gain === 'number') ? Math.max(0, CAM_ROLL_CFG.gain) : 12;
|
||||
var CAM_ROLL_MAX = (typeof CAM_ROLL_CFG.maxDeg === 'number') ? Math.max(0, Math.min(35, CAM_ROLL_CFG.maxDeg)) * Math.PI / 180 : 12 * Math.PI / 180;
|
||||
var CAM_ROLL_EASE = (typeof CAM_ROLL_CFG.ease === 'number') ? Math.max(0, Math.min(0.999, CAM_ROLL_CFG.ease)) : 0.92;
|
||||
var CAM_ROLL_SIGN = (typeof CAM_ROLL_CFG.sign === 'number') ? CAM_ROLL_CFG.sign : -1;
|
||||
var lastCamBearing = null, lastCamTime = null, camRoll = 0;
|
||||
var aimHdX = 0, aimHdZ = 1, aimPitch = 0.45, aimReady = false;
|
||||
// CONFIG.clouds = { top: ..., bottom: ... } overrides the defaults; the
|
||||
// deck must stay below the camera and keep a minimum thickness.
|
||||
@@ -6243,7 +6250,29 @@ window.clouds3dRender = function(target) {
|
||||
// View direction as compass bearing (world +X = east, +Z = north,
|
||||
// matching the sun-vector convention): 0 = north, clockwise.
|
||||
// The clock's compass needle reads this.
|
||||
window.__flightBearing = Math.atan2(hdX, hdZ);
|
||||
var flightBearing = Math.atan2(hdX, hdZ);
|
||||
window.__flightBearing = flightBearing;
|
||||
var viewRoll = 0;
|
||||
if (CAM_ROLL_ON) {
|
||||
if (lastCamBearing !== null && lastCamTime !== null) {
|
||||
var _dt = Math.max(0.001, now - lastCamTime);
|
||||
var _db = flightBearing - lastCamBearing;
|
||||
while (_db > Math.PI) _db -= 2 * Math.PI;
|
||||
while (_db < -Math.PI) _db += 2 * Math.PI;
|
||||
var _turnRate = _db / _dt;
|
||||
var _target = CAM_ROLL_SIGN * _turnRate * CAM_ROLL_GAIN;
|
||||
if (_target > CAM_ROLL_MAX) _target = CAM_ROLL_MAX;
|
||||
else if (_target < -CAM_ROLL_MAX) _target = -CAM_ROLL_MAX;
|
||||
camRoll += (_target - camRoll) * (1 - CAM_ROLL_EASE);
|
||||
}
|
||||
lastCamBearing = flightBearing;
|
||||
lastCamTime = now;
|
||||
viewRoll = camRoll;
|
||||
} else {
|
||||
lastCamBearing = null;
|
||||
lastCamTime = null;
|
||||
camRoll = 0;
|
||||
}
|
||||
// Periodic check: when the camera approaches the corridor edge,
|
||||
// re-centre the mosaic (whole-tile shift of the canvas content +
|
||||
// fetch the newly exposed columns). At uSpeed=1 the camera moves
|
||||
@@ -6309,10 +6338,20 @@ window.clouds3dRender = function(target) {
|
||||
// Debug override: point at world origin so the mesh is always in view.
|
||||
var fwdLen = Math.hypot(hdX, pitch, hdZ) || 1;
|
||||
var fwdX = hdX / fwdLen, fwdY = -pitch / fwdLen, fwdZ = hdZ / fwdLen;
|
||||
var upX = 0, upY = 1, upZ = 0;
|
||||
if (Math.abs(viewRoll) > 1e-5) {
|
||||
var _rc = Math.cos(viewRoll), _rs = Math.sin(viewRoll);
|
||||
// Rodrigues rotation of the world-up vector around the forward axis.
|
||||
upX = -fwdZ * _rs;
|
||||
upY = _rc;
|
||||
upZ = fwdX * _rs;
|
||||
var _ul = Math.hypot(upX, upY, upZ) || 1;
|
||||
upX /= _ul; upY /= _ul; upZ /= _ul;
|
||||
}
|
||||
var view = mat4LookAt(
|
||||
[camX, camY, camZ],
|
||||
[camX + fwdX * 5, camY + fwdY * 5, camZ + fwdZ * 5],
|
||||
[0, 1, 0]
|
||||
[upX, upY, upZ]
|
||||
);
|
||||
// Inverse of (proj * view) is uploaded to the cloud/sky shader so
|
||||
// both can reconstruct the world ray from gl_FragCoord identically
|
||||
|
||||
Reference in new issue
Block a user