MikaFil commited on
Commit
7bc4269
·
verified ·
1 Parent(s): 6c26003

Update orbit-camera.js

Browse files
Files changed (1) hide show
  1. orbit-camera.js +40 -256
orbit-camera.js CHANGED
@@ -1,3 +1,4 @@
 
1
  ///////////////////////////////////////////////////////////////////////////////
2
  // Orbit Camera Script //
3
  ////////////////////////////////////////////////////////////////////////////////
@@ -35,6 +36,7 @@ OrbitCamera.attributes.add('frameOnStart', {
35
  });
36
 
37
  // Property to get and set the distance between the pivot point and camera
 
38
  Object.defineProperty(OrbitCamera.prototype, 'distance', {
39
  get: function () {
40
  return this._targetDistance;
@@ -55,12 +57,31 @@ Object.defineProperty(OrbitCamera.prototype, 'orthoHeight', {
55
  });
56
 
57
  // Property to get and set the pitch (in degrees) of the camera around the pivot.
 
 
 
58
  Object.defineProperty(OrbitCamera.prototype, 'pitch', {
59
  get: function () {
60
  return this._targetPitch;
61
  },
62
  set: function (value) {
63
- this._targetPitch = this._clampPitchAngle(value);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  }
65
  });
66
 
@@ -86,6 +107,7 @@ Object.defineProperty(OrbitCamera.prototype, 'pivotPoint', {
86
 
87
  // Moves the camera to look at an entity and all its children so they are all in view.
88
  OrbitCamera.prototype.focus = function (focusEntity) {
 
89
  this._buildAabb(focusEntity);
90
  var halfExtents = this._modelsAabb.halfExtents;
91
  var radius = Math.max(halfExtents.x, Math.max(halfExtents.y, halfExtents.z));
@@ -96,6 +118,7 @@ OrbitCamera.prototype.focus = function (focusEntity) {
96
 
97
  OrbitCamera.distanceBetween = new pc.Vec3();
98
 
 
99
  OrbitCamera.prototype.resetAndLookAtPoint = function (resetPoint, lookAtPoint) {
100
  this.pivotPoint.copy(lookAtPoint);
101
  this.entity.setPosition(resetPoint);
@@ -156,6 +179,7 @@ OrbitCamera.prototype.initialize = function () {
156
  this._pivotPoint.copy(this._modelsAabb.center);
157
  var cameraQuat = this.entity.getRotation();
158
  this._yaw = this._calcYaw(cameraQuat);
 
159
  this._pitch = this._clampPitchAngle(this._calcPitch(cameraQuat, this._yaw));
160
  this.entity.setLocalEulerAngles(this._pitch, this._yaw, 0);
161
  this._distance = 0;
@@ -172,26 +196,26 @@ OrbitCamera.prototype.initialize = function () {
172
 
173
  this._targetDistance = this._distance;
174
 
175
- this.on('attr:distanceMin', function (value, prev) {
176
  this._distance = this._clampDistance(this._distance);
177
  });
178
- this.on('attr:distanceMax', function (value, prev) {
179
  this._distance = this._clampDistance(this._distance);
180
  });
181
- this.on('attr:pitchAngleMin', function (value, prev) {
182
  this._pitch = this._clampPitchAngle(this._pitch);
183
  });
184
- this.on('attr:pitchAngleMax', function (value, prev) {
185
  this._pitch = this._clampPitchAngle(this._pitch);
186
  });
187
- this.on('attr:focusEntity', function (value, prev) {
188
  if (this.frameOnStart) {
189
  this.focus(value || this.app.root);
190
  } else {
191
  this.resetAndLookAtEntity(this.entity.getPosition(), value || this.app.root);
192
  }
193
  });
194
- this.on('attr:frameOnStart', function (value, prev) {
195
  if (value) {
196
  this.focus(this.focusEntity || this.app.root);
197
  }
@@ -216,7 +240,7 @@ OrbitCamera.prototype._updatePosition = function () {
216
  position.copy(this.entity.forward);
217
  position.mulScalar(-this._distance);
218
  position.add(this.pivotPoint);
219
- // Clamp the camera's Y position so it never goes below minY.
220
  position.y = Math.max(position.y, this.minY);
221
  this.entity.setPosition(position);
222
  };
@@ -234,11 +258,11 @@ OrbitCamera.prototype._checkAspectRatio = function () {
234
  };
235
 
236
  OrbitCamera.prototype._buildAabb = function (entity) {
237
- var i, m, meshInstances = [];
238
  var renders = entity.findComponents('render');
239
- for (i = 0; i < renders.length; i++) {
240
  var render = renders[i];
241
- for (m = 0; m < render.meshInstances.length; m++) {
242
  meshInstances.push(render.meshInstances[m]);
243
  }
244
  }
@@ -251,9 +275,8 @@ OrbitCamera.prototype._buildAabb = function (entity) {
251
  }
252
  var gsplats = entity.findComponents('gsplat');
253
  for (i = 0; i < gsplats.length; i++) {
254
- var gsplat = gsplats[i];
255
- var instance = gsplat.instance;
256
- if (instance?.meshInstance) {
257
  meshInstances.push(instance.meshInstance);
258
  }
259
  }
@@ -279,27 +302,9 @@ OrbitCamera.prototype._clampDistance = function (distance) {
279
  return Math.max(distance, this.distanceMin);
280
  };
281
 
282
- // ----- FIXED PITCH CLAMPING WITH minY RESPECT -----
283
  OrbitCamera.prototype._clampPitchAngle = function (pitch) {
284
- // Clamp between configured pitchAngleMin/Max first
285
- var clamped = pc.math.clamp(pitch, this.pitchAngleMin, this.pitchAngleMax);
286
-
287
- // Then ensure resulting world-space Y >= minY
288
- // simulate forward vector
289
- var yaw = this._targetYaw;
290
- var quat = new pc.Quat().setFromEulerAngles(clamped, yaw, 0);
291
- var forward = new pc.Vec3();
292
- quat.transformVector(pc.Vec3.FORWARD, forward);
293
- var simulatedY = this._pivotPoint.y - forward.y * this._targetDistance;
294
- if (simulatedY < this.minY) {
295
- // compute max pitch that just reaches minY: asin((pivotY-minY)/distance)
296
- var ratio = (this._pivotPoint.y - this.minY) / this._targetDistance;
297
- ratio = pc.math.clamp(ratio, -1, 1);
298
- var angle = Math.asin(ratio) * pc.math.RAD_TO_DEG;
299
- return pc.math.clamp(angle, this.pitchAngleMin, this.pitchAngleMax);
300
- }
301
-
302
- return clamped;
303
  };
304
 
305
  OrbitCamera.prototype._clampYawAngle = function (yaw) {
@@ -309,7 +314,7 @@ OrbitCamera.prototype._clampYawAngle = function (yaw) {
309
  OrbitCamera.quatWithoutYaw = new pc.Quat();
310
  OrbitCamera.yawOffset = new pc.Quat();
311
 
312
- // ----- REVISED PITCH CALCULATION -----
313
  OrbitCamera.prototype._calcPitch = function (quat, yaw) {
314
  var quatWithoutYaw = OrbitCamera.quatWithoutYaw;
315
  var yawOffset = OrbitCamera.yawOffset;
@@ -319,224 +324,3 @@ OrbitCamera.prototype._calcPitch = function (quat, yaw) {
319
  quatWithoutYaw.transformVector(pc.Vec3.FORWARD, transformedForward);
320
  return Math.atan2(-transformedForward.y, -transformedForward.z) * pc.math.RAD_TO_DEG;
321
  };
322
-
323
-
324
-
325
- ////////////////////////////////////////////////////////////////////////////////
326
- // Orbit Camera Mouse Input Script //
327
- ////////////////////////////////////////////////////////////////////////////////
328
- var OrbitCameraInputMouse = pc.createScript('orbitCameraInputMouse');
329
-
330
- OrbitCameraInputMouse.attributes.add('orbitSensitivity', {
331
- type: 'number',
332
- default: 0.3,
333
- title: 'Orbit Sensitivity',
334
- description: 'How fast the camera moves around the orbit. Higher is faster'
335
- });
336
- OrbitCameraInputMouse.attributes.add('distanceSensitivity', {
337
- type: 'number',
338
- default: 0.4,
339
- title: 'Distance Sensitivity',
340
- description: 'How fast the camera moves in and out. Higher is faster'
341
- });
342
-
343
- OrbitCameraInputMouse.prototype.initialize = function () {
344
- this.orbitCamera = this.entity.script.orbitCamera;
345
- if (this.orbitCamera) {
346
- var self = this;
347
- var onMouseOut = function (e) { self.onMouseOut(e); };
348
- this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);
349
- this.app.mouse.on(pc.EVENT_MOUSEUP, this.onMouseUp, this);
350
- this.app.mouse.on(pc.EVENT_MOUSEMOVE, this.onMouseMove, this);
351
- this.app.mouse.on(pc.EVENT_MOUSEWHEEL, this.onMouseWheel, this);
352
- window.addEventListener('mouseout', onMouseOut, false);
353
- this.on('destroy', function () {
354
- this.app.mouse.off(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);
355
- this.app.mouse.off(pc.EVENT_MOUSEUP, this.onMouseUp, this);
356
- this.app.mouse.off(pc.EVENT_MOUSEMOVE, this.onMouseMove, this);
357
- this.app.mouse.off(pc.EVENT_MOUSEWHEEL, this.onMouseWheel, this);
358
- window.removeEventListener('mouseout', onMouseOut, false);
359
- });
360
- }
361
- this.app.mouse.disableContextMenu();
362
- this.lookButtonDown = false;
363
- this.panButtonDown = false;
364
- this.lastPoint = new pc.Vec2();
365
- };
366
-
367
- OrbitCameraInputMouse.fromWorldPoint = new pc.Vec3();
368
- OrbitCameraInputMouse.toWorldPoint = new pc.Vec3();
369
- OrbitCameraInputMouse.worldDiff = new pc.Vec3();
370
-
371
- OrbitCameraInputMouse.prototype.pan = function (screenPoint) {
372
- var fromWorldPoint = OrbitCameraInputMouse.fromWorldPoint;
373
- var toWorldPoint = OrbitCameraInputMouse.toWorldPoint;
374
- var worldDiff = OrbitCameraInputMouse.worldDiff;
375
- var camera = this.entity.camera;
376
- var distance = this.orbitCamera.distance;
377
- camera.screenToWorld(screenPoint.x, screenPoint.y, distance, fromWorldPoint);
378
- camera.screenToWorld(this.lastPoint.x, this.lastPoint.y, distance, toWorldPoint);
379
- worldDiff.sub2(toWorldPoint, fromWorldPoint);
380
- this.orbitCamera.pivotPoint.add(worldDiff);
381
- var pitchRadians = this.orbitCamera.pitch * pc.math.DEG_TO_RAD;
382
- var minPivotY = this.orbitCamera.distance * Math.sin(pitchRadians);
383
- if (this.orbitCamera.pivotPoint.y < minPivotY) {
384
- this.orbitCamera.pivotPoint.y = minPivotY;
385
- }
386
- };
387
-
388
- OrbitCameraInputMouse.prototype.onMouseDown = function (event) {
389
- switch (event.button) {
390
- case pc.MOUSEBUTTON_LEFT:
391
- this.panButtonDown = true;
392
- break;
393
- case pc.MOUSEBUTTON_MIDDLE:
394
- case pc.MOUSEBUTTON_RIGHT:
395
- this.lookButtonDown = true;
396
- break;
397
- }
398
- };
399
- OrbitCameraInputMouse.prototype.onMouseUp = function (event) {
400
- switch (event.button) {
401
- case pc.MOUSEBUTTON_LEFT:
402
- this.panButtonDown = false;
403
- break;
404
- case pc.MOUSEBUTTON_MIDDLE:
405
- case pc.MOUSEBUTTON_RIGHT:
406
- this.lookButtonDown = false;
407
- break;
408
- }
409
- };
410
-
411
- OrbitCameraInputMouse.prototype.onMouseMove = function (event) {
412
- if (this.lookButtonDown) {
413
- var delta = -event.dy * this.orbitSensitivity;
414
- var camY = this.entity.getPosition().y;
415
- // block further downward orbit when at minY
416
- if (!(delta < 0 && camY <= this.orbitCamera.minY)) {
417
- this.orbitCamera.pitch += delta;
418
- }
419
- } else if (this.panButtonDown) {
420
- this.pan(new pc.Vec2(event.x, event.y));
421
- }
422
- this.lastPoint.set(event.x, event.y);
423
- };
424
-
425
- OrbitCameraInputMouse.prototype.onMouseWheel = function (event) {
426
- if (this.entity.camera.projection === pc.PROJECTION_PERSPECTIVE) {
427
- this.orbitCamera.distance -= event.wheelDelta * this.distanceSensitivity * (this.orbitCamera.distance * 0.1);
428
- } else {
429
- this.orbitCamera.orthoHeight -= event.wheelDelta * this.distanceSensitivity * (this.orbitCamera.orthoHeight * 0.1);
430
- }
431
- event.event.preventDefault();
432
- };
433
-
434
- OrbitCameraInputMouse.prototype.onMouseOut = function (event) {
435
- this.lookButtonDown = false;
436
- this.panButtonDown = false;
437
- };
438
-
439
-
440
- ////////////////////////////////////////////////////////////////////////////////
441
- // Orbit Camera Touch Input Script //
442
- ////////////////////////////////////////////////////////////////////////////////
443
- var OrbitCameraInputTouch = pc.createScript('orbitCameraInputTouch');
444
-
445
- OrbitCameraInputTouch.attributes.add('orbitSensitivity', {
446
- type: 'number',
447
- default: 0.6,
448
- title: 'Orbit Sensitivity',
449
- description: 'How fast the camera moves around the orbit. Higher is faster'
450
- });
451
- OrbitCameraInputTouch.attributes.add('distanceSensitivity', {
452
- type: 'number',
453
- default: 0.5,
454
- title: 'Distance Sensitivity',
455
- description: 'How fast the camera moves in and out. Higher is faster'
456
- });
457
-
458
- OrbitCameraInputTouch.prototype.initialize = function () {
459
- this.orbitCamera = this.entity.script.orbitCamera;
460
- this.lastTouchPoint = new pc.Vec2();
461
- this.lastPinchMidPoint = new pc.Vec2();
462
- this.lastPinchDistance = 0;
463
- if (this.orbitCamera && this.app.touch) {
464
- this.app.touch.on(pc.EVENT_TOUCHSTART, this.onTouchStartEndCancel, this);
465
- this.app.touch.on(pc.EVENT_TOUCHEND, this.onTouchStartEndCancel, this);
466
- this.app.touch.on(pc.EVENT_TOUCHCANCEL, this.onTouchStartEndCancel, this);
467
- this.app.touch.on(pc.EVENT_TOUCHMOVE, this.onTouchMove, this);
468
- this.on('destroy', function () {
469
- this.app.touch.off(pc.EVENT_TOUCHSTART, this.onTouchStartEndCancel, this);
470
- this.app.touch.off(pc.EVENT_TOUCHEND, this.onTouchStartEndCancel, this);
471
- this.app.touch.off(pc.EVENT_TOUCHCANCEL, this.onTouchStartEndCancel, this);
472
- this.app.touch.off(pc.EVENT_TOUCHMOVE, this.onTouchMove, this);
473
- });
474
- }
475
- };
476
-
477
- OrbitCameraInputTouch.prototype.getPinchDistance = function (pointA, pointB) {
478
- var dx = pointA.x - pointB.x;
479
- var dy = pointA.y - pointB.y;
480
- return Math.sqrt((dx * dx) + (dy * dy));
481
- };
482
- OrbitCameraInputTouch.prototype.calcMidPoint = function (pointA, pointB, result) {
483
- result.set(pointB.x - pointA.x, pointB.y - pointA.y);
484
- result.mulScalar(0.5);
485
- result.x += pointA.x;
486
- result.y += pointA.y;
487
- };
488
- OrbitCameraInputTouch.prototype.onTouchStartEndCancel = function (event) {
489
- var touches = event.touches;
490
- if (touches.length === 1) {
491
- this.lastTouchPoint.set(touches[0].x, touches[0].y);
492
- } else if (touches.length === 2) {
493
- this.lastPinchDistance = this.getPinchDistance(touches[0], touches[1]);
494
- this.calcMidPoint(touches[0], touches[1], this.lastPinchMidPoint);
495
- }
496
- };
497
-
498
- OrbitCameraInputTouch.fromWorldPoint = new pc.Vec3();
499
- OrbitCameraInputTouch.toWorldPoint = new pc.Vec3();
500
- OrbitCameraInputTouch.worldDiff = new pc.Vec3();
501
-
502
- OrbitCameraInputTouch.prototype.pan = function (midPoint) {
503
- var fromWorldPoint = OrbitCameraInputTouch.fromWorldPoint;
504
- var toWorldPoint = OrbitCameraInputTouch.toWorldPoint;
505
- var worldDiff = OrbitCameraInputTouch.worldDiff;
506
- var camera = this.entity.camera;
507
- var distance = this.orbitCamera.distance;
508
- camera.screenToWorld(midPoint.x, midPoint.y, distance, fromWorldPoint);
509
- camera.screenToWorld(this.lastPinchMidPoint.x, this.lastPinchMidPoint.y, distance, toWorldPoint);
510
- worldDiff.sub2(toWorldPoint, fromWorldPoint);
511
- this.orbitCamera.pivotPoint.add(worldDiff);
512
- var pitchRadians = this.orbitCamera.pitch * pc.math.DEG_TO_RAD;
513
- var minPivotY = this.orbitCamera.distance * Math.sin(pitchRadians);
514
- if (this.orbitCamera.pivotPoint.y < minPivotY) {
515
- this.orbitCamera.pivotPoint.y = minPivotY;
516
- }
517
- };
518
-
519
- OrbitCameraInputTouch.pinchMidPoint = new pc.Vec2();
520
-
521
- OrbitCameraInputTouch.prototype.onTouchMove = function (event) {
522
- var touches = event.touches;
523
- if (touches.length === 1) {
524
- var touch = touches[0];
525
- var dy = touch.y - this.lastTouchPoint.y;
526
- var delta = -dy * this.orbitSensitivity;
527
- var camY = this.entity.getPosition().y;
528
- // block further downward orbit when at minY
529
- if (!(delta < 0 && camY <= this.orbitCamera.minY)) {
530
- this.orbitCamera.pitch += delta;
531
- }
532
- this.lastTouchPoint.set(touch.x, touch.y);
533
- } else if (touches.length === 2) {
534
- var currentPinchDistance = this.getPinchDistance(touches[0], touches[1]);
535
- var diffInPinchDistance = currentPinchDistance - this.lastPinchDistance;
536
- this.lastPinchDistance = currentPinchDistance;
537
- this.orbitCamera.distance -= (diffInPinchDistance * this.distanceSensitivity * 0.1) * (this.orbitCamera.distance * 0.1);
538
- this.calcMidPoint(touches[0], touches[1], OrbitCameraInputTouch.pinchMidPoint);
539
- this.pan(OrbitCameraInputTouch.pinchMidPoint);
540
- this.lastPinchMidPoint.copy(OrbitCameraInputTouch.pinchMidPoint);
541
- }
542
- };
 
1
+ // orbit-camera.js
2
  ///////////////////////////////////////////////////////////////////////////////
3
  // Orbit Camera Script //
4
  ////////////////////////////////////////////////////////////////////////////////
 
36
  });
37
 
38
  // Property to get and set the distance between the pivot point and camera
39
+ // Clamped between this.distanceMin and this.distanceMax
40
  Object.defineProperty(OrbitCamera.prototype, 'distance', {
41
  get: function () {
42
  return this._targetDistance;
 
57
  });
58
 
59
  // Property to get and set the pitch (in degrees) of the camera around the pivot.
60
+ // The pitch value is clamped between pitchAngleMin and pitchAngleMax.
61
+ // With your JSON (minAngle: -90, maxAngle: 0), the allowed pitch will be from -90 (overhead)
62
+ // to 0 (horizontal). Additionally respects minY so camera never goes below ground.
63
  Object.defineProperty(OrbitCamera.prototype, 'pitch', {
64
  get: function () {
65
  return this._targetPitch;
66
  },
67
  set: function (value) {
68
+ // clamp to configured limits first
69
+ var clamped = this._clampPitchAngle(value);
70
+ // compute max downward pitch allowed by minY
71
+ if (this._pivotPoint && this._targetDistance > 0) {
72
+ // pivot height and distance
73
+ var pivotY = this._pivotPoint.y;
74
+ var dist = this._targetDistance;
75
+ // compute max pitch angle (radians) so that pivotY - sin(pitch)*dist >= minY
76
+ var maxDown = Math.asin(Math.max(0, Math.min(1, (pivotY - this.minY) / dist)));
77
+ // asin gives positive angle; downward pitch is negative, so use -maxDown
78
+ var maxDownDeg = - maxDown * pc.math.RAD_TO_DEG;
79
+ // ensure clamped is not below maxDownDeg
80
+ if (clamped < maxDownDeg) {
81
+ clamped = maxDownDeg;
82
+ }
83
+ }
84
+ this._targetPitch = clamped;
85
  }
86
  });
87
 
 
107
 
108
  // Moves the camera to look at an entity and all its children so they are all in view.
109
  OrbitCamera.prototype.focus = function (focusEntity) {
110
+ // Calculate a bounding box that encompasses all models to frame in the camera view.
111
  this._buildAabb(focusEntity);
112
  var halfExtents = this._modelsAabb.halfExtents;
113
  var radius = Math.max(halfExtents.x, Math.max(halfExtents.y, halfExtents.z));
 
118
 
119
  OrbitCamera.distanceBetween = new pc.Vec3();
120
 
121
+ // Set the camera position to a world position and look at a world position.
122
  OrbitCamera.prototype.resetAndLookAtPoint = function (resetPoint, lookAtPoint) {
123
  this.pivotPoint.copy(lookAtPoint);
124
  this.entity.setPosition(resetPoint);
 
179
  this._pivotPoint.copy(this._modelsAabb.center);
180
  var cameraQuat = this.entity.getRotation();
181
  this._yaw = this._calcYaw(cameraQuat);
182
+ // Compute pitch and clamp it immediately.
183
  this._pitch = this._clampPitchAngle(this._calcPitch(cameraQuat, this._yaw));
184
  this.entity.setLocalEulerAngles(this._pitch, this._yaw, 0);
185
  this._distance = 0;
 
196
 
197
  this._targetDistance = this._distance;
198
 
199
+ this.on('attr:distanceMin', function () {
200
  this._distance = this._clampDistance(this._distance);
201
  });
202
+ this.on('attr:distanceMax', function () {
203
  this._distance = this._clampDistance(this._distance);
204
  });
205
+ this.on('attr:pitchAngleMin', function () {
206
  this._pitch = this._clampPitchAngle(this._pitch);
207
  });
208
+ this.on('attr:pitchAngleMax', function () {
209
  this._pitch = this._clampPitchAngle(this._pitch);
210
  });
211
+ this.on('attr:focusEntity', function (value) {
212
  if (this.frameOnStart) {
213
  this.focus(value || this.app.root);
214
  } else {
215
  this.resetAndLookAtEntity(this.entity.getPosition(), value || this.app.root);
216
  }
217
  });
218
+ this.on('attr:frameOnStart', function (value) {
219
  if (value) {
220
  this.focus(this.focusEntity || this.app.root);
221
  }
 
240
  position.copy(this.entity.forward);
241
  position.mulScalar(-this._distance);
242
  position.add(this.pivotPoint);
243
+ // Ensure world Y never drops below minY
244
  position.y = Math.max(position.y, this.minY);
245
  this.entity.setPosition(position);
246
  };
 
258
  };
259
 
260
  OrbitCamera.prototype._buildAabb = function (entity) {
261
+ var meshInstances = [];
262
  var renders = entity.findComponents('render');
263
+ for (var i = 0; i < renders.length; i++) {
264
  var render = renders[i];
265
+ for (var m = 0; m < render.meshInstances.length; m++) {
266
  meshInstances.push(render.meshInstances[m]);
267
  }
268
  }
 
275
  }
276
  var gsplats = entity.findComponents('gsplat');
277
  for (i = 0; i < gsplats.length; i++) {
278
+ var instance = gsplats[i].instance;
279
+ if (instance && instance.meshInstance) {
 
280
  meshInstances.push(instance.meshInstance);
281
  }
282
  }
 
302
  return Math.max(distance, this.distanceMin);
303
  };
304
 
305
+ // Clamp the pitch between pitchAngleMin and pitchAngleMax
306
  OrbitCamera.prototype._clampPitchAngle = function (pitch) {
307
+ return pc.math.clamp(pitch, this.pitchAngleMin, this.pitchAngleMax);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  };
309
 
310
  OrbitCamera.prototype._clampYawAngle = function (yaw) {
 
314
  OrbitCamera.quatWithoutYaw = new pc.Quat();
315
  OrbitCamera.yawOffset = new pc.Quat();
316
 
317
+ // Compute pitch from quaternion and yaw
318
  OrbitCamera.prototype._calcPitch = function (quat, yaw) {
319
  var quatWithoutYaw = OrbitCamera.quatWithoutYaw;
320
  var yawOffset = OrbitCamera.yawOffset;
 
324
  quatWithoutYaw.transformVector(pc.Vec3.FORWARD, transformedForward);
325
  return Math.atan2(-transformedForward.y, -transformedForward.z) * pc.math.RAD_TO_DEG;
326
  };