Spaces:
Running
Running
Update deplacement_dans_env/ctrl_camera_pr_env.js
Browse files
deplacement_dans_env/ctrl_camera_pr_env.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
| 1 |
// ctrl_camera_pr_env.js
|
| 2 |
// ============================================================================
|
| 3 |
-
// ORBIT CAMERA + INPUTS (PlayCanvas) — version bbox
|
| 4 |
-
// -
|
| 5 |
-
// -
|
|
|
|
|
|
|
|
|
|
| 6 |
// ============================================================================
|
| 7 |
|
| 8 |
var OrbitCamera = pc.createScript('orbitCamera');
|
|
@@ -61,20 +64,16 @@ OrbitCamera.prototype.focus = function (focusEntity) {
|
|
| 61 |
this._buildAabb(focusEntity);
|
| 62 |
var halfExtents = this._modelsAabb.halfExtents;
|
| 63 |
var radius = Math.max(halfExtents.x, Math.max(halfExtents.y, halfExtents.z));
|
| 64 |
-
|
| 65 |
-
// calcule distance initiale (pas de maxZoom à respecter)
|
| 66 |
this.distance = (radius * 1.5) / Math.sin(0.5 * this.entity.camera.fov * pc.math.DEG_TO_RAD);
|
| 67 |
-
|
| 68 |
this._removeInertia();
|
| 69 |
this._pivotPoint.copy(this._modelsAabb.center);
|
| 70 |
-
this._clampPivotToBBox(this._pivotPoint);
|
| 71 |
};
|
| 72 |
|
| 73 |
OrbitCamera.distanceBetween = new pc.Vec3();
|
| 74 |
|
| 75 |
OrbitCamera.prototype.resetAndLookAtPoint = function (resetPoint, lookAtPoint) {
|
| 76 |
this.pivotPoint.copy(lookAtPoint);
|
| 77 |
-
this._clampPivotToBBox(this._pivotPoint);
|
| 78 |
|
| 79 |
this.entity.setPosition(resetPoint);
|
| 80 |
this.entity.lookAt(lookAtPoint);
|
|
@@ -107,7 +106,6 @@ OrbitCamera.prototype.resetToPosition = function (position, lookAtPoint) {
|
|
| 107 |
this.entity.setPosition(position);
|
| 108 |
this.entity.lookAt(lookAtPoint);
|
| 109 |
this._pivotPoint.copy(lookAtPoint);
|
| 110 |
-
this._clampPivotToBBox(this._pivotPoint);
|
| 111 |
|
| 112 |
var distanceVec = new pc.Vec3();
|
| 113 |
distanceVec.sub2(position, lookAtPoint);
|
|
@@ -121,7 +119,7 @@ OrbitCamera.prototype.resetToPosition = function (position, lookAtPoint) {
|
|
| 121 |
this._updatePosition();
|
| 122 |
};
|
| 123 |
|
| 124 |
-
// ==== Helper:
|
| 125 |
OrbitCamera.prototype.worldCameraYForPivot = function(pivot) {
|
| 126 |
var quat = new pc.Quat();
|
| 127 |
quat.setFromEulerAngles(this._pitch, this._yaw, 0);
|
|
@@ -145,7 +143,6 @@ OrbitCamera.prototype.initialize = function () {
|
|
| 145 |
this.entity.lookAt(this._modelsAabb.center);
|
| 146 |
this._pivotPoint = new pc.Vec3();
|
| 147 |
this._pivotPoint.copy(this._modelsAabb.center);
|
| 148 |
-
this._clampPivotToBBox(this._pivotPoint);
|
| 149 |
|
| 150 |
var cameraQuat = this.entity.getRotation();
|
| 151 |
this._yaw = this._calcYaw(cameraQuat);
|
|
@@ -165,7 +162,7 @@ OrbitCamera.prototype.initialize = function () {
|
|
| 165 |
}
|
| 166 |
this._targetDistance = this._distance;
|
| 167 |
|
| 168 |
-
// Listeners d’attributs
|
| 169 |
this.on('attr:distanceMin', function () { this._distance = this._clampDistance(this._distance); });
|
| 170 |
this.on('attr:pitchAngleMin', function () { this._pitch = this._clampPitchAngle(this._pitch); });
|
| 171 |
this.on('attr:pitchAngleMax', function () { this._pitch = this._clampPitchAngle(this._pitch); });
|
|
@@ -179,10 +176,6 @@ OrbitCamera.prototype.initialize = function () {
|
|
| 179 |
if (value) { this.focus(this.focusEntity || this.app.root); }
|
| 180 |
});
|
| 181 |
|
| 182 |
-
// Clamp bbox dynamique
|
| 183 |
-
var bboxAttrs = ['Xmin','Xmax','Ymin','Ymax','Zmin','Zmax'];
|
| 184 |
-
bboxAttrs.forEach((a)=> this.on('attr:'+a, function(){ this._clampPivotToBBox(this._pivotPoint); this._updatePosition(); }));
|
| 185 |
-
|
| 186 |
this.on('destroy', function () { window.removeEventListener('resize', onWindowResize, false); });
|
| 187 |
};
|
| 188 |
|
|
@@ -195,24 +188,33 @@ OrbitCamera.prototype.update = function (dt) {
|
|
| 195 |
};
|
| 196 |
|
| 197 |
OrbitCamera.prototype._updatePosition = function () {
|
|
|
|
| 198 |
this.entity.setLocalPosition(0, 0, 0);
|
| 199 |
this.entity.setLocalEulerAngles(this._pitch, this._yaw, 0);
|
| 200 |
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
position.add(this.pivotPoint);
|
| 205 |
|
| 206 |
-
//
|
| 207 |
-
|
|
|
|
|
|
|
| 208 |
|
| 209 |
-
//
|
| 210 |
-
|
|
|
|
| 211 |
|
| 212 |
-
|
|
|
|
| 213 |
|
| 214 |
-
//
|
| 215 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
};
|
| 217 |
|
| 218 |
OrbitCamera.prototype._removeInertia = function () {
|
|
@@ -268,7 +270,6 @@ OrbitCamera.prototype._calcYaw = function (quat) {
|
|
| 268 |
};
|
| 269 |
|
| 270 |
OrbitCamera.prototype._clampDistance = function (distance) {
|
| 271 |
-
// Plus de distanceMax : uniquement un minimum
|
| 272 |
return Math.max(distance, this.distanceMin);
|
| 273 |
};
|
| 274 |
|
|
@@ -298,18 +299,22 @@ OrbitCamera.prototype._bboxEnabled = function () {
|
|
| 298 |
return (this.Xmin < this.Xmax) && (this.Ymin < this.Ymax) && (this.Zmin < this.Zmax);
|
| 299 |
};
|
| 300 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
OrbitCamera.prototype._applyBoundingBox = function (v3 /* camera position */) {
|
| 302 |
-
if (!this._bboxEnabled()) return;
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
|
|
|
| 307 |
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
v3.x =
|
| 311 |
-
|
| 312 |
-
v3.z = pc.math.clamp(v3.z, this.Zmin, this.Zmax);
|
| 313 |
};
|
| 314 |
|
| 315 |
// ===================== Orbit Camera Input Mouse ========================
|
|
@@ -358,26 +363,24 @@ OrbitCameraInputMouse.prototype.pan = function (screenPoint) {
|
|
| 358 |
var camera = this.entity.camera;
|
| 359 |
var distance = this.orbitCamera.distance;
|
| 360 |
|
| 361 |
-
camera.screenToWorld(screenPoint.x,
|
| 362 |
camera.screenToWorld(this.lastPoint.x, this.lastPoint.y, distance, toWorldPoint);
|
| 363 |
|
| 364 |
worldDiff.sub2(toWorldPoint, fromWorldPoint);
|
| 365 |
|
| 366 |
-
// Enforce minY
|
| 367 |
var proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
|
| 368 |
-
var minY = this.orbitCamera.minY;
|
| 369 |
-
var resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
|
| 370 |
|
| 371 |
-
|
| 372 |
-
|
|
|
|
| 373 |
this.orbitCamera.pivotPoint.copy(proposedPivot);
|
| 374 |
} else {
|
| 375 |
-
//
|
| 376 |
worldDiff.y = 0;
|
| 377 |
proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
|
| 378 |
-
|
| 379 |
-
if (
|
| 380 |
-
this.orbitCamera._clampPivotToBBox(proposedPivot);
|
| 381 |
this.orbitCamera.pivotPoint.copy(proposedPivot);
|
| 382 |
}
|
| 383 |
}
|
|
@@ -525,14 +528,12 @@ OrbitCameraInputTouch.prototype.pan = function (midPoint) {
|
|
| 525 |
var resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
|
| 526 |
|
| 527 |
if (resultingY >= minY - 1e-4) {
|
| 528 |
-
this.orbitCamera._clampPivotToBBox(proposedPivot);
|
| 529 |
this.orbitCamera.pivotPoint.copy(proposedPivot);
|
| 530 |
} else {
|
| 531 |
worldDiff.y = 0;
|
| 532 |
proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
|
| 533 |
resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
|
| 534 |
if (resultingY >= minY - 1e-4) {
|
| 535 |
-
this.orbitCamera._clampPivotToBBox(proposedPivot);
|
| 536 |
this.orbitCamera.pivotPoint.copy(proposedPivot);
|
| 537 |
}
|
| 538 |
}
|
|
@@ -595,7 +596,7 @@ OrbitCameraInputTouch.prototype.onTouchMove = function (event) {
|
|
| 595 |
|
| 596 |
// =================== Orbit Camera Input Keyboard ========================
|
| 597 |
// Flèches : déplacement avant/arrière & droite/gauche (repère caméra, 3D)
|
| 598 |
-
// Ctrl+flèches : orbiter autour du pivot
|
| 599 |
// Maj+flèches : rotation libre sur place (pas de limites yaw/pitch)
|
| 600 |
var OrbitCameraInputKeyboard = pc.createScript('orbitCameraInputKeyboard');
|
| 601 |
|
|
@@ -677,7 +678,6 @@ OrbitCameraInputKeyboard.prototype.update = function (dt) {
|
|
| 677 |
var q = new pc.Quat().setFromEulerAngles(this.orbitCamera._pitch, this.orbitCamera._yaw, 0);
|
| 678 |
var forward = new pc.Vec3(); q.transformVector(pc.Vec3.FORWARD, forward);
|
| 679 |
var newPivot = camPos.clone().add(forward.clone().mulScalar(dist));
|
| 680 |
-
this.orbitCamera._clampPivotToBBox(newPivot);
|
| 681 |
this.orbitCamera._pivotPoint.copy(newPivot);
|
| 682 |
|
| 683 |
this.orbitCamera._removeInertia();
|
|
@@ -712,8 +712,6 @@ OrbitCameraInputKeyboard.prototype.update = function (dt) {
|
|
| 712 |
if (currCamY + delta.y < minY) {
|
| 713 |
delta.y = minY - currCamY;
|
| 714 |
}
|
| 715 |
-
|
| 716 |
-
this.orbitCamera._clampPivotToBBox(newPivot);
|
| 717 |
-
this.orbitCamera._pivotPoint.copy(newPivot);
|
| 718 |
}
|
| 719 |
};
|
|
|
|
| 1 |
// ctrl_camera_pr_env.js
|
| 2 |
// ============================================================================
|
| 3 |
+
// ORBIT CAMERA + INPUTS (PlayCanvas) — version bbox "rotation-libre"
|
| 4 |
+
// - Zoom : uniquement un minimum (pas de maxZoom)
|
| 5 |
+
// - Bounding Box : on contraint UNIQUEMENT la position caméra
|
| 6 |
+
// -> si la position sort, on la clampe puis on décale le pivot
|
| 7 |
+
// pour conserver l'orientation ET la distance (orbite fluide).
|
| 8 |
+
// - minY : altitude mini de la caméra (appliquée comme une "box" horizontale)
|
| 9 |
// ============================================================================
|
| 10 |
|
| 11 |
var OrbitCamera = pc.createScript('orbitCamera');
|
|
|
|
| 64 |
this._buildAabb(focusEntity);
|
| 65 |
var halfExtents = this._modelsAabb.halfExtents;
|
| 66 |
var radius = Math.max(halfExtents.x, Math.max(halfExtents.y, halfExtents.z));
|
| 67 |
+
// Distance initiale (pas de maxZoom)
|
|
|
|
| 68 |
this.distance = (radius * 1.5) / Math.sin(0.5 * this.entity.camera.fov * pc.math.DEG_TO_RAD);
|
|
|
|
| 69 |
this._removeInertia();
|
| 70 |
this._pivotPoint.copy(this._modelsAabb.center);
|
|
|
|
| 71 |
};
|
| 72 |
|
| 73 |
OrbitCamera.distanceBetween = new pc.Vec3();
|
| 74 |
|
| 75 |
OrbitCamera.prototype.resetAndLookAtPoint = function (resetPoint, lookAtPoint) {
|
| 76 |
this.pivotPoint.copy(lookAtPoint);
|
|
|
|
| 77 |
|
| 78 |
this.entity.setPosition(resetPoint);
|
| 79 |
this.entity.lookAt(lookAtPoint);
|
|
|
|
| 106 |
this.entity.setPosition(position);
|
| 107 |
this.entity.lookAt(lookAtPoint);
|
| 108 |
this._pivotPoint.copy(lookAtPoint);
|
|
|
|
| 109 |
|
| 110 |
var distanceVec = new pc.Vec3();
|
| 111 |
distanceVec.sub2(position, lookAtPoint);
|
|
|
|
| 119 |
this._updatePosition();
|
| 120 |
};
|
| 121 |
|
| 122 |
+
// ==== Helper: cam Y si le pivot = 'pivot' (sert pour minY) ====
|
| 123 |
OrbitCamera.prototype.worldCameraYForPivot = function(pivot) {
|
| 124 |
var quat = new pc.Quat();
|
| 125 |
quat.setFromEulerAngles(this._pitch, this._yaw, 0);
|
|
|
|
| 143 |
this.entity.lookAt(this._modelsAabb.center);
|
| 144 |
this._pivotPoint = new pc.Vec3();
|
| 145 |
this._pivotPoint.copy(this._modelsAabb.center);
|
|
|
|
| 146 |
|
| 147 |
var cameraQuat = this.entity.getRotation();
|
| 148 |
this._yaw = this._calcYaw(cameraQuat);
|
|
|
|
| 162 |
}
|
| 163 |
this._targetDistance = this._distance;
|
| 164 |
|
| 165 |
+
// Listeners d’attributs
|
| 166 |
this.on('attr:distanceMin', function () { this._distance = this._clampDistance(this._distance); });
|
| 167 |
this.on('attr:pitchAngleMin', function () { this._pitch = this._clampPitchAngle(this._pitch); });
|
| 168 |
this.on('attr:pitchAngleMax', function () { this._pitch = this._clampPitchAngle(this._pitch); });
|
|
|
|
| 176 |
if (value) { this.focus(this.focusEntity || this.app.root); }
|
| 177 |
});
|
| 178 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
this.on('destroy', function () { window.removeEventListener('resize', onWindowResize, false); });
|
| 180 |
};
|
| 181 |
|
|
|
|
| 188 |
};
|
| 189 |
|
| 190 |
OrbitCamera.prototype._updatePosition = function () {
|
| 191 |
+
// 1) oriente la caméra
|
| 192 |
this.entity.setLocalPosition(0, 0, 0);
|
| 193 |
this.entity.setLocalEulerAngles(this._pitch, this._yaw, 0);
|
| 194 |
|
| 195 |
+
// 2) calcule la position théorique en fonction du pivot et de la distance
|
| 196 |
+
var forward = this.entity.forward.clone(); // direction de visée
|
| 197 |
+
var desired = this._pivotPoint.clone().add(forward.clone().mulScalar(-this._distance));
|
|
|
|
| 198 |
|
| 199 |
+
// 3) applique minY (comme un plan horizontal)
|
| 200 |
+
if (desired.y < this.minY) {
|
| 201 |
+
desired.y = this.minY;
|
| 202 |
+
}
|
| 203 |
|
| 204 |
+
// 4) contraint UNIQUEMENT la position caméra à la bbox
|
| 205 |
+
var clamped = desired.clone();
|
| 206 |
+
var wasClamped = this._applyBoundingBox(clamped); // retourne true si clamp effectué
|
| 207 |
|
| 208 |
+
// 5) positionne la caméra
|
| 209 |
+
this.entity.setPosition(clamped);
|
| 210 |
|
| 211 |
+
// 6) si clamp (bbox ou minY), on recalcule un pivot cohérent sur le même rayon
|
| 212 |
+
// (préserve orientation + distance => rotation reste fluide au contact)
|
| 213 |
+
if (wasClamped || clamped.y !== desired.y) {
|
| 214 |
+
// forward pointe de la caméra vers la scène
|
| 215 |
+
// pos = pivot - forward * distance => pivot = pos + forward * distance
|
| 216 |
+
this._pivotPoint.copy(clamped.clone().add(forward.mulScalar(this._distance)));
|
| 217 |
+
}
|
| 218 |
};
|
| 219 |
|
| 220 |
OrbitCamera.prototype._removeInertia = function () {
|
|
|
|
| 270 |
};
|
| 271 |
|
| 272 |
OrbitCamera.prototype._clampDistance = function (distance) {
|
|
|
|
| 273 |
return Math.max(distance, this.distanceMin);
|
| 274 |
};
|
| 275 |
|
|
|
|
| 299 |
return (this.Xmin < this.Xmax) && (this.Ymin < this.Ymax) && (this.Zmin < this.Zmax);
|
| 300 |
};
|
| 301 |
|
| 302 |
+
/**
|
| 303 |
+
* Contrainte position caméra à la bbox.
|
| 304 |
+
* @returns {boolean} true si un clamp a été appliqué
|
| 305 |
+
*/
|
| 306 |
OrbitCamera.prototype._applyBoundingBox = function (v3 /* camera position */) {
|
| 307 |
+
if (!this._bboxEnabled()) return false;
|
| 308 |
+
|
| 309 |
+
var clamped = false;
|
| 310 |
+
var nx = pc.math.clamp(v3.x, this.Xmin, this.Xmax);
|
| 311 |
+
var ny = pc.math.clamp(v3.y, this.Ymin, this.Ymax);
|
| 312 |
+
var nz = pc.math.clamp(v3.z, this.Zmin, this.Zmax);
|
| 313 |
|
| 314 |
+
if (nx !== v3.x || ny !== v3.y || nz !== v3.z) clamped = true;
|
| 315 |
+
|
| 316 |
+
v3.x = nx; v3.y = ny; v3.z = nz;
|
| 317 |
+
return clamped;
|
|
|
|
| 318 |
};
|
| 319 |
|
| 320 |
// ===================== Orbit Camera Input Mouse ========================
|
|
|
|
| 363 |
var camera = this.entity.camera;
|
| 364 |
var distance = this.orbitCamera.distance;
|
| 365 |
|
| 366 |
+
camera.screenToWorld(screenPoint.x, screenPoint.y, distance, fromWorldPoint);
|
| 367 |
camera.screenToWorld(this.lastPoint.x, this.lastPoint.y, distance, toWorldPoint);
|
| 368 |
|
| 369 |
worldDiff.sub2(toWorldPoint, fromWorldPoint);
|
| 370 |
|
| 371 |
+
// Enforce minY via test sur la position caméra résultante
|
| 372 |
var proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
|
|
|
|
|
|
|
| 373 |
|
| 374 |
+
// calcule Y caméra si on acceptait ce pivot (sans bbox ici)
|
| 375 |
+
var camY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
|
| 376 |
+
if (camY >= this.orbitCamera.minY - 1e-4) {
|
| 377 |
this.orbitCamera.pivotPoint.copy(proposedPivot);
|
| 378 |
} else {
|
| 379 |
+
// Essai horizontal-only
|
| 380 |
worldDiff.y = 0;
|
| 381 |
proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
|
| 382 |
+
camY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
|
| 383 |
+
if (camY >= this.orbitCamera.minY - 1e-4) {
|
|
|
|
| 384 |
this.orbitCamera.pivotPoint.copy(proposedPivot);
|
| 385 |
}
|
| 386 |
}
|
|
|
|
| 528 |
var resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
|
| 529 |
|
| 530 |
if (resultingY >= minY - 1e-4) {
|
|
|
|
| 531 |
this.orbitCamera.pivotPoint.copy(proposedPivot);
|
| 532 |
} else {
|
| 533 |
worldDiff.y = 0;
|
| 534 |
proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
|
| 535 |
resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
|
| 536 |
if (resultingY >= minY - 1e-4) {
|
|
|
|
| 537 |
this.orbitCamera.pivotPoint.copy(proposedPivot);
|
| 538 |
}
|
| 539 |
}
|
|
|
|
| 596 |
|
| 597 |
// =================== Orbit Camera Input Keyboard ========================
|
| 598 |
// Flèches : déplacement avant/arrière & droite/gauche (repère caméra, 3D)
|
| 599 |
+
// Ctrl+flèches : orbiter autour du pivot (avec test minY)
|
| 600 |
// Maj+flèches : rotation libre sur place (pas de limites yaw/pitch)
|
| 601 |
var OrbitCameraInputKeyboard = pc.createScript('orbitCameraInputKeyboard');
|
| 602 |
|
|
|
|
| 678 |
var q = new pc.Quat().setFromEulerAngles(this.orbitCamera._pitch, this.orbitCamera._yaw, 0);
|
| 679 |
var forward = new pc.Vec3(); q.transformVector(pc.Vec3.FORWARD, forward);
|
| 680 |
var newPivot = camPos.clone().add(forward.clone().mulScalar(dist));
|
|
|
|
| 681 |
this.orbitCamera._pivotPoint.copy(newPivot);
|
| 682 |
|
| 683 |
this.orbitCamera._removeInertia();
|
|
|
|
| 712 |
if (currCamY + delta.y < minY) {
|
| 713 |
delta.y = minY - currCamY;
|
| 714 |
}
|
| 715 |
+
this.orbitCamera._pivotPoint.add(delta);
|
|
|
|
|
|
|
| 716 |
}
|
| 717 |
};
|