Coverage Report

Created: 2025-11-25 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreCamera.cpp
Line
Count
Source
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
    (Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
#include "OgreStableHeaders.h"
29
30
#include "OgreViewport.h"
31
#include "OgreMovablePlane.h"
32
33
namespace Ogre {
34
35
    const String MOT_CAMERA = "Camera";
36
    //-----------------------------------------------------------------------
37
    Camera::Camera( const String& name, SceneManager* sm)
38
0
        : Frustum(name),
39
0
        mWindowSet(false),
40
0
        mAutoAspectRatio(false),
41
0
        mUseRenderingDistance(true),
42
0
        mUseMinPixelSize(false),
43
#ifdef OGRE_NODELESS_POSITIONING
44
        mOrientation(Quaternion::IDENTITY),
45
        mPosition(Vector3::ZERO),
46
        mAutoTrackTarget(0),
47
        mAutoTrackOffset(Vector3::ZERO),
48
#endif
49
0
        mSceneLodFactor(1.0f),
50
0
        mSceneLodFactorInv(1.0f),
51
0
        mLastViewport(0),
52
0
        mCullFrustum(0),
53
0
        mLodCamera(0),
54
0
        mPixelDisplayRatio(0),
55
0
        mSortMode(SM_DISTANCE),
56
0
        mSceneDetail(PM_SOLID)
57
0
    {
58
59
        // Reasonable defaults to camera params
60
0
        mFOVy = Radian(Math::PI/4.0f);
61
0
        mNearDist = 100.0f;
62
0
        mFarDist = 100000.0f;
63
0
        mAspect = 1.33333333333333f;
64
0
        mProjType = PT_PERSPECTIVE;
65
66
#ifdef OGRE_NODELESS_POSITIONING
67
        mYawFixed = true; // Default to fixed yaw, like freelook since most people expect this
68
        mYawFixedAxis = Vector3::UNIT_Y;
69
#endif
70
71
0
        invalidateFrustum();
72
0
        invalidateView();
73
74
        // Init matrices
75
0
        mViewMatrix = Affine3::ZERO;
76
77
0
        mParentNode = 0;
78
79
        // no reflection
80
0
        mReflect = false;
81
82
0
        mVisible = false;
83
0
        mManager = sm;
84
0
    }
85
86
    //-----------------------------------------------------------------------
87
    Camera::~Camera()
88
0
    {
89
0
        ListenerList listenersCopy = mListeners;
90
0
        for (auto & i : listenersCopy)
91
0
        {
92
0
            i->cameraDestroyed(this);
93
0
        }
94
0
    }
95
    //-----------------------------------------------------------------------
96
    SceneManager* Camera::getSceneManager(void) const
97
0
    {
98
0
        return mManager;
99
0
    }
100
101
102
    //-----------------------------------------------------------------------
103
    void Camera::setPolygonMode(PolygonMode sd)
104
0
    {
105
0
        mSceneDetail = sd;
106
0
    }
107
108
    //-----------------------------------------------------------------------
109
    PolygonMode Camera::getPolygonMode(void) const
110
0
    {
111
0
        return mSceneDetail;
112
0
    }
113
#ifdef OGRE_NODELESS_POSITIONING
114
    //-----------------------------------------------------------------------
115
    void Camera::setPosition(Real x, Real y, Real z)
116
    {
117
        mPosition.x = x;
118
        mPosition.y = y;
119
        mPosition.z = z;
120
        invalidateView();
121
    }
122
123
    //-----------------------------------------------------------------------
124
    void Camera::setPosition(const Vector3& vec)
125
    {
126
        mPosition = vec;
127
        invalidateView();
128
    }
129
130
    //-----------------------------------------------------------------------
131
    const Vector3& Camera::getPosition(void) const
132
    {
133
        return mPosition;
134
    }
135
136
    //-----------------------------------------------------------------------
137
    void Camera::move(const Vector3& vec)
138
    {
139
        mPosition = mPosition + vec;
140
        invalidateView();
141
    }
142
143
    //-----------------------------------------------------------------------
144
    void Camera::moveRelative(const Vector3& vec)
145
    {
146
        // Transform the axes of the relative vector by camera's local axes
147
        Vector3 trans = mOrientation * vec;
148
149
        mPosition = mPosition + trans;
150
        invalidateView();
151
    }
152
153
    //-----------------------------------------------------------------------
154
    void Camera::setDirection(Real x, Real y, Real z)
155
    {
156
        OGRE_IGNORE_DEPRECATED_BEGIN
157
        setDirection(Vector3(x,y,z));
158
        OGRE_IGNORE_DEPRECATED_END
159
    }
160
161
    //-----------------------------------------------------------------------
162
    void Camera::setDirection(const Vector3& vec)
163
    {
164
        // Do nothing if given a zero vector
165
        // (Replaced assert since this could happen with auto tracking camera and
166
        //  camera passes through the lookAt point)
167
        if (vec == Vector3::ZERO) return;
168
169
        // Remember, camera points down -Z of local axes!
170
        // Therefore reverse direction of direction vector before determining local Z
171
        Vector3 zAdjustVec = -vec;
172
        zAdjustVec.normalise();
173
174
        Quaternion targetWorldOrientation;
175
176
        if( mYawFixed )
177
        {
178
            targetWorldOrientation = Math::lookRotation(zAdjustVec, mYawFixedAxis);
179
        }
180
        else
181
        {
182
183
            // Get axes from current quaternion
184
            Vector3 axes[3];
185
            updateView();
186
            mRealOrientation.ToAxes(axes);
187
            Quaternion rotQuat;
188
            if ( (axes[2]+zAdjustVec).squaredLength() <  0.00005f) 
189
            {
190
                // Oops, a 180 degree turn (infinite possible rotation axes)
191
                // Default to yaw i.e. use current UP
192
                rotQuat.FromAngleAxis(Radian(Math::PI), axes[1]);
193
            }
194
            else
195
            {
196
                // Derive shortest arc to new direction
197
                rotQuat = axes[2].getRotationTo(zAdjustVec);
198
199
            }
200
            targetWorldOrientation = rotQuat * mRealOrientation;
201
        }
202
203
        // transform to parent space
204
        if (mParentNode)
205
        {
206
            mOrientation = mParentNode->convertWorldToLocalOrientation(targetWorldOrientation);
207
        }
208
        else
209
        {
210
            mOrientation = targetWorldOrientation;
211
        }
212
213
        // TODO If we have a fixed yaw axis, we mustn't break it by using the
214
        // shortest arc because this will sometimes cause a relative yaw
215
        // which will tip the camera
216
217
        invalidateView();
218
219
    }
220
221
    //-----------------------------------------------------------------------
222
    Vector3 Camera::getDirection(void) const
223
    {
224
        // Direction points down -Z by default
225
        return mOrientation * -Vector3::UNIT_Z;
226
    }
227
228
    //-----------------------------------------------------------------------
229
    Vector3 Camera::getUp(void) const
230
    {
231
        return mOrientation * Vector3::UNIT_Y;
232
    }
233
234
    //-----------------------------------------------------------------------
235
    Vector3 Camera::getRight(void) const
236
    {
237
        return mOrientation * Vector3::UNIT_X;
238
    }
239
240
    //-----------------------------------------------------------------------
241
    void Camera::lookAt(const Vector3& targetPoint)
242
    {
243
        updateView();
244
        OGRE_IGNORE_DEPRECATED_BEGIN
245
        this->setDirection(targetPoint - mRealPosition);
246
        OGRE_IGNORE_DEPRECATED_END
247
    }
248
249
    //-----------------------------------------------------------------------
250
    void Camera::lookAt( Real x, Real y, Real z )
251
    {
252
        Vector3 vTemp( x, y, z );
253
        OGRE_IGNORE_DEPRECATED_BEGIN
254
        this->lookAt(vTemp);
255
        OGRE_IGNORE_DEPRECATED_END
256
    }
257
258
    //-----------------------------------------------------------------------
259
    void Camera::roll(const Radian& angle)
260
    {
261
        // Rotate around local Z axis
262
        Vector3 zAxis = mOrientation * Vector3::UNIT_Z;
263
        OGRE_IGNORE_DEPRECATED_BEGIN
264
        rotate(zAxis, angle);
265
        OGRE_IGNORE_DEPRECATED_END
266
267
        invalidateView();
268
    }
269
270
    //-----------------------------------------------------------------------
271
    void Camera::yaw(const Radian& angle)
272
    {
273
        Vector3 yAxis;
274
275
        if (mYawFixed)
276
        {
277
            // Rotate around fixed yaw axis
278
            yAxis = mYawFixedAxis;
279
        }
280
        else
281
        {
282
            // Rotate around local Y axis
283
            yAxis = mOrientation * Vector3::UNIT_Y;
284
        }
285
286
        OGRE_IGNORE_DEPRECATED_BEGIN
287
        rotate(yAxis, angle);
288
        OGRE_IGNORE_DEPRECATED_END
289
290
        invalidateView();
291
    }
292
293
    //-----------------------------------------------------------------------
294
    void Camera::pitch(const Radian& angle)
295
    {
296
        // Rotate around local X axis
297
        Vector3 xAxis = mOrientation * Vector3::UNIT_X;
298
        OGRE_IGNORE_DEPRECATED_BEGIN
299
        rotate(xAxis, angle);
300
        OGRE_IGNORE_DEPRECATED_END
301
302
        invalidateView();
303
304
    }
305
306
    //-----------------------------------------------------------------------
307
    void Camera::rotate(const Vector3& axis, const Radian& angle)
308
    {
309
        Quaternion q;
310
        q.FromAngleAxis(angle,axis);
311
        OGRE_IGNORE_DEPRECATED_BEGIN
312
        rotate(q);
313
        OGRE_IGNORE_DEPRECATED_END
314
    }
315
316
    //-----------------------------------------------------------------------
317
    void Camera::rotate(const Quaternion& q)
318
    {
319
        // Note the order of the mult, i.e. q comes after
320
321
        // Normalise the quat to avoid cumulative problems with precision
322
        Quaternion qres = q * mOrientation;
323
        qres.normalise();
324
        mOrientation = qres;
325
326
        invalidateView();
327
328
    }
329
330
    //-----------------------------------------------------------------------
331
    void Camera::setFixedYawAxis(bool useFixed, const Vector3& fixedAxis)
332
    {
333
        mYawFixed = useFixed;
334
        mYawFixedAxis = fixedAxis;
335
    }
336
    //-----------------------------------------------------------------------
337
    const Quaternion& Camera::getOrientation(void) const
338
    {
339
        return mOrientation;
340
    }
341
    //-----------------------------------------------------------------------
342
    void Camera::_autoTrack(void)
343
    {
344
        // NB assumes that all scene nodes have been updated
345
        if (mAutoTrackTarget)
346
        {
347
            OGRE_IGNORE_DEPRECATED_BEGIN
348
            lookAt(mAutoTrackTarget->_getFullTransform() * mAutoTrackOffset);
349
            OGRE_IGNORE_DEPRECATED_END
350
        }
351
    }
352
353
    //-----------------------------------------------------------------------
354
    void Camera::setOrientation(const Quaternion& q)
355
    {
356
        mOrientation = q;
357
        mOrientation.normalise();
358
        invalidateView();
359
    }
360
    //-----------------------------------------------------------------------
361
    void Camera::setAutoTracking(bool enabled, SceneNode* const target,
362
        const Vector3& offset)
363
    {
364
        if (enabled)
365
        {
366
            assert (target != 0 && "target cannot be a null pointer if tracking is enabled");
367
            mAutoTrackTarget = target;
368
            mAutoTrackOffset = offset;
369
        }
370
        else
371
        {
372
            mAutoTrackTarget = 0;
373
        }
374
    }
375
    //-----------------------------------------------------------------------
376
    const Vector3& Camera::getPositionForViewUpdate(void) const
377
    {
378
        // Note no update, because we're calling this from the update!
379
        return mRealPosition;
380
    }
381
    //-----------------------------------------------------------------------
382
    const Quaternion& Camera::getOrientationForViewUpdate(void) const
383
    {
384
        return mRealOrientation;
385
    }
386
#endif
387
    //-----------------------------------------------------------------------
388
    bool Camera::isViewOutOfDate(void) const
389
0
    {
390
#ifdef OGRE_NODELESS_POSITIONING
391
        // Overridden from Frustum to use local orientation / position offsets
392
        // Attached to node?
393
        if (mParentNode != 0)
394
        {
395
            if (mRecalcView ||
396
                mParentNode->_getDerivedOrientation() != mLastParentOrientation ||
397
                mParentNode->_getDerivedPosition() != mLastParentPosition)
398
            {
399
                // Ok, we're out of date with SceneNode we're attached to
400
                mLastParentOrientation = mParentNode->_getDerivedOrientation();
401
                mLastParentPosition = mParentNode->_getDerivedPosition();
402
                mRealOrientation = mParentNode->convertLocalToWorldOrientation(mOrientation);
403
                mRealPosition = mParentNode->convertLocalToWorldPosition(mPosition);
404
                mRecalcView = true;
405
                mRecalcWindow = true;
406
            }
407
        }
408
        else
409
        {
410
            // Rely on own updates
411
            mRealOrientation = mOrientation;
412
            mRealPosition = mPosition;
413
        }
414
415
        // Deriving reflection from linked plane?
416
        if (mReflect && mLinkedReflectPlane && 
417
            !(mLastLinkedReflectionPlane == mLinkedReflectPlane->_getDerivedPlane()))
418
        {
419
            mReflectPlane = mLinkedReflectPlane->_getDerivedPlane();
420
            mReflectMatrix = Math::buildReflectionMatrix(mReflectPlane);
421
            mLastLinkedReflectionPlane = mLinkedReflectPlane->_getDerivedPlane();
422
            mRecalcView = true;
423
            mRecalcWindow = true;
424
        }
425
#else
426
0
        if(Frustum::isViewOutOfDate())
427
0
            mRecalcWindow = true;
428
0
#endif
429
430
        // Deriving reflected orientation / position
431
0
        if (mRecalcView)
432
0
        {
433
0
#ifndef OGRE_NODELESS_POSITIONING
434
0
            const auto& mRealOrientation = mLastParentOrientation;
435
0
            const auto& mRealPosition = mLastParentPosition;
436
0
#endif
437
438
0
            if (mReflect)
439
0
            {
440
                // Calculate reflected orientation, use up-vector as fallback axis.
441
0
                Vector3 dir = -mRealOrientation.zAxis();
442
0
                Vector3 rdir = dir.reflect(mReflectPlane.normal);
443
0
                Vector3 up = mRealOrientation.yAxis();
444
0
                mDerivedOrientation = dir.getRotationTo(rdir, up) * mRealOrientation;
445
446
                // Calculate reflected position.
447
0
                mDerivedPosition = mReflectMatrix * mRealPosition;
448
0
            }
449
0
            else
450
0
            {
451
0
                mDerivedOrientation = mRealOrientation;
452
0
                mDerivedPosition = mRealPosition;
453
0
            }
454
0
        }
455
456
0
        return mRecalcView;
457
458
0
    }
459
460
    // -------------------------------------------------------------------
461
    void Camera::invalidateView() const
462
0
    {
463
0
        mRecalcWindow = true;
464
0
        Frustum::invalidateView();
465
0
    }
466
    // -------------------------------------------------------------------
467
    void Camera::invalidateFrustum(void) const
468
0
    {
469
0
        mRecalcWindow = true;
470
0
        Frustum::invalidateFrustum();
471
0
    }
472
    //-----------------------------------------------------------------------
473
    void Camera::_renderScene(Viewport *vp)
474
0
    {
475
0
        OgreGpuEventScope(getName());
476
477
        //update the pixel display ratio
478
0
        if (mProjType == Ogre::PT_PERSPECTIVE)
479
0
        {
480
0
            mPixelDisplayRatio = (2 * Ogre::Math::Tan(mFOVy * 0.5f)) / vp->getActualHeight();
481
0
        }
482
0
        else
483
0
        {
484
0
            mPixelDisplayRatio = -mExtents.height() / vp->getActualHeight();
485
0
        }
486
487
        //notify prerender scene
488
0
        ListenerList listenersCopy = mListeners;
489
0
        for (auto & i : listenersCopy)
490
0
        {
491
0
            i->cameraPreRenderScene(this);
492
0
        }
493
494
        //render scene
495
0
        mManager->_renderScene(this, vp);
496
497
        // Listener list may have change
498
0
        listenersCopy = mListeners;
499
500
        //notify postrender scene
501
0
        for (auto & i : listenersCopy)
502
0
        {
503
0
            i->cameraPostRenderScene(this);
504
0
        }
505
0
    }
506
    //---------------------------------------------------------------------
507
    void Camera::addListener(Listener* l)
508
0
    {
509
0
        if (std::find(mListeners.begin(), mListeners.end(), l) == mListeners.end())
510
0
            mListeners.push_back(l);
511
0
    }
512
    //---------------------------------------------------------------------
513
    void Camera::removeListener(Listener* l)
514
0
    {
515
0
        ListenerList::iterator i = std::find(mListeners.begin(), mListeners.end(), l);
516
0
        if (i != mListeners.end())
517
0
            mListeners.erase(i);
518
0
    }
519
    //-----------------------------------------------------------------------
520
    std::ostream& operator<<( std::ostream& o, const Camera& c )
521
0
    {
522
0
        o << "Camera(Name='" << c.mName << "'";
523
#ifdef OGRE_NODELESS_POSITIONING
524
        o << ", pos=" << c.mPosition << ", direction=" << -c.mOrientation.zAxis();
525
#else
526
0
        o << ", pos=" << c.mLastParentPosition << ", direction=" << -c.mLastParentOrientation.zAxis();
527
0
#endif
528
0
        o << ",near=" << c.mNearDist;
529
0
        o << ", far=" << c.mFarDist << ", FOVy=" << c.mFOVy.valueDegrees();
530
0
        o << ", aspect=" << c.mAspect << ", ";
531
0
        o << ", xoffset=" << c.mFrustumOffset.x << ", yoffset=" << c.mFrustumOffset.y;
532
0
        o << ", focalLength=" << c.mFocalLength << ", ";
533
0
        o << "NearFrustumPlane=" << c.mFrustumPlanes[FRUSTUM_PLANE_NEAR] << ", ";
534
0
        o << "FarFrustumPlane=" << c.mFrustumPlanes[FRUSTUM_PLANE_FAR] << ", ";
535
0
        o << "LeftFrustumPlane=" << c.mFrustumPlanes[FRUSTUM_PLANE_LEFT] << ", ";
536
0
        o << "RightFrustumPlane=" << c.mFrustumPlanes[FRUSTUM_PLANE_RIGHT] << ", ";
537
0
        o << "TopFrustumPlane=" << c.mFrustumPlanes[FRUSTUM_PLANE_TOP] << ", ";
538
0
        o << "BottomFrustumPlane=" << c.mFrustumPlanes[FRUSTUM_PLANE_BOTTOM];
539
0
        o << ")";
540
541
0
        return o;
542
0
    }
543
    //-----------------------------------------------------------------------
544
    const Quaternion& Camera::getDerivedOrientation(void) const
545
0
    {
546
0
        updateView();
547
0
        return mDerivedOrientation;
548
0
    }
549
    //-----------------------------------------------------------------------
550
    const Vector3& Camera::getDerivedPosition(void) const
551
0
    {
552
0
        updateView();
553
0
        return mDerivedPosition;
554
0
    }
555
    //-----------------------------------------------------------------------
556
    Vector3 Camera::getDerivedDirection(void) const
557
0
    {
558
        // Direction points down -Z
559
0
        updateView();
560
0
        return -mDerivedOrientation.zAxis();
561
0
    }
562
    //-----------------------------------------------------------------------
563
    Vector3 Camera::getDerivedUp(void) const
564
0
    {
565
0
        updateView();
566
0
        return mDerivedOrientation.yAxis();
567
0
    }
568
    //-----------------------------------------------------------------------
569
    Vector3 Camera::getDerivedRight(void) const
570
0
    {
571
0
        updateView();
572
0
        return mDerivedOrientation.xAxis();
573
0
    }
574
    //-----------------------------------------------------------------------
575
    const Quaternion& Camera::getRealOrientation(void) const
576
0
    {
577
0
        updateView();
578
#ifdef OGRE_NODELESS_POSITIONING
579
        return mRealOrientation;
580
#else
581
0
        return mLastParentOrientation;
582
0
#endif
583
0
    }
584
    //-----------------------------------------------------------------------
585
    const Vector3& Camera::getRealPosition(void) const
586
0
    {
587
0
        updateView();
588
#ifdef OGRE_NODELESS_POSITIONING
589
        return mRealPosition;
590
#else
591
0
        return mLastParentPosition;
592
0
#endif
593
0
    }
594
    //-----------------------------------------------------------------------
595
    Vector3 Camera::getRealDirection(void) const
596
0
    {
597
        // Direction points down -Z
598
0
        updateView();
599
#ifdef OGRE_NODELESS_POSITIONING
600
        return mRealOrientation * Vector3::NEGATIVE_UNIT_Z;
601
#else
602
0
        return -mLastParentOrientation.zAxis();
603
0
#endif
604
0
    }
605
    //-----------------------------------------------------------------------
606
    Vector3 Camera::getRealUp(void) const
607
0
    {
608
0
        updateView();
609
#ifdef OGRE_NODELESS_POSITIONING
610
        return mRealOrientation * Vector3::UNIT_Y;
611
#else
612
0
        return mLastParentOrientation.yAxis();
613
0
#endif
614
0
    }
615
    //-----------------------------------------------------------------------
616
    Vector3 Camera::getRealRight(void) const
617
0
    {
618
0
        updateView();
619
#ifdef OGRE_NODELESS_POSITIONING
620
        return mRealOrientation * Vector3::UNIT_X;
621
#else
622
0
        return mLastParentOrientation.xAxis();
623
0
#endif
624
0
    }
625
    //-----------------------------------------------------------------------
626
    const String& Camera::getMovableType(void) const
627
0
    {
628
0
        return MOT_CAMERA;
629
0
    }
630
    //-----------------------------------------------------------------------
631
    void Camera::setLodBias(Real factor)
632
0
    {
633
0
        assert(factor > 0.0f && "Bias factor must be > 0!");
634
0
        mSceneLodFactor = factor;
635
0
        mSceneLodFactorInv = 1.0f / factor;
636
0
    }
637
    //-----------------------------------------------------------------------
638
    Real Camera::getLodBias(void) const
639
0
    {
640
0
        return mSceneLodFactor;
641
0
    }
642
    //-----------------------------------------------------------------------
643
    Real Camera::_getLodBiasInverse(void) const
644
0
    {
645
0
        return mSceneLodFactorInv;
646
0
    }
647
    //-----------------------------------------------------------------------
648
    void Camera::setLodCamera(const Camera* lodCam)
649
0
    {
650
0
        if (lodCam == this)
651
0
            mLodCamera = 0;
652
0
        else
653
0
            mLodCamera = lodCam;
654
0
    }
655
    //---------------------------------------------------------------------
656
    const Camera* Camera::getLodCamera() const
657
0
    {
658
0
        return mLodCamera? mLodCamera : this;
659
0
    }
660
    //-----------------------------------------------------------------------
661
    Ray Camera::getCameraToViewportRay(Real screenX, Real screenY) const
662
0
    {
663
0
        Ray ret;
664
0
        getCameraToViewportRay(screenX, screenY, &ret);
665
0
        return ret;
666
0
    }
667
    //---------------------------------------------------------------------
668
    void Camera::getCameraToViewportRay(Real screenX, Real screenY, Ray* outRay) const
669
0
    {
670
0
        Matrix4 inverseVP = (getProjectionMatrix() * getViewMatrix(true)).inverse();
671
672
0
        Real nx = (2.0f * screenX) - 1.0f;
673
0
        Real ny = 1.0f - (2.0f * screenY);
674
0
        Vector3 nearPoint(nx, ny, -1.f);
675
        // Use midPoint rather than far point to avoid issues with infinite projection
676
0
        Vector3 midPoint (nx, ny,  0.0f);
677
678
        // Get ray origin and ray target on near plane in world space
679
0
        Vector3 rayOrigin, rayTarget;
680
        
681
0
        rayOrigin = inverseVP * nearPoint;
682
0
        rayTarget = inverseVP * midPoint;
683
684
0
        Vector3 rayDirection = rayTarget - rayOrigin;
685
0
        rayDirection.normalise();
686
687
0
        outRay->setOrigin(rayOrigin);
688
0
        outRay->setDirection(rayDirection);
689
0
    } 
690
    //---------------------------------------------------------------------
691
    PlaneBoundedVolume Camera::getCameraToViewportBoxVolume(Real screenLeft, 
692
        Real screenTop, Real screenRight, Real screenBottom, bool includeFarPlane)
693
0
    {
694
0
        PlaneBoundedVolume vol;
695
0
        getCameraToViewportBoxVolume(screenLeft, screenTop, screenRight, screenBottom, 
696
0
            &vol, includeFarPlane);
697
0
        return vol;
698
699
0
    }
700
    //---------------------------------------------------------------------()
701
    void Camera::getCameraToViewportBoxVolume(Real screenLeft, 
702
        Real screenTop, Real screenRight, Real screenBottom, 
703
        PlaneBoundedVolume* outVolume, bool includeFarPlane)
704
0
    {
705
0
        outVolume->planes.clear();
706
707
0
        if (mProjType == PT_PERSPECTIVE)
708
0
        {
709
710
            // Use the corner rays to generate planes
711
0
            Ray ul = getCameraToViewportRay(screenLeft, screenTop);
712
0
            Ray ur = getCameraToViewportRay(screenRight, screenTop);
713
0
            Ray bl = getCameraToViewportRay(screenLeft, screenBottom);
714
0
            Ray br = getCameraToViewportRay(screenRight, screenBottom);
715
716
717
0
            Vector3 normal;
718
            // top plane
719
0
            normal = ul.getDirection().crossProduct(ur.getDirection());
720
0
            normal.normalise();
721
0
            outVolume->planes.push_back(
722
0
                Plane(normal, getDerivedPosition()));
723
724
            // right plane
725
0
            normal = ur.getDirection().crossProduct(br.getDirection());
726
0
            normal.normalise();
727
0
            outVolume->planes.push_back(
728
0
                Plane(normal, getDerivedPosition()));
729
730
            // bottom plane
731
0
            normal = br.getDirection().crossProduct(bl.getDirection());
732
0
            normal.normalise();
733
0
            outVolume->planes.push_back(
734
0
                Plane(normal, getDerivedPosition()));
735
736
            // left plane
737
0
            normal = bl.getDirection().crossProduct(ul.getDirection());
738
0
            normal.normalise();
739
0
            outVolume->planes.push_back(
740
0
                Plane(normal, getDerivedPosition()));
741
742
0
        }
743
0
        else
744
0
        {
745
            // ortho planes are parallel to frustum planes
746
747
0
            Ray ul = getCameraToViewportRay(screenLeft, screenTop);
748
0
            Ray br = getCameraToViewportRay(screenRight, screenBottom);
749
750
0
            updateFrustumPlanes();
751
0
            outVolume->planes.push_back(
752
0
                Plane(mFrustumPlanes[FRUSTUM_PLANE_TOP].normal, ul.getOrigin()));
753
0
            outVolume->planes.push_back(
754
0
                Plane(mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal, br.getOrigin()));
755
0
            outVolume->planes.push_back(
756
0
                Plane(mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal, br.getOrigin()));
757
0
            outVolume->planes.push_back(
758
0
                Plane(mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal, ul.getOrigin()));
759
            
760
761
0
        }
762
763
        // near & far plane applicable to both projection types
764
0
        outVolume->planes.push_back(getFrustumPlane(FRUSTUM_PLANE_NEAR));
765
0
        if (includeFarPlane)
766
0
            outVolume->planes.push_back(getFrustumPlane(FRUSTUM_PLANE_FAR));
767
0
    }
768
    // -------------------------------------------------------------------
769
    void Camera::setWindow (Real Left, Real Top, Real Right, Real Bottom)
770
0
    {
771
0
        mWLeft = Left;
772
0
        mWTop = Top;
773
0
        mWRight = Right;
774
0
        mWBottom = Bottom;
775
776
0
        mWindowSet = true;
777
0
        mRecalcWindow = true;
778
0
    }
779
    // -------------------------------------------------------------------
780
    void Camera::resetWindow ()
781
0
    {
782
0
        mWindowSet = false;
783
0
    }
784
    // -------------------------------------------------------------------
785
    void Camera::setWindowImpl() const
786
0
    {
787
0
        if (!mWindowSet || !mRecalcWindow)
788
0
            return;
789
790
        // Calculate general projection parameters
791
0
        RealRect vp = calcProjectionParameters();
792
793
0
        Real vpWidth = vp.width();
794
0
        Real vpHeight = -vp.height();
795
796
0
        Real wvpLeft   = vp.left + mWLeft * vpWidth;
797
0
        Real wvpRight  = vp.left + mWRight * vpWidth;
798
0
        Real wvpTop    = vp.top - mWTop * vpHeight;
799
0
        Real wvpBottom = vp.top - mWBottom * vpHeight;
800
801
0
        Vector3 vp_ul (wvpLeft, wvpTop, -mNearDist);
802
0
        Vector3 vp_ur (wvpRight, wvpTop, -mNearDist);
803
0
        Vector3 vp_bl (wvpLeft, wvpBottom, -mNearDist);
804
0
        Vector3 vp_br (wvpRight, wvpBottom, -mNearDist);
805
806
0
        Affine3 inv = mViewMatrix.inverse();
807
808
0
        Vector3 vw_ul = inv * vp_ul;
809
0
        Vector3 vw_ur = inv * vp_ur;
810
0
        Vector3 vw_bl = inv * vp_bl;
811
0
        Vector3 vw_br = inv * vp_br;
812
813
0
        mWindowClipPlanes.clear();
814
0
        if (mProjType == PT_PERSPECTIVE)
815
0
        {
816
0
            Vector3 position = getPositionForViewUpdate();
817
0
            mWindowClipPlanes.push_back(Plane(position, vw_bl, vw_ul));
818
0
            mWindowClipPlanes.push_back(Plane(position, vw_ul, vw_ur));
819
0
            mWindowClipPlanes.push_back(Plane(position, vw_ur, vw_br));
820
0
            mWindowClipPlanes.push_back(Plane(position, vw_br, vw_bl));
821
0
        }
822
0
        else
823
0
        {
824
0
            Vector3 x_axis(inv[0][0], inv[0][1], inv[0][2]);
825
0
            Vector3 y_axis(inv[1][0], inv[1][1], inv[1][2]);
826
0
            x_axis.normalise();
827
0
            y_axis.normalise();
828
0
            mWindowClipPlanes.push_back(Plane( x_axis, vw_bl));
829
0
            mWindowClipPlanes.push_back(Plane(-x_axis, vw_ur));
830
0
            mWindowClipPlanes.push_back(Plane( y_axis, vw_bl));
831
0
            mWindowClipPlanes.push_back(Plane(-y_axis, vw_ur));
832
0
        }
833
834
0
        mRecalcWindow = false;
835
836
0
    }
837
    // -------------------------------------------------------------------
838
    const std::vector<Plane>& Camera::getWindowPlanes(void) const
839
0
    {
840
0
        updateView();
841
0
        setWindowImpl();
842
0
        return mWindowClipPlanes;
843
0
    }
844
    // -------------------------------------------------------------------
845
    Real Camera::getBoundingRadius(void) const
846
0
    {
847
        // return a little bigger than the near distance
848
        // just to keep things just outside
849
0
        return mNearDist * 1.5f;
850
851
0
    }
852
    //-----------------------------------------------------------------------
853
    bool Camera::getAutoAspectRatio(void) const
854
0
    {
855
0
        return mAutoAspectRatio;
856
0
    }
857
    //-----------------------------------------------------------------------
858
    void Camera::setAutoAspectRatio(bool autoratio)
859
0
    {
860
0
        mAutoAspectRatio = autoratio;
861
0
    }
862
    //-----------------------------------------------------------------------
863
    bool Camera::isVisible(const AxisAlignedBox& bound, FrustumPlane* culledBy) const
864
0
    {
865
0
        if (mCullFrustum)
866
0
        {
867
0
            return mCullFrustum->isVisible(bound, culledBy);
868
0
        }
869
0
        else
870
0
        {
871
0
            return Frustum::isVisible(bound, culledBy);
872
0
        }
873
0
    }
874
    //-----------------------------------------------------------------------
875
    bool Camera::isVisible(const Sphere& bound, FrustumPlane* culledBy) const
876
0
    {
877
0
        if (mCullFrustum)
878
0
        {
879
0
            return mCullFrustum->isVisible(bound, culledBy);
880
0
        }
881
0
        else
882
0
        {
883
0
            return Frustum::isVisible(bound, culledBy);
884
0
        }
885
0
    }
886
    //-----------------------------------------------------------------------
887
    bool Camera::isVisible(const Vector3& vert, FrustumPlane* culledBy) const
888
0
    {
889
0
        if (mCullFrustum)
890
0
        {
891
0
            return mCullFrustum->isVisible(vert, culledBy);
892
0
        }
893
0
        else
894
0
        {
895
0
            return Frustum::isVisible(vert, culledBy);
896
0
        }
897
0
    }
898
    //-----------------------------------------------------------------------
899
    const Frustum::Corners& Camera::getWorldSpaceCorners(void) const
900
0
    {
901
0
        if (mCullFrustum)
902
0
        {
903
0
            return mCullFrustum->getWorldSpaceCorners();
904
0
        }
905
0
        else
906
0
        {
907
0
            return Frustum::getWorldSpaceCorners();
908
0
        }
909
0
    }
910
    //-----------------------------------------------------------------------
911
    const Plane& Camera::getFrustumPlane( unsigned short plane ) const
912
0
    {
913
0
        if (mCullFrustum)
914
0
        {
915
0
            return mCullFrustum->getFrustumPlane(plane);
916
0
        }
917
0
        else
918
0
        {
919
0
            return Frustum::getFrustumPlane(plane);
920
0
        }
921
0
    }
922
    //-----------------------------------------------------------------------
923
    bool Camera::projectSphere(const Sphere& sphere, 
924
        Real* left, Real* top, Real* right, Real* bottom) const
925
0
    {
926
0
        if (mCullFrustum)
927
0
        {
928
0
            return mCullFrustum->projectSphere(sphere, left, top, right, bottom);
929
0
        }
930
0
        else
931
0
        {
932
0
            return Frustum::projectSphere(sphere, left, top, right, bottom);
933
0
        }
934
0
    }
935
    //-----------------------------------------------------------------------
936
    float Camera::getNearClipDistance(void) const
937
0
    {
938
0
        if (mCullFrustum)
939
0
        {
940
0
            return mCullFrustum->getNearClipDistance();
941
0
        }
942
0
        else
943
0
        {
944
0
            return Frustum::getNearClipDistance();
945
0
        }
946
0
    }
947
    //-----------------------------------------------------------------------
948
    float Camera::getFarClipDistance(void) const
949
0
    {
950
0
        if (mCullFrustum)
951
0
        {
952
0
            return mCullFrustum->getFarClipDistance();
953
0
        }
954
0
        else
955
0
        {
956
0
            return Frustum::getFarClipDistance();
957
0
        }
958
0
    }
959
    //-----------------------------------------------------------------------
960
    const Affine3& Camera::getViewMatrix(void) const
961
0
    {
962
0
        if (mCullFrustum)
963
0
        {
964
0
            return mCullFrustum->getViewMatrix();
965
0
        }
966
0
        else
967
0
        {
968
0
            return Frustum::getViewMatrix();
969
0
        }
970
0
    }
971
    //-----------------------------------------------------------------------
972
    const Affine3& Camera::getViewMatrix(bool ownFrustumOnly) const
973
0
    {
974
0
        if (ownFrustumOnly)
975
0
        {
976
0
            return Frustum::getViewMatrix();
977
0
        }
978
0
        else
979
0
        {
980
0
            return getViewMatrix();
981
0
        }
982
0
    }
983
    //-----------------------------------------------------------------------
984
    //_______________________________________________________
985
    //|                                                     |
986
    //| getRayForwardIntersect                              |
987
    //| -----------------------------                       |
988
    //| get the intersections of frustum rays with a plane  |
989
    //| of interest.  The plane is assumed to have constant |
990
    //| z.  If this is not the case, rays                   |
991
    //| should be rotated beforehand to work in a           |
992
    //| coordinate system in which this is true.            |
993
    //|_____________________________________________________|
994
    //
995
    std::vector<Vector4> Camera::getRayForwardIntersect(const Vector3& anchor, const Vector3 *dir, Real planeOffset) const
996
0
    {
997
0
        std::vector<Vector4> res;
998
999
0
        if(!dir)
1000
0
            return res;
1001
1002
0
        int infpt[4] = {0, 0, 0, 0}; // 0=finite, 1=infinite, 2=straddles infinity
1003
0
        Vector3 vec[4];
1004
1005
        // find how much the anchor point must be displaced in the plane's
1006
        // constant variable
1007
0
        Real delta = planeOffset - anchor.z;
1008
1009
        // now set the intersection point and note whether it is a 
1010
        // point at infinity or straddles infinity
1011
0
        unsigned int i;
1012
0
        for (i=0; i<4; i++)
1013
0
        {
1014
0
            Real test = dir[i].z * delta;
1015
0
            if (test == 0.0) {
1016
0
                vec[i] = dir[i];
1017
0
                infpt[i] = 1;
1018
0
            }
1019
0
            else {
1020
0
                Real lambda = delta / dir[i].z;
1021
0
                vec[i] = anchor + (lambda * dir[i]);
1022
0
                if(test < 0.0)
1023
0
                    infpt[i] = 2;
1024
0
            }
1025
0
        }
1026
1027
0
        for (i=0; i<4; i++)
1028
0
        {
1029
            // store the finite intersection points
1030
0
            if (infpt[i] == 0)
1031
0
                res.push_back(Vector4(vec[i].x, vec[i].y, vec[i].z, 1.0));
1032
0
            else
1033
0
            {
1034
                // handle the infinite points of intersection;
1035
                // cases split up into the possible frustum planes 
1036
                // pieces which may contain a finite intersection point
1037
0
                int nextind = (i+1) % 4;
1038
0
                int prevind = (i+3) % 4;
1039
0
                if ((infpt[prevind] == 0) || (infpt[nextind] == 0))
1040
0
                {
1041
0
                    if (infpt[i] == 1)
1042
0
                        res.push_back(Vector4(vec[i].x, vec[i].y, vec[i].z, 0.0));
1043
0
                    else
1044
0
                    {
1045
                        // handle the intersection points that straddle infinity (back-project)
1046
0
                        if(infpt[prevind] == 0) 
1047
0
                        {
1048
0
                            Vector3 temp = vec[prevind] - vec[i];
1049
0
                            res.push_back(Vector4(temp.x, temp.y, temp.z, 0.0));
1050
0
                        }
1051
0
                        if(infpt[nextind] == 0)
1052
0
                        {
1053
0
                            Vector3 temp = vec[nextind] - vec[i];
1054
0
                            res.push_back(Vector4(temp.x, temp.y, temp.z, 0.0));
1055
0
                        }
1056
0
                    }
1057
0
                } // end if we need to add an intersection point to the list
1058
0
            } // end if infinite point needs to be considered
1059
0
        } // end loop over frustun corners
1060
1061
        // we end up with either 0, 3, 4, or 5 intersection points
1062
1063
0
        return res;
1064
0
    }
1065
1066
    //_______________________________________________________
1067
    //|                                                     |
1068
    //| forwardIntersect                                    |
1069
    //| -----------------------------                       |
1070
    //| Forward intersect the camera's frustum rays with    |
1071
    //| a specified plane of interest.                      |
1072
    //| Note that if the frustum rays shoot out and would   |
1073
    //| back project onto the plane, this means the forward |
1074
    //| intersection of the frustum would occur at the      |
1075
    //| line at infinity.                                   |
1076
    //|_____________________________________________________|
1077
    //
1078
    void Camera::forwardIntersect(const Plane& worldPlane, std::vector<Vector4>* intersect3d) const
1079
0
    {
1080
0
        if(!intersect3d)
1081
0
            return;
1082
1083
0
        Vector3 trCorner = getWorldSpaceCorners()[0];
1084
0
        Vector3 tlCorner = getWorldSpaceCorners()[1];
1085
0
        Vector3 blCorner = getWorldSpaceCorners()[2];
1086
0
        Vector3 brCorner = getWorldSpaceCorners()[3];
1087
1088
        // need some sort of rotation that will bring the plane normal to the z axis
1089
0
        Plane pval = worldPlane;
1090
0
        if(pval.normal.z < 0.0)
1091
0
        {
1092
0
            pval.normal *= -1.0;
1093
0
            pval.d *= -1.0;
1094
0
        }
1095
0
        Quaternion invPlaneRot = pval.normal.getRotationTo(Vector3::UNIT_Z);
1096
1097
        // get rotated light
1098
0
        Vector3 lPos = invPlaneRot * getDerivedPosition();
1099
0
        Vector3 vec[4];
1100
0
        vec[0] = invPlaneRot * trCorner - lPos;
1101
0
        vec[1] = invPlaneRot * tlCorner - lPos; 
1102
0
        vec[2] = invPlaneRot * blCorner - lPos; 
1103
0
        vec[3] = invPlaneRot * brCorner - lPos; 
1104
1105
        // compute intersection points on plane
1106
0
        std::vector<Vector4> iPnt = getRayForwardIntersect(lPos, vec, -pval.d);
1107
1108
1109
        // return wanted data
1110
0
        if(intersect3d) 
1111
0
        {
1112
0
            Quaternion planeRot = invPlaneRot.Inverse();
1113
0
            (*intersect3d).clear();
1114
0
            for(auto & i : iPnt)
1115
0
            {
1116
0
                Vector3 intersection = planeRot * Vector3(i.x, i.y, i.z);
1117
0
                (*intersect3d).push_back(Vector4(intersection.x, intersection.y, intersection.z, i.w));
1118
0
            }
1119
0
        }
1120
0
    }
1121
    //-----------------------------------------------------------------------
1122
    void Camera::synchroniseBaseSettingsWith(const Camera* cam)
1123
0
    {
1124
0
        this->setProjectionType(cam->getProjectionType());
1125
#ifdef OGRE_NODELESS_POSITIONING
1126
        mPosition = cam->mPosition;
1127
        mOrientation = cam->mOrientation;
1128
#endif
1129
0
        invalidateView();
1130
0
        this->setAspectRatio(cam->getAspectRatio());
1131
0
        this->setNearClipDistance(cam->getNearClipDistance());
1132
0
        this->setFarClipDistance(cam->getFarClipDistance());
1133
0
        this->setUseRenderingDistance(cam->getUseRenderingDistance());
1134
0
        this->setFOVy(cam->getFOVy());
1135
0
        this->setFocalLength(cam->getFocalLength());
1136
1137
        // Don't do these, they're not base settings and can cause referencing issues
1138
        //this->setLodCamera(cam->getLodCamera());
1139
        //this->setCullingFrustum(cam->getCullingFrustum());
1140
1141
0
    }
1142
1143
1144
} // namespace Ogre