MikaFil commited on
Commit
0073426
·
verified ·
1 Parent(s): 986d444

Update orbit-camera.js

Browse files
Files changed (1) hide show
  1. orbit-camera.js +65 -195
orbit-camera.js CHANGED
@@ -1,91 +1,45 @@
1
- // orbit-camera.js (fixed to clamp world Y at minY, with debug logs)
2
-
3
- ///////////////////////////////////////////////////////////////////////////////
4
- // Orbit Camera Script //
5
- ///////////////////////////////////////////////////////////////////////////////
6
 
7
  var OrbitCamera = pc.createScript('orbitCamera');
8
 
9
- OrbitCamera.attributes.add('distanceMax', { type: 'number', default: 20, title: 'Distance Max', description: 'Setting this at 0 will give an infinite distance limit' });
 
10
  OrbitCamera.attributes.add('distanceMin', { type: 'number', default: 1, title: 'Distance Min' });
11
  OrbitCamera.attributes.add('pitchAngleMax', { type: 'number', default: 90, title: 'Pitch Angle Max (degrees)' });
12
- // Note: This default will be overridden by your JSON config. In your JSON you set minAngle to -90.
13
  OrbitCamera.attributes.add('pitchAngleMin', { type: 'number', default: 0, title: 'Pitch Angle Min (degrees)' });
14
  OrbitCamera.attributes.add('yawAngleMax', { type: 'number', default: 360, title: 'Yaw Angle Max (degrees)' });
15
  OrbitCamera.attributes.add('yawAngleMin', { type: 'number', default: -360, title: 'Yaw Angle Min (degrees)' });
16
- OrbitCamera.attributes.add('minY', { type: 'number', default: 0, title: 'Minimum Y', description: 'Minimum Y value for the camera during orbiting or translation' });
17
-
18
- OrbitCamera.attributes.add('inertiaFactor', {
19
- type: 'number',
20
- default: 0.2,
21
- title: 'Inertia Factor',
22
- description: 'Higher value means that the camera will continue moving after the user has stopped dragging. 0 is fully responsive.'
23
- });
24
-
25
- OrbitCamera.attributes.add('focusEntity', {
26
- type: 'entity',
27
- title: 'Focus Entity',
28
- description: 'Entity for the camera to focus on. If blank, then the camera will use the whole scene'
29
- });
30
 
31
- OrbitCamera.attributes.add('frameOnStart', {
32
- type: 'boolean',
33
- default: true,
34
- title: 'Frame on Start',
35
- description: 'Frames the entity or scene at the start of the application."'
36
- });
37
 
38
- // Property to get and set the distance between the pivot point and camera
39
  Object.defineProperty(OrbitCamera.prototype, 'distance', {
40
- get: function () {
41
- return this._targetDistance;
42
- },
43
- set: function (value) {
44
- this._targetDistance = this._clampDistance(value);
45
- }
46
  });
47
 
48
- // Property to get and set the camera orthoHeight (clamped above 0)
49
  Object.defineProperty(OrbitCamera.prototype, 'orthoHeight', {
50
- get: function () {
51
- return this.entity.camera.orthoHeight;
52
- },
53
- set: function (value) {
54
- this.entity.camera.orthoHeight = Math.max(0, value);
55
- }
56
  });
57
 
58
- // Property to get and set the pitch (in degrees) of the camera around the pivot.
59
  Object.defineProperty(OrbitCamera.prototype, 'pitch', {
60
- get: function () {
61
- return this._targetPitch;
62
- },
63
- set: function (value) {
64
- this._targetPitch = this._clampPitchAngle(value);
65
- }
66
  });
67
 
68
- // Property to get and set the yaw (in degrees) of the camera around the pivot.
69
  Object.defineProperty(OrbitCamera.prototype, 'yaw', {
70
- get: function () {
71
- return this._targetYaw;
72
- },
73
- set: function (value) {
74
- this._targetYaw = this._clampYawAngle(value);
75
- }
76
  });
77
 
78
- // Property to get and set the world position of the pivot point that the camera orbits around.
79
  Object.defineProperty(OrbitCamera.prototype, 'pivotPoint', {
80
- get: function () {
81
- return this._pivotPoint;
82
- },
83
- set: function (value) {
84
- this._pivotPoint.copy(value);
85
- }
86
  });
