Spaces:
Running
Running
Update deplacement_dans_env/ctrl_camera_pr_env.js
Browse files
deplacement_dans_env/ctrl_camera_pr_env.js
CHANGED
|
@@ -35,13 +35,10 @@ FreeCamera.attributes.add('maxStepDistance', { type: 'number', default: 0.20, ti
|
|
| 35 |
FreeCamera.attributes.add('maxResolveIters', { type: 'number', default: 6, title: 'Max resolve iterations per step' });
|
| 36 |
|
| 37 |
// Construction des colliders
|
| 38 |
-
// IMPORTANT: garder très petit; on n'"épaissit" plus agressivement pour l'indoor
|
| 39 |
FreeCamera.attributes.add('inflateBias', { type: 'number', default: 0.0, title: 'Extra inflate (m, tiny)' });
|
| 40 |
-
// On ne merge presque pas : uniquement si recouvrement réel (tolérance numérique)
|
| 41 |
FreeCamera.attributes.add('mergeGap', { type: 'number', default: 0.0, title: 'Merge AABBs gap (0 = pas de gap)' });
|
| 42 |
|
| 43 |
-
// Filtrage "anti-coquille"
|
| 44 |
-
// Par axe: if halfExtents >= worldHalfExtents * (1 - globalCullFrac) => on la considère "quasi globale".
|
| 45 |
FreeCamera.attributes.add('globalCullFrac', { type: 'number', default: 0.08, title: 'Cull near-global AABBs (0.08=8%)' });
|
| 46 |
|
| 47 |
// Bounding Box globale optionnelle (Xmin..Zmax)
|
|
@@ -86,9 +83,9 @@ FreeCamera.prototype.initialize = function () {
|
|
| 86 |
this.state = this.app.systems.script.app.freeCamState;
|
| 87 |
|
| 88 |
// colliders
|
| 89 |
-
this._buildIndoorSafeColliders();
|
| 90 |
|
| 91 |
-
// Forcer une passe de résolution initiale
|
| 92 |
var p = this.entity.getPosition().clone();
|
| 93 |
p = this._moveSweptTo(p, p);
|
| 94 |
this._clampPosition(p);
|
|
@@ -151,7 +148,7 @@ FreeCamera.prototype._buildIndoorSafeColliders = function () {
|
|
| 151 |
for (var j = 1; j < boxes.length; j++) world.add(boxes[j]);
|
| 152 |
|
| 153 |
// 3) Filtrer les AABBs "quasi globales" (anti-coquille)
|
| 154 |
-
var frac = pc.math.clamp(this.globalCullFrac, 0, 0.49);
|
| 155 |
var wh = world.halfExtents;
|
| 156 |
var filtered = [];
|
| 157 |
for (var k = 0; k < boxes.length; k++) {
|
|
@@ -163,10 +160,10 @@ FreeCamera.prototype._buildIndoorSafeColliders = function () {
|
|
| 163 |
if (!nearGlobal) filtered.push(boxes[k]);
|
| 164 |
}
|
| 165 |
|
| 166 |
-
// 4)
|
| 167 |
var merged = this._mergeAabbs(filtered, Math.max(0, this.mergeGap || 0));
|
| 168 |
|
| 169 |
-
// 5)
|
| 170 |
var inflate = Math.max(0, this.inflateBias || 0);
|
| 171 |
for (var m = 0; m < merged.length; m++) {
|
| 172 |
merged[m].halfExtents.add(new pc.Vec3(inflate, inflate, inflate));
|
|
@@ -178,7 +175,6 @@ FreeCamera.prototype._buildIndoorSafeColliders = function () {
|
|
| 178 |
this._worldAabb = world;
|
| 179 |
this._useCollision = true;
|
| 180 |
} else {
|
| 181 |
-
// Aucun collider utile après filtrage : on désactive les collisions pour ne pas bloquer
|
| 182 |
this._colliders = [];
|
| 183 |
this._useCollision = false;
|
| 184 |
console.warn('[orbitCamera] Aucun collider utile trouvé (désactivation des collisions)');
|
|
@@ -215,11 +211,27 @@ FreeCamera.prototype._mergeAabbs = function (boxes, gap) {
|
|
| 215 |
if (overlap(acc, out[j], tol)) {
|
| 216 |
var aMin = acc.getMin(), aMax = acc.getMax();
|
| 217 |
var bMin = out[j].getMin(), bMax = out[j].getMax();
|
| 218 |
-
|
| 219 |
-
var
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
used[j] = true;
|
| 224 |
changed = true;
|
| 225 |
}
|
|
@@ -247,7 +259,7 @@ FreeCamera.prototype._clampPosition = function (p) {
|
|
| 247 |
|
| 248 |
// ======================== Mouvement swept + résolution =====================
|
| 249 |
FreeCamera.prototype._moveSweptTo = function (from, to) {
|
| 250 |
-
if (!this._useCollision) return to.clone();
|
| 251 |
|
| 252 |
var maxStep = Math.max(0.01, this.maxStepDistance || 0.2);
|
| 253 |
var delta = to.clone().sub(from);
|
|
@@ -287,7 +299,7 @@ FreeCamera.prototype._resolveCollisions = function (pos, maxIters) {
|
|
| 287 |
var aabb = this._colliders[i].aabb;
|
| 288 |
var min = aabb.getMin(); var max = aabb.getMax();
|
| 289 |
|
| 290 |
-
//
|
| 291 |
var cx = pc.math.clamp(p.x, min.x, max.x);
|
| 292 |
var cy = pc.math.clamp(p.y, min.y, max.y);
|
| 293 |
var cz = pc.math.clamp(p.z, min.z, max.z);
|
|
@@ -295,7 +307,6 @@ FreeCamera.prototype._resolveCollisions = function (pos, maxIters) {
|
|
| 295 |
var dx = p.x - cx, dy = p.y - cy, dz = p.z - cz;
|
| 296 |
var distSq = dx*dx + dy*dy + dz*dz;
|
| 297 |
|
| 298 |
-
// Collision sphère vs AABB (AABB non "gonflée" au rayon ; on le traite ici)
|
| 299 |
if (distSq < (R*R)) {
|
| 300 |
var dist = Math.sqrt(Math.max(distSq, 1e-12));
|
| 301 |
var pen = R - dist + eps;
|
|
@@ -305,7 +316,7 @@ FreeCamera.prototype._resolveCollisions = function (pos, maxIters) {
|
|
| 305 |
p.y += (dy / dist) * pen;
|
| 306 |
p.z += (dz / dist) * pen;
|
| 307 |
} else {
|
| 308 |
-
//
|
| 309 |
var ex = Math.min(Math.abs(p.x - min.x), Math.abs(max.x - p.x));
|
| 310 |
var ey = Math.min(Math.abs(p.y - min.y), Math.abs(max.y - p.y));
|
| 311 |
var ez = Math.min(Math.abs(p.z - min.z), Math.abs(max.z - p.z));
|
|
|
|
| 35 |
FreeCamera.attributes.add('maxResolveIters', { type: 'number', default: 6, title: 'Max resolve iterations per step' });
|
| 36 |
|
| 37 |
// Construction des colliders
|
|
|
|
| 38 |
FreeCamera.attributes.add('inflateBias', { type: 'number', default: 0.0, title: 'Extra inflate (m, tiny)' });
|
|
|
|
| 39 |
FreeCamera.attributes.add('mergeGap', { type: 'number', default: 0.0, title: 'Merge AABBs gap (0 = pas de gap)' });
|
| 40 |
|
| 41 |
+
// Filtrage "anti-coquille"
|
|
|
|
| 42 |
FreeCamera.attributes.add('globalCullFrac', { type: 'number', default: 0.08, title: 'Cull near-global AABBs (0.08=8%)' });
|
| 43 |
|
| 44 |
// Bounding Box globale optionnelle (Xmin..Zmax)
|
|
|
|
| 83 |
this.state = this.app.systems.script.app.freeCamState;
|
| 84 |
|
| 85 |
// colliders
|
| 86 |
+
this._buildIndoorSafeColliders();
|
| 87 |
|
| 88 |
+
// Forcer une passe de résolution initiale
|
| 89 |
var p = this.entity.getPosition().clone();
|
| 90 |
p = this._moveSweptTo(p, p);
|
| 91 |
this._clampPosition(p);
|
|
|
|
| 148 |
for (var j = 1; j < boxes.length; j++) world.add(boxes[j]);
|
| 149 |
|
| 150 |
// 3) Filtrer les AABBs "quasi globales" (anti-coquille)
|
| 151 |
+
var frac = pc.math.clamp(this.globalCullFrac, 0, 0.49);
|
| 152 |
var wh = world.halfExtents;
|
| 153 |
var filtered = [];
|
| 154 |
for (var k = 0; k < boxes.length; k++) {
|
|
|
|
| 160 |
if (!nearGlobal) filtered.push(boxes[k]);
|
| 161 |
}
|
| 162 |
|
| 163 |
+
// 4) Merge strict (chevauchement réel uniquement, gap ~ 0)
|
| 164 |
var merged = this._mergeAabbs(filtered, Math.max(0, this.mergeGap || 0));
|
| 165 |
|
| 166 |
+
// 5) Petit gonflage (epsilon), pas du rayon
|
| 167 |
var inflate = Math.max(0, this.inflateBias || 0);
|
| 168 |
for (var m = 0; m < merged.length; m++) {
|
| 169 |
merged[m].halfExtents.add(new pc.Vec3(inflate, inflate, inflate));
|
|
|
|
| 175 |
this._worldAabb = world;
|
| 176 |
this._useCollision = true;
|
| 177 |
} else {
|
|
|
|
| 178 |
this._colliders = [];
|
| 179 |
this._useCollision = false;
|
| 180 |
console.warn('[orbitCamera] Aucun collider utile trouvé (désactivation des collisions)');
|
|
|
|
| 211 |
if (overlap(acc, out[j], tol)) {
|
| 212 |
var aMin = acc.getMin(), aMax = acc.getMax();
|
| 213 |
var bMin = out[j].getMin(), bMax = out[j].getMax();
|
| 214 |
+
|
| 215 |
+
var nMin = new pc.Vec3(
|
| 216 |
+
Math.min(aMin.x, bMin.x),
|
| 217 |
+
Math.min(aMin.y, bMin.y),
|
| 218 |
+
Math.min(aMin.z, bMin.z)
|
| 219 |
+
);
|
| 220 |
+
var nMax = new pc.Vec3(
|
| 221 |
+
Math.max(aMax.x, bMax.x),
|
| 222 |
+
Math.max(aMax.y, bMax.y),
|
| 223 |
+
Math.max(aMax.z, bMax.z)
|
| 224 |
+
);
|
| 225 |
+
var nCenter = nMin.clone().add(nMax).mulScalar(0.5);
|
| 226 |
+
|
| 227 |
+
// ❗️Pas de .abs() sur pc.Vec3 : calculer composante par composante
|
| 228 |
+
var nHalf = new pc.Vec3(
|
| 229 |
+
Math.abs(nMax.x - nCenter.x),
|
| 230 |
+
Math.abs(nMax.y - nCenter.y),
|
| 231 |
+
Math.abs(nMax.z - nCenter.z)
|
| 232 |
+
);
|
| 233 |
+
|
| 234 |
+
acc = new pc.BoundingBox(nCenter, nHalf);
|
| 235 |
used[j] = true;
|
| 236 |
changed = true;
|
| 237 |
}
|
|
|
|
| 259 |
|
| 260 |
// ======================== Mouvement swept + résolution =====================
|
| 261 |
FreeCamera.prototype._moveSweptTo = function (from, to) {
|
| 262 |
+
if (!this._useCollision) return to.clone();
|
| 263 |
|
| 264 |
var maxStep = Math.max(0.01, this.maxStepDistance || 0.2);
|
| 265 |
var delta = to.clone().sub(from);
|
|
|
|
| 299 |
var aabb = this._colliders[i].aabb;
|
| 300 |
var min = aabb.getMin(); var max = aabb.getMax();
|
| 301 |
|
| 302 |
+
// Point le plus proche sur l'AABB
|
| 303 |
var cx = pc.math.clamp(p.x, min.x, max.x);
|
| 304 |
var cy = pc.math.clamp(p.y, min.y, max.y);
|
| 305 |
var cz = pc.math.clamp(p.z, min.z, max.z);
|
|
|
|
| 307 |
var dx = p.x - cx, dy = p.y - cy, dz = p.z - cz;
|
| 308 |
var distSq = dx*dx + dy*dy + dz*dz;
|
| 309 |
|
|
|
|
| 310 |
if (distSq < (R*R)) {
|
| 311 |
var dist = Math.sqrt(Math.max(distSq, 1e-12));
|
| 312 |
var pen = R - dist + eps;
|
|
|
|
| 316 |
p.y += (dy / dist) * pen;
|
| 317 |
p.z += (dz / dist) * pen;
|
| 318 |
} else {
|
| 319 |
+
// pousser selon l'axe le plus "proche"
|
| 320 |
var ex = Math.min(Math.abs(p.x - min.x), Math.abs(max.x - p.x));
|
| 321 |
var ey = Math.min(Math.abs(p.y - min.y), Math.abs(max.y - p.y));
|
| 322 |
var ez = Math.min(Math.abs(p.z - min.z), Math.abs(max.z - p.z));
|