viewer_sgos / orbit-camera.js
MikaFil's picture
Update orbit-camera.js
8d41429 verified
raw
history blame
8 kB
// orbit-camera.js
// ==============================
console.log('[OrbitFILE] loaded orbit-camera.js'); // preuve que le fichier est bien chargé
/*
* PlayCanvas Orbit Camera for GSplat/SOGS/GLB viewers.
* - Handles min/max zoom, pitch, yaw, minY (don't go below ground)
* - Mouse, touch & keyboard controls (orbit, pan, zoom)
* - Attributes are auto-injected by viewer.js
*/
var OrbitCamera = pc.createScript('orbitCamera');
OrbitCamera.attributes.add('distanceMax', { type: 'number', default: 20, title: 'Distance Max' });
OrbitCamera.attributes.add('distanceMin', { type: 'number', default: 1, title: 'Distance Min' });
OrbitCamera.attributes.add('pitchAngleMax', { type: 'number', default: 90, title: 'Pitch Angle Max (degrees)' });
OrbitCamera.attributes.add('pitchAngleMin', { type: 'number', default: 0, title: 'Pitch Angle Min (degrees)' });
OrbitCamera.attributes.add('yawAngleMax', { type: 'number', default: 360, title: 'Yaw Angle Max (degrees)' });
OrbitCamera.attributes.add('yawAngleMin', { type: 'number', default: -360,title: 'Yaw Angle Min (degrees)' });
OrbitCamera.attributes.add('minY', { type: 'number', default: 0, title: 'Minimum Y' });
OrbitCamera.attributes.add('inertiaFactor', { type: 'number', default: 0.2, title: 'Inertia Factor' });
OrbitCamera.attributes.add('focusEntity', { type: 'entity', title: 'Focus Entity' });
OrbitCamera.attributes.add('frameOnStart', { type: 'boolean', default: true, title: 'Frame on Start' });
Object.defineProperty(OrbitCamera.prototype, 'distance', {
get: function () { return this._targetDistance; },
set: function (value) { this._targetDistance = this._clampDistance(value); }
});
Object.defineProperty(OrbitCamera.prototype, 'pitch', {
get: function () { return this._targetPitch; },
set: function (value) { this._targetPitch = this._clampPitchAngle(value); }
});
Object.defineProperty(OrbitCamera.prototype, 'yaw', {
get: function () { return this._targetYaw; },
set: function (value) { this._targetYaw = this._clampYawAngle(value); }
});
Object.defineProperty(OrbitCamera.prototype, 'pivotPoint', {
get: function () { return this._pivotPoint; },
set: function (value) { this._pivotPoint.copy(value); }
});
OrbitCamera.prototype.focus = function (focusEntity) {
this._buildAabb(focusEntity);
var halfExtents = this._modelsAabb.halfExtents;
var radius = Math.max(halfExtents.x, Math.max(halfExtents.y, halfExtents.z));
this.distance = (radius * 1.5) / Math.sin(0.5 * this.entity.camera.fov * pc.math.DEG_TO_RAD);
this._removeInertia();
this._pivotPoint.copy(this._modelsAabb.center);
};
OrbitCamera.distanceBetween = new pc.Vec3();
OrbitCamera.prototype.resetAndLookAtPoint = function (resetPoint, lookAtPoint) {
this.pivotPoint.copy(lookAtPoint);
this.entity.setPosition(resetPoint);
this.entity.lookAt(lookAtPoint);
var distance = OrbitCamera.distanceBetween;
distance.sub2(lookAtPoint, resetPoint);
this.distance = distance.length();
this.pivotPoint.copy(lookAtPoint);
var cameraQuat = this.entity.getRotation();
this.yaw = this._calcYaw(cameraQuat);
this.pitch = this._calcPitch(cameraQuat, this.yaw);
this._removeInertia();
this._updatePosition();
};
OrbitCamera.prototype.resetAndLookAtEntity = function (resetPoint, entity) {
this._buildAabb(entity);
this.resetAndLookAtPoint(resetPoint, this._modelsAabb.center);
};
OrbitCamera.prototype.reset = function (yaw, pitch, distance) {
this.pitch = pitch;
this.yaw = yaw;
this.distance = distance;
this._removeInertia();
};
OrbitCamera.prototype.resetToPosition = function (position, lookAtPoint) {
this.entity.setPosition(position);
this.entity.lookAt(lookAtPoint);
this._pivotPoint.copy(lookAtPoint);
var distanceVec = new pc.Vec3();
distanceVec.sub2(position, lookAtPoint);
this._targetDistance = this._distance = distanceVec.length();
var cameraQuat = this.entity.getRotation();
this._targetYaw = this._yaw = this._calcYaw(cameraQuat);
this._targetPitch = this._pitch = this._calcPitch(cameraQuat, this._yaw);
this._removeInertia();
this._updatePosition();
};
OrbitCamera.prototype.worldCameraYForPivot = function(pivot) {
var quat = new pc.Quat();
quat.setFromEulerAngles(this._pitch, this._yaw, 0);
var forward = new pc.Vec3();
quat.transformVector(pc.Vec3.FORWARD, forward);
var camPos = pivot.clone();
camPos.add(forward.clone().scale(-this._distance));
return camPos.y;
};
OrbitCamera.prototype.initialize = function () {
var self = this;
var onWindowResize = function () { self._checkAspectRatio(); };
window.addEventListener('resize', onWindowResize, false);
this._checkAspectRatio();
this._modelsAabb = new pc.BoundingBox();
this._buildAabb(this.focusEntity || this.app.root);
this.entity.lookAt(this._modelsAabb.center);
this._pivotPoint = new pc.Vec3();
this._pivotPoint.copy(this._modelsAabb.center);
var cameraQuat = this.entity.getRotation();
this._yaw = this._calcYaw(cameraQuat); // DEGRÉS
this._pitch = this._clampPitchAngle(this._calcPitch(cameraQuat, this._yaw));
this.entity.setLocalEulerAngles(this._pitch, this._yaw, 0);
this._distance = 0;
this._targetYaw = this._yaw;
this._targetPitch = this._pitch;
if (this.frameOnStart) {
this.focus(this.focusEntity || this.app.root);
} else {
var distanceBetween = new pc.Vec3();
distanceBetween.sub2(this.entity.getPosition(), this._pivotPoint);
this._distance = this._clampDistance(distanceBetween.length());
}
this._targetDistance = this._distance;
this.on('attr:distanceMin', function () { this._distance = this._clampDistance(this._distance); });
this.on('attr:distanceMax', function () { this._distance = this._clampDistance(this._distance); });
this.on('attr:pitchAngleMin', function () { this._pitch = this._clampPitchAngle(this._pitch); });
this.on('attr:pitchAngleMax', function () { this._pitch = this._clampPitchAngle(this._pitch); });
this.on('attr:focusEntity', function (value) {
if (this.frameOnStart) { this.focus(value || this.app.root); }
else { this.resetAndLookAtEntity(this.entity.getPosition(), value || this.app.root); }
});
this.on('attr:frameOnStart', function (value) {
if (value) { this.focus(this.focusEntity || this.app.root); }
});
this.on('destroy', function () { window.removeEventListener('resize', onWindowResize, false); });
console.log('[OrbitCam] init yaw=%s° pitch=%s° dist=%s',
this._yaw.toFixed(2), this._pitch.toFixed(2), this._distance.toFixed(3));
};
OrbitCamera.prototype.update = function (dt) {
var t = this.inertiaFactor === 0 ? 1 : Math.min(dt / this.inertiaFactor, 1);
this._distance = pc.math.lerp(this._distance, this._targetDistance, t);
this._yaw = pc.math.lerp(this._yaw, this._targetYaw, t);
this._pitch = pc.math.lerp(this._pitch, this._targetPitch, t);
this._updatePosition();
};
OrbitCamera.prototype._updatePosition = function () {
this.entity.setLocalPosition(0, 0, 0);
this.entity.setLocalEulerAngles(this._pitch, this._yaw, 0);
var position = this.entity.getPosition();
position.copy(this.entity.forward);
position.mulScalar(-this._distance);
position.add(this.pivotPoint);
position.y = Math.max(position.y, this.minY);
this.entity.setPosition(position);
};
OrbitCamera.prototype._removeInertia = function () {
this._yaw = this._targetYaw;
this._pitch = this._targetPitch;
this._distance = this._targetDistance;
};
OrbitCamera.prototype._checkAspectRatio = function () {
var height = this.app.graphicsDevice.height;
var width = this.app.graphicsDevice.width;
this.entity.camera.horizontalFov = (height > width);
};
OrbitCamera.prototype._buildAabb = function (entity) {
var i, m, mes