87
 
88
- // Moves the camera to look at an entity and all its children so they are all in view.
89
  OrbitCamera.prototype.focus = function (focusEntity) {
90
  this._buildAabb(focusEntity);
91
  var halfExtents = this._modelsAabb.halfExtents;
@@ -138,16 +92,24 @@ OrbitCamera.prototype.resetToPosition = function (position, lookAtPoint) {
138
  this._updatePosition();
139
  };
140
 
 
 
 
 
 
 
 
 
 
 
 
141
  ////////////////////////////////////////////////////////////////////////////////
142
  // Private Methods //
143
  ////////////////////////////////////////////////////////////////////////////////
144
 
145
  OrbitCamera.prototype.initialize = function () {
146
  var self = this;
147
- var onWindowResize = function () {
148
- self._checkAspectRatio();
149
- };
150
-
151
  window.addEventListener('resize', onWindowResize, false);
152
  this._checkAspectRatio();
153
  this._modelsAabb = new pc.BoundingBox();
@@ -162,7 +124,6 @@ OrbitCamera.prototype.initialize = function () {
162
  this._distance = 0;
163
  this._targetYaw = this._yaw;
164
  this._targetPitch = this._pitch;
165
-
166
  if (this.frameOnStart) {
167
  this.focus(this.focusEntity || this.app.root);
168
  } else {
@@ -170,36 +131,19 @@ OrbitCamera.prototype.initialize = function () {
170
  distanceBetween.sub2(this.entity.getPosition(), this._pivotPoint);
171
  this._distance = this._clampDistance(distanceBetween.length());
172
  }
173
-
174
  this._targetDistance = this._distance;
175
-
176
- this.on('attr:distanceMin', function (value, prev) {
177
- this._distance = this._clampDistance(this._distance);
178
- });
179
- this.on('attr:distanceMax', function (value, prev) {
180
- this._distance = this._clampDistance(this._distance);
181
- });
182
- this.on('attr:pitchAngleMin', function (value, prev) {
183
- this._pitch = this._clampPitchAngle(this._pitch);
184
- });
185
- this.on('attr:pitchAngleMax', function (value, prev) {
186
- this._pitch = this._clampPitchAngle(this._pitch);
187
- });
188
  this.on('attr:focusEntity', function (value, prev) {
189
- if (this.frameOnStart) {
190
- this.focus(value || this.app.root);
191
- } else {
192
- this.resetAndLookAtEntity(this.entity.getPosition(), value || this.app.root);
193
- }
194
  });
195
  this.on('attr:frameOnStart', function (value, prev) {
196
- if (value) {
197
- this.focus(this.focusEntity || this.app.root);
198
- }
199
- });
200
- this.on('destroy', function () {
201
- window.removeEventListener('resize', onWindowResize, false);
202
  });
 
203
  };
204
 
205
  OrbitCamera.prototype.update = function (dt) {
@@ -217,7 +161,7 @@ OrbitCamera.prototype._updatePosition = function () {
217
  position.copy(this.entity.forward);
218
  position.mulScalar(-this._distance);
219
  position.add(this.pivotPoint);
220
- // Clamp camera's Y position so it never goes below minY (after all rotations)
221
  position.y = Math.max(position.y, this.minY);
222
  this.entity.setPosition(position);
223
  };
@@ -301,23 +245,11 @@ OrbitCamera.prototype._calcPitch = function (quat, yaw) {
301
  return Math.atan2(-transformedForward.y, -transformedForward.z) * pc.math.RAD_TO_DEG;
302
  };
303
 
304
- ////////////////////////////////////////////////////////////////////////////////
305
- // Orbit Camera Mouse Input Script //
306
- ////////////////////////////////////////////////////////////////////////////////
307
  var OrbitCameraInputMouse = pc.createScript('orbitCameraInputMouse');
 
 
308
 
309
- OrbitCameraInputMouse.attributes.add('orbitSensitivity', {
310
- type: 'number',
311
- default: 0.3,
312
- title: 'Orbit Sensitivity',
313
- description: 'How fast the camera moves around the orbit. Higher is faster'
314
- });
315
- OrbitCameraInputMouse.attributes.add('distanceSensitivity', {
316
- type: 'number',
317
- default: 0.4,
318
- title: 'Distance Sensitivity',
319
- description: 'How fast the camera moves in and out. Higher is faster'
320
- });
321
  OrbitCameraInputMouse.prototype.initialize = function () {
322
  this.orbitCamera = this.entity.script.orbitCamera;
323
  if (this.orbitCamera) {
@@ -341,22 +273,10 @@ OrbitCameraInputMouse.prototype.initialize = function () {
341
  this.panButtonDown = false;
342
  this.lastPoint = new pc.Vec2();
343
  };
344
-
345
- // Returns the resulting camera world position Y for a pivot
346
- OrbitCamera.prototype.worldCameraYForPivot = function(pivot) {
347
- var quat = new pc.Quat();
348
- quat.setFromEulerAngles(this._pitch, this._yaw, 0);
349
- var forward = new pc.Vec3();
350
- quat.transformVector(pc.Vec3.FORWARD, forward);
351
- var camPos = pivot.clone();
352
- camPos.add(forward.clone().scale(-this._distance));
353
- return camPos.y;
354
- };
355
-
356
-
357
  OrbitCameraInputMouse.fromWorldPoint = new pc.Vec3();
358
  OrbitCameraInputMouse.toWorldPoint = new pc.Vec3();
359
  OrbitCameraInputMouse.worldDiff = new pc.Vec3();
 
360
  OrbitCameraInputMouse.prototype.pan = function (screenPoint) {
361
  var fromWorldPoint = OrbitCameraInputMouse.fromWorldPoint;
362
  var toWorldPoint = OrbitCameraInputMouse.toWorldPoint;
@@ -367,53 +287,39 @@ OrbitCameraInputMouse.prototype.pan = function (screenPoint) {
367
  camera.screenToWorld(this.lastPoint.x, this.lastPoint.y, distance, toWorldPoint);
368
  worldDiff.sub2(toWorldPoint, fromWorldPoint);
369
 
370
- // Try proposed new pivot
371
  var proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
372
  var minY = this.orbitCamera.minY;
373
  var resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
 
374
  if (resultingY >= minY - 1e-4) {
375
  this.orbitCamera.pivotPoint.add(worldDiff);
376
  } else {
377
- // Optionally, restrict only vertical panning
378
  worldDiff.y = 0;
379
  proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
380
  resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
381
  if (resultingY >= minY - 1e-4) {
382
  this.orbitCamera.pivotPoint.add(worldDiff);
383
  }
384
- // else, do nothing (block pan)
385
- }
386
-
387
- var pitchRadians = this.orbitCamera.pitch * pc.math.DEG_TO_RAD;
388
- var minPivotY = this.orbitCamera.distance * Math.sin(pitchRadians);
389
- if (this.orbitCamera.pivotPoint.y < minPivotY) {
390
- this.orbitCamera.pivotPoint.y = minPivotY;
391
  }
392
  };
 
393
  OrbitCameraInputMouse.prototype.onMouseDown = function (event) {
394
  switch (event.button) {
395
- case pc.MOUSEBUTTON_LEFT:
396
- this.panButtonDown = true;
397
- break;
398
  case pc.MOUSEBUTTON_MIDDLE:
399
- case pc.MOUSEBUTTON_RIGHT:
400
- this.lookButtonDown = true;
401
- break;
402
  }
403
  };
404
  OrbitCameraInputMouse.prototype.onMouseUp = function (event) {
405
  switch (event.button) {
406
- case pc.MOUSEBUTTON_LEFT:
407
- this.panButtonDown = false;
408
- break;
409
  case pc.MOUSEBUTTON_MIDDLE:
410
- case pc.MOUSEBUTTON_RIGHT:
411
- this.lookButtonDown = false;
412
- break;
413
  }
414
  };
415
-
416
- // ---------- PATCHED: orbit suppression at minY (mouse) ---------------
417
  OrbitCameraInputMouse.prototype.onMouseMove = function (event) {
418
  if (this.lookButtonDown) {
419
  var sens = this.orbitSensitivity;
@@ -425,14 +331,12 @@ OrbitCameraInputMouse.prototype.onMouseMove = function (event) {
425
  var currDist = this.orbitCamera.distance;
426
  var currPivot = this.orbitCamera.pivotPoint.clone();
427
 
428
- // Compute the world position before the change
429
  var camQuat = new pc.Quat();
430
  camQuat.setFromEulerAngles(currPitch, currYaw, 0);
431
  var forward = new pc.Vec3();
432
  camQuat.transformVector(pc.Vec3.FORWARD, forward);
433
  var preY = currPivot.y + (-forward.y) * currDist;
434
 
435
- // Compute the world position after applying the vertical delta
436
  var proposedPitch = currPitch - deltaPitch;
437
  var testQuat = new pc.Quat();
438
  testQuat.setFromEulerAngles(proposedPitch, currYaw, 0);
@@ -441,26 +345,18 @@ OrbitCameraInputMouse.prototype.onMouseMove = function (event) {
441
  var proposedY = currPivot.y + (-testForward.y) * currDist;
442
 
443
  var minY = this.orbitCamera.minY;
444
- var isAtMinY = preY <= minY + 1e-4;
445
  var wouldGoBelow = proposedY < minY - 1e-4;
446
- var suppressed = false;
447
-
448
- // Only suppress if going *further* below minY (upward)
449
  if (wouldGoBelow && (proposedY < preY)) {
450
- // Suppress vertical, allow horizontal (yaw)
451
  this.orbitCamera.yaw = currYaw - deltaYaw;
452
- suppressed = true;
453
  } else {
454
  this.orbitCamera.pitch = proposedPitch;
455
  this.orbitCamera.yaw = currYaw - deltaYaw;
456
  }
457
-
458
  } else if (this.panButtonDown) {
459
  this.pan(new pc.Vec2(event.x, event.y));
460
  }
461
  this.lastPoint.set(event.x, event.y);
462
  };
463
- // ---------------------------------------------------------------------
464
 
465
  OrbitCameraInputMouse.prototype.onMouseWheel = function (event) {
466
  if (this.entity.camera.projection === pc.PROJECTION_PERSPECTIVE) {
@@ -475,23 +371,10 @@ OrbitCameraInputMouse.prototype.onMouseOut = function (event) {
475
  this.panButtonDown = false;
476
  };
477
 
478
- ////////////////////////////////////////////////////////////////////////////////
479
- // Orbit Camera Touch Input Script //
480
- ////////////////////////////////////////////////////////////////////////////////
481
  var OrbitCameraInputTouch = pc.createScript('orbitCameraInputTouch');
482
-
483
- OrbitCameraInputTouch.attributes.add('orbitSensitivity', {
484
- type: 'number',
485
- default: 0.6,
486
- title: 'Orbit Sensitivity',
487
- description: 'How fast the camera moves around the orbit. Higher is faster'
488
- });
489
- OrbitCameraInputTouch.attributes.add('distanceSensitivity', {
490
- type: 'number',
491
- default: 0.5,
492
- title: 'Distance Sensitivity',
493
- description: 'How fast the camera moves in and out. Higher is faster'
494
- });
495
  OrbitCameraInputTouch.prototype.initialize = function () {
496
  this.orbitCamera = this.entity.script.orbitCamera;
497
  this.lastTouchPoint = new pc.Vec2();
@@ -542,30 +425,25 @@ OrbitCameraInputTouch.prototype.pan = function (midPoint) {
542
  camera.screenToWorld(midPoint.x, midPoint.y, distance, fromWorldPoint);
543
  camera.screenToWorld(this.lastPinchMidPoint.x, this.lastPinchMidPoint.y, distance, toWorldPoint);
544
  worldDiff.sub2(toWorldPoint, fromWorldPoint);
545
-
546
  var proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
547
  var minY = this.orbitCamera.minY;
548
  var resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
 
549
  if (resultingY >= minY - 1e-4) {
550
- this.orbitCamera.pivotPoint.add(worldDiff);
551
- } else {
552
- worldDiff.y = 0;
553
- proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
554
- resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
555
- if (resultingY >= minY - 1e-4) {
556
  this.orbitCamera.pivotPoint.add(worldDiff);
557
- }
558
- }
559
-
560
- var pitchRadians = this.orbitCamera.pitch * pc.math.DEG_TO_RAD;
561
- var minPivotY = this.orbitCamera.distance * Math.sin(pitchRadians);
562
- if (this.orbitCamera.pivotPoint.y < minPivotY) {
563
- this.orbitCamera.pivotPoint.y = minPivotY;
564
  }
565
  };
 
566
  OrbitCameraInputTouch.pinchMidPoint = new pc.Vec2();
567
 
568
- // ---------- PATCHED: orbit suppression at minY (touch) ---------------
569
  OrbitCameraInputTouch.prototype.onTouchMove = function (event) {
570
  var pinchMidPoint = OrbitCameraInputTouch.pinchMidPoint;
571
  var touches = event.touches;
@@ -580,14 +458,12 @@ OrbitCameraInputTouch.prototype.onTouchMove = function (event) {
580
  var currDist = this.orbitCamera.distance;
581
  var currPivot = this.orbitCamera.pivotPoint.clone();
582
 
583
- // Compute the world position before the change
584
  var camQuat = new pc.Quat();
585
  camQuat.setFromEulerAngles(currPitch, currYaw, 0);
586
  var forward = new pc.Vec3();
587
  camQuat.transformVector(pc.Vec3.FORWARD, forward);
588
  var preY = currPivot.y + (-forward.y) * currDist;
589
 
590
- // Compute the world position after applying the vertical delta
591
  var proposedPitch = currPitch - deltaPitch;
592
  var testQuat = new pc.Quat();
593
  testQuat.setFromEulerAngles(proposedPitch, currYaw, 0);
@@ -596,19 +472,13 @@ OrbitCameraInputTouch.prototype.onTouchMove = function (event) {
596
  var proposedY = currPivot.y + (-testForward.y) * currDist;
597
 
598
  var minY = this.orbitCamera.minY;
599
- var isAtMinY = preY <= minY + 1e-4;
600
  var wouldGoBelow = proposedY < minY - 1e-4;
601
- var suppressed = false;
602
-
603
  if (wouldGoBelow && (proposedY < preY)) {
604
- // Suppress vertical, allow horizontal (yaw)
605
  this.orbitCamera.yaw = currYaw - deltaYaw;
606
- suppressed = true;
607
  } else {
608
  this.orbitCamera.pitch = proposedPitch;
609
  this.orbitCamera.yaw = currYaw - deltaYaw;
610
  }
611
-
612
  this.lastTouchPoint.set(touch.x, touch.y);
613
  } else if (touches.length === 2) {
614
  var currentPinchDistance = this.getPinchDistance(touches[0], touches[1]);
@@ -620,4 +490,4 @@ OrbitCameraInputTouch.prototype.onTouchMove = function (event) {
620
  this.lastPinchMidPoint.copy(pinchMidPoint);
621
  }
622
  };
623
- // ---------------------------------------------------------------------
 
1
+ // orbit-camera.js
 
 
 
 
2
 
3
  var OrbitCamera = pc.createScript('orbitCamera');
4
 
5
+ // Camera attributes
6
+ OrbitCamera.attributes.add('distanceMax', { type: 'number', default: 20, title: 'Distance Max' });
7
  OrbitCamera.attributes.add('distanceMin', { type: 'number', default: 1, title: 'Distance Min' });
8
  OrbitCamera.attributes.add('pitchAngleMax', { type: 'number', default: 90, title: 'Pitch Angle Max (degrees)' });
 
9
  OrbitCamera.attributes.add('pitchAngleMin', { type: 'number', default: 0, title: 'Pitch Angle Min (degrees)' });
10
  OrbitCamera.attributes.add('yawAngleMax', { type: 'number', default: 360, title: 'Yaw Angle Max (degrees)' });
11
  OrbitCamera.attributes.add('yawAngleMin', { type: 'number', default: -360, title: 'Yaw Angle Min (degrees)' });
12
+ OrbitCamera.attributes.add('minY', { type: 'number', default: 0, title: 'Minimum Y', description: 'Minimum Y value for camera world position' });
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
+ OrbitCamera.attributes.add('inertiaFactor', { type: 'number', default: 0.2, title: 'Inertia Factor' });
15
+ OrbitCamera.attributes.add('focusEntity', { type: 'entity', title: 'Focus Entity' });
16
+ OrbitCamera.attributes.add('frameOnStart', { type: 'boolean', default: true, title: 'Frame on Start' });
 
 
 
17
 
 
18
  Object.defineProperty(OrbitCamera.prototype, 'distance', {
19
+ get: function () { return this._targetDistance; },
20
+ set: function (value) { this._targetDistance = this._clampDistance(value); }
 
 
 
 
21
  });
22
 
 
23
  Object.defineProperty(OrbitCamera.prototype, 'orthoHeight', {
24
+ get: function () { return this.entity.camera.orthoHeight; },
25
+ set: function (value) { this.entity.camera.orthoHeight = Math.max(0, value); }
 
 
 
 
26
  });
27
 
 
28
  Object.defineProperty(OrbitCamera.prototype, 'pitch', {
29
+ get: function () { return this._targetPitch; },
30
+ set: function (value) { this._targetPitch = this._clampPitchAngle(value); }
 
 
 
 
31
  });
32
 
 
33
  Object.defineProperty(OrbitCamera.prototype, 'yaw', {
34
+ get: function () { return this._targetYaw; },
35
+ set: function (value) { this._targetYaw = this._clampYawAngle(value); }
 
 
 
 
36
  });
37
 
 
38
  Object.defineProperty(OrbitCamera.prototype, 'pivotPoint', {
39
+ get: function () { return this._pivotPoint; },
40
+ set: function (value) { this._pivotPoint.copy(value); }
 
 
 
 
41
  });
42
 
 
43
  OrbitCamera.prototype.focus = function (focusEntity) {
44
  this._buildAabb(focusEntity);
45
  var halfExtents = this._modelsAabb.halfExtents;
 
92
  this._updatePosition();
93
  };
94
 
95
+ // ==== Clamp helper for panning/orbiting so camera never under minY ====
96
+ OrbitCamera.prototype.worldCameraYForPivot = function(pivot) {
97
+ var quat = new pc.Quat();
98
+ quat.setFromEulerAngles(this._pitch, this._yaw, 0);
99
+ var forward = new pc.Vec3();
100
+ quat.transformVector(pc.Vec3.FORWARD, forward);
101
+ var camPos = pivot.clone();
102
+ camPos.add(forward.clone().scale(-this._distance));
103
+ return camPos.y;
104
+ };
105
+
106
  ////////////////////////////////////////////////////////////////////////////////
107
  // Private Methods //
108
  ////////////////////////////////////////////////////////////////////////////////
109
 
110
  OrbitCamera.prototype.initialize = function () {
111
  var self = this;
112
+ var onWindowResize = function () { self._checkAspectRatio(); };
 
 
 
113
  window.addEventListener('resize', onWindowResize, false);
114
  this._checkAspectRatio();
115
  this._modelsAabb = new pc.BoundingBox();
 
124
  this._distance = 0;
125
  this._targetYaw = this._yaw;
126
  this._targetPitch = this._pitch;
 
127
  if (this.frameOnStart) {
128
  this.focus(this.focusEntity || this.app.root);
129
  } else {
 
131
  distanceBetween.sub2(this.entity.getPosition(), this._pivotPoint);
132
  this._distance = this._clampDistance(distanceBetween.length());
133
  }
 
134
  this._targetDistance = this._distance;
135
+ this.on('attr:distanceMin', function (value, prev) { this._distance = this._clampDistance(this._distance); });
136
+ this.on('attr:distanceMax', function (value, prev) { this._distance = this._clampDistance(this._distance); });
137
+ this.on('attr:pitchAngleMin', function (value, prev) { this._pitch = this._clampPitchAngle(this._pitch); });
138
+ this.on('attr:pitchAngleMax', function (value, prev) { this._pitch = this._clampPitchAngle(this._pitch); });
 
 
 
 
 
 
 
 
 
139
  this.on('attr:focusEntity', function (value, prev) {
140
+ if (this.frameOnStart) { this.focus(value || this.app.root); }
141
+ else { this.resetAndLookAtEntity(this.entity.getPosition(), value || this.app.root); }
 
 
 
142
  });
143
  this.on('attr:frameOnStart', function (value, prev) {
144
+ if (value) { this.focus(this.focusEntity || this.app.root); }
 
 
 
 
 
145
  });
146
+ this.on('destroy', function () { window.removeEventListener('resize', onWindowResize, false); });
147
  };
148
 
149
  OrbitCamera.prototype.update = function (dt) {
 
161
  position.copy(this.entity.forward);
162
  position.mulScalar(-this._distance);
163
  position.add(this.pivotPoint);
164
+ // Clamp camera's Y position so it never goes below minY
165
  position.y = Math.max(position.y, this.minY);
166
  this.entity.setPosition(position);
167
  };
 
245
  return Math.atan2(-transformedForward.y, -transformedForward.z) * pc.math.RAD_TO_DEG;
246
  };
247
 
248
+ // ===================== Orbit Camera Input Mouse Script ========================
 
 
249
  var OrbitCameraInputMouse = pc.createScript('orbitCameraInputMouse');
250
+ OrbitCameraInputMouse.attributes.add('orbitSensitivity', { type: 'number', default: 0.3, title: 'Orbit Sensitivity' });
251
+ OrbitCameraInputMouse.attributes.add('distanceSensitivity', { type: 'number', default: 0.4, title: 'Distance Sensitivity' });
252
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  OrbitCameraInputMouse.prototype.initialize = function () {
254
  this.orbitCamera = this.entity.script.orbitCamera;
255
  if (this.orbitCamera) {
 
273
  this.panButtonDown = false;
274
  this.lastPoint = new pc.Vec2();
275
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
276
  OrbitCameraInputMouse.fromWorldPoint = new pc.Vec3();
277
  OrbitCameraInputMouse.toWorldPoint = new pc.Vec3();
278
  OrbitCameraInputMouse.worldDiff = new pc.Vec3();
279
+
280
  OrbitCameraInputMouse.prototype.pan = function (screenPoint) {
281
  var fromWorldPoint = OrbitCameraInputMouse.fromWorldPoint;
282
  var toWorldPoint = OrbitCameraInputMouse.toWorldPoint;
 
287
  camera.screenToWorld(this.lastPoint.x, this.lastPoint.y, distance, toWorldPoint);
288
  worldDiff.sub2(toWorldPoint, fromWorldPoint);
289
 
290
+ // Clamp so camera never goes below minY
291
  var proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
292
  var minY = this.orbitCamera.minY;
293
  var resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
294
+
295
  if (resultingY >= minY - 1e-4) {
296
  this.orbitCamera.pivotPoint.add(worldDiff);
297
  } else {
298
+ // Only allow horizontal pan if it would help
299
  worldDiff.y = 0;
300
  proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
301
  resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
302
  if (resultingY >= minY - 1e-4) {
303
  this.orbitCamera.pivotPoint.add(worldDiff);
304
  }
305
+ // Otherwise, suppress pan
 
 
 
 
 
 
306
  }
307
  };
308
+
309
  OrbitCameraInputMouse.prototype.onMouseDown = function (event) {
310
  switch (event.button) {
311
+ case pc.MOUSEBUTTON_LEFT: this.panButtonDown = true; break;
 
 
312
  case pc.MOUSEBUTTON_MIDDLE:
313
+ case pc.MOUSEBUTTON_RIGHT: this.lookButtonDown = true; break;
 
 
314
  }
315
  };
316
  OrbitCameraInputMouse.prototype.onMouseUp = function (event) {
317
  switch (event.button) {
318
+ case pc.MOUSEBUTTON_LEFT: this.panButtonDown = false; break;
 
 
319
  case pc.MOUSEBUTTON_MIDDLE:
320
+ case pc.MOUSEBUTTON_RIGHT: this.lookButtonDown = false; break;
 
 
321
  }
322
  };
 
 
323
  OrbitCameraInputMouse.prototype.onMouseMove = function (event) {
324
  if (this.lookButtonDown) {
325
  var sens = this.orbitSensitivity;
 
331
  var currDist = this.orbitCamera.distance;
332
  var currPivot = this.orbitCamera.pivotPoint.clone();
333
 
 
334
  var camQuat = new pc.Quat();
335
  camQuat.setFromEulerAngles(currPitch, currYaw, 0);
336
  var forward = new pc.Vec3();
337
  camQuat.transformVector(pc.Vec3.FORWARD, forward);
338
  var preY = currPivot.y + (-forward.y) * currDist;
339
 
 
340
  var proposedPitch = currPitch - deltaPitch;
341
  var testQuat = new pc.Quat();
342
  testQuat.setFromEulerAngles(proposedPitch, currYaw, 0);
 
345
  var proposedY = currPivot.y + (-testForward.y) * currDist;
346
 
347
  var minY = this.orbitCamera.minY;
 
348
  var wouldGoBelow = proposedY < minY - 1e-4;
 
 
 
349
  if (wouldGoBelow && (proposedY < preY)) {
 
350
  this.orbitCamera.yaw = currYaw - deltaYaw;
 
351
  } else {
352
  this.orbitCamera.pitch = proposedPitch;
353
  this.orbitCamera.yaw = currYaw - deltaYaw;
354
  }
 
355
  } else if (this.panButtonDown) {
356
  this.pan(new pc.Vec2(event.x, event.y));
357
  }
358
  this.lastPoint.set(event.x, event.y);
359
  };
 
360
 
361
  OrbitCameraInputMouse.prototype.onMouseWheel = function (event) {
362
  if (this.entity.camera.projection === pc.PROJECTION_PERSPECTIVE) {
 
371
  this.panButtonDown = false;
372
  };
373
 
374
+ // =================== Orbit Camera Input Touch Script ========================
 
 
375
  var OrbitCameraInputTouch = pc.createScript('orbitCameraInputTouch');
376
+ OrbitCameraInputTouch.attributes.add('orbitSensitivity', { type: 'number', default: 0.6, title: 'Orbit Sensitivity' });
377
+ OrbitCameraInputTouch.attributes.add('distanceSensitivity', { type: 'number', default: 0.5, title: 'Distance Sensitivity' });
 
 
 
 
 
 
 
 
 
 
 
378
  OrbitCameraInputTouch.prototype.initialize = function () {
379
  this.orbitCamera = this.entity.script.orbitCamera;
380
  this.lastTouchPoint = new pc.Vec2();
 
425
  camera.screenToWorld(midPoint.x, midPoint.y, distance, fromWorldPoint);
426
  camera.screenToWorld(this.lastPinchMidPoint.x, this.lastPinchMidPoint.y, distance, toWorldPoint);
427
  worldDiff.sub2(toWorldPoint, fromWorldPoint);
428
+
429
  var proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
430
  var minY = this.orbitCamera.minY;
431
  var resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
432
+
433
  if (resultingY >= minY - 1e-4) {
 
 
 
 
 
 
434
  this.orbitCamera.pivotPoint.add(worldDiff);
435
+ } else {
436
+ worldDiff.y = 0;
437
+ proposedPivot = this.orbitCamera.pivotPoint.clone().add(worldDiff);
438
+ resultingY = this.orbitCamera.worldCameraYForPivot(proposedPivot);
439
+ if (resultingY >= minY - 1e-4) {
440
+ this.orbitCamera.pivotPoint.add(worldDiff);
441
+ }
442
  }
443
  };
444
+
445
  OrbitCameraInputTouch.pinchMidPoint = new pc.Vec2();
446
 
 
447
  OrbitCameraInputTouch.prototype.onTouchMove = function (event) {
448
  var pinchMidPoint = OrbitCameraInputTouch.pinchMidPoint;
449
  var touches = event.touches;
 
458
  var currDist = this.orbitCamera.distance;
459
  var currPivot = this.orbitCamera.pivotPoint.clone();
460
 
 
461
  var camQuat = new pc.Quat();
462
  camQuat.setFromEulerAngles(currPitch, currYaw, 0);
463
  var forward = new pc.Vec3();
464
  camQuat.transformVector(pc.Vec3.FORWARD, forward);
465
  var preY = currPivot.y + (-forward.y) * currDist;
466
 
 
467
  var proposedPitch = currPitch - deltaPitch;
468
  var testQuat = new pc.Quat();
469
  testQuat.setFromEulerAngles(proposedPitch, currYaw, 0);
 
472
  var proposedY = currPivot.y + (-testForward.y) * currDist;
473
 
474
  var minY = this.orbitCamera.minY;
 
475
  var wouldGoBelow = proposedY < minY - 1e-4;
 
 
476
  if (wouldGoBelow && (proposedY < preY)) {
 
477
  this.orbitCamera.yaw = currYaw - deltaYaw;
 
478
  } else {
479
  this.orbitCamera.pitch = proposedPitch;
480
  this.orbitCamera.yaw = currYaw - deltaYaw;
481
  }
 
482
  this.lastTouchPoint.set(touch.x, touch.y);
483
  } else if (touches.length === 2) {
484
  var currentPinchDistance = this.getPinchDistance(touches[0], touches[1]);
 
490
  this.lastPinchMidPoint.copy(pinchMidPoint);
491
  }
492
  };
493
+