Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
Camera.cpp
Go to the documentation of this file.
1
2
3#include "Headers/Camera.h"
4
10
11namespace Divide
12{
13
14 namespace TypeUtil
15 {
16 const char* FStopsToString( const FStops stop ) noexcept
17 {
18 return Names::fStops[to_base( stop )];
19 }
20
21 FStops StringToFStops( const string& name )
22 {
23 for ( U8 i = 0; i < to_U8( FStops::COUNT ); ++i )
24 {
25 if ( strcmp( name.c_str(), Names::fStops[i] ) == 0 )
26 {
27 return static_cast<FStops>(i);
28 }
29 }
30
31 return FStops::COUNT;
32 }
33
34 const char* CameraModeToString( const Camera::Mode mode ) noexcept
35 {
36 return Names::cameraMode[to_base( mode )];
37 }
38
39 Camera::Mode StringToCameraMode( const string& name )
40 {
41
42 for ( U8 i = 0; i < to_U8( Camera::Mode::COUNT ); ++i )
43 {
44 if ( strcmp( name.c_str(), Names::cameraMode[i] ) == 0 )
45 {
46 return static_cast<Camera::Mode>(i);
47 }
48 }
49
51 }
52 }
53
55 {
56 Camera_uptr _camera;
57 std::atomic_size_t _useCount{0u};
58 };
59
60 namespace
61 {
62
63 using CameraPool = eastl::list<CameraEntry>;
64
70
71 vec3<F32> ExtractCameraPos2( const mat4<F32>& a_modelView ) noexcept
72 {
74
75 // Get the 3 basis vector planes at the camera origin and transform them into model space.
76 //
77 // NOTE: Planes have to be transformed by the inverse transpose of a matrix
78 // Nice reference here: http://www.opengl.org/discussion_boards/showthread.php/159564-Clever-way-to-transform-plane-by-matrix
79 //
80 // So for a transform to model space we need to do:
81 // inverse(transpose(inverse(MV)))
82 // This equals : transpose(MV) - see Lemma 5 in http://mathrefresher.blogspot.com.au/2007/06/transpose-of-matrix.html
83 //
84 // As each plane is simply (1,0,0,0), (0,1,0,0), (0,0,1,0) we can pull the data directly from the transpose matrix.
85 //
86 const mat4<F32> modelViewT( a_modelView.getTranspose() );
87
88 // Get plane normals
89 const vec4<F32>& n1( modelViewT.getRow( 0 ) );
90 const vec4<F32>& n2( modelViewT.getRow( 1 ) );
91 const vec4<F32>& n3( modelViewT.getRow( 2 ) );
92
93 // Get plane distances
94 const F32 d1( n1.w );
95 const F32 d2( n2.w );
96 const F32 d3( n3.w );
97
98 // Get the intersection of these 3 planes
99 // (using math from RealTime Collision Detection by Christer Ericson)
100 const vec3<F32> n2n3 = Cross( n2.xyz, n3.xyz );
101 const F32 denom = Dot( n1.xyz, n2n3 );
102 const vec3<F32> top = n2n3 * d1 + Cross( n1.xyz, d3 * n2.xyz - d2 * n3.xyz );
103 return top / -denom;
104 }
105 }
106
107 void Camera::Update( const U64 deltaTimeUS )
108 {
110
111 s_lastFrameTimeSec = Time::MicrosecondsToSeconds<F32>( deltaTimeUS );
112
113 SharedLock<SharedMutex> r_lock( s_cameraPoolLock );
114 for ( CameraEntry& cameEntry : s_cameraPool )
115 {
116 cameEntry._camera->update();
117 }
118 }
119
121 {
122 if ( type != UtilityCamera::COUNT )
123 {
124 return _utilityCameras[to_base( type )];
125 }
126
127 return nullptr;
128 }
129
131 {
132 _utilityCameras[to_base( UtilityCamera::DEFAULT )] = CreateCamera( "DefaultCamera", Mode::FREE_FLY );
133 _utilityCameras[to_base( UtilityCamera::_2D )] = CreateCamera( "2DRenderCamera", Mode::STATIC );
134 _utilityCameras[to_base( UtilityCamera::_2D_FLIP_Y )] = CreateCamera( "2DRenderCameraFlipY", Mode::STATIC );
135 _utilityCameras[to_base( UtilityCamera::CUBE )] = CreateCamera( "CubeCamera", Mode::STATIC );
136 _utilityCameras[to_base( UtilityCamera::DUAL_PARABOLOID )] = CreateCamera( "DualParaboloidCamera", Mode::STATIC );
137 }
138
140 {
141 Console::printfn( LOCALE_STR( "CAMERA_MANAGER_DELETE" ) );
142 _utilityCameras.fill( nullptr );
143 LockGuard<SharedMutex> w_lock( s_cameraPoolLock );
144 s_cameraPool.clear();
145 }
146
147 Camera* Camera::CreateCamera( const Str<256>& cameraName, const Camera::Mode mode )
148 {
149 const U64 targetHash = _ID( cameraName.c_str() );
150
151 CameraEntry* camera = FindCameraEntry( targetHash );
152 if ( camera != nullptr )
153 {
154 camera->_useCount.fetch_add( 1u );
155 return camera->_camera.get();
156 }
157
158 // Cache miss
159 LockGuard<SharedMutex> w_lock( s_cameraPoolLock );
160 // Search again in case another thread created it in the meantime
161 camera = FindCameraEntryLocked( targetHash );
162 if ( camera != nullptr )
163 {
164 camera->_useCount.fetch_add( 1u );
165 return camera->_camera.get();
166 }
167
168 // No such luck. Create it ourselves.
169 s_cameraPool.emplace_back( nullptr, 1u);
170 s_cameraPool.back()._camera.reset( new Camera( cameraName, mode ));
171
172 return s_cameraPool.back()._camera.get();
173 }
174
176 {
177 if ( camera == nullptr )
178 {
179 return true; //??
180 }
181
182 const U64 targetHash = _ID( camera->resourceName().c_str() );
183 camera = nullptr;
184
185 LockGuard<SharedMutex> w_lock( s_cameraPoolLock );
186
187 return erase_if( s_cameraPool,
188 [targetHash]( CameraEntry& camEntry )
189 {
190 if (_ID( camEntry._camera->resourceName().c_str() ) == targetHash)
191 {
192 camEntry._useCount.fetch_sub( 1u );
193 return camEntry._useCount == 0u;
194 }
195
196 return false;
197 }) > 0;
198 }
199
201 {
203
204 SharedLock<SharedMutex> r_lock( s_cameraPoolLock );
205 return FindCameraEntryLocked( nameHash );
206 }
207
209 {
210 auto it = eastl::find_if( begin( s_cameraPool ),
211 end( s_cameraPool ),
212 [nameHash]( CameraEntry& camEntry )
213 {
214 return _ID( camEntry._camera->resourceName().c_str() ) == nameHash;
215 } );
216 if ( it != std::end( s_cameraPool ) )
217 {
218 return &(*it);
219 }
220
221 return nullptr;
222 }
223
225 {
226 CameraEntry* entry = FindCameraEntry( nameHash );
227 if ( entry != nullptr )
228 {
229 return entry->_camera.get();
230 }
231
232 return nullptr;
233 }
234
236 {
238
239 const auto it = s_changeCameraListeners.find( id );
240 if ( it != std::cend( s_changeCameraListeners ) )
241 {
242 s_changeCameraListeners.erase( it );
243 return true;
244 }
245
246 return false;
247 }
248
250 {
252
253 insert( s_changeCameraListeners, ++s_changeCameraId, f );
254 return s_changeCameraId;
255 }
256
257 Camera::Camera( const std::string_view name, const Mode mode, const vec3<F32>& eye )
258 : Resource( name, "Camera" )
259 , _mode( mode )
260 {
261 _data._eye.set( eye );
262 _data._fov = 60.0f;
263 _data._aspectRatio = 1.77f;
268 _data._zPlanes.set( 0.1f, 1000.0f );
270 }
271
272 void Camera::fromCamera( const Camera& camera )
273 {
275
277 _reflectionActive = camera._reflectionActive;
279 _maxRadius = camera._maxRadius;
280 _minRadius = camera._minRadius;
281 _curRadius = camera._curRadius;
284 _rotationDirty = true;
285 _offsetDir.set( camera._offsetDir );
288 _speedFactor = camera._speedFactor;
289 _orthoRect.set( camera._orthoRect );
290 setFixedYawAxis( camera._yawFixed, camera._fixedYawAxis );
291 rotationLocked( camera._rotationLocked );
292 movementLocked( camera._movementLocked );
293 frustumLocked( camera._frustumLocked );
294 fromSnapshot( camera.snapshot() );
295 }
296
297 void Camera::fromSnapshot( const CameraSnapshot& snapshot )
298 {
300
305 if ( _data._isOrthoCamera )
306 {
307 setProjection( _orthoRect, snapshot._zPlanes );
308 }
309 else
310 {
311
313 }
314 updateLookAt();
315 }
316
317 void Camera::update() noexcept
318 {
319 if ( (mode() == Mode::ORBIT || mode() == Mode::THIRD_PERSON) && _targetTransform != nullptr )
320 {
322
323 vec3<Angle::RADIANS<F32>> newTargetOrientation;
324 if (/*trans->changedLastFrame() || */ _rotationDirty || true )
325 {
326 newTargetOrientation = _targetTransform->getWorldOrientation().getEuler();
327 newTargetOrientation.yaw = M_PI_f - newTargetOrientation.yaw;
328 newTargetOrientation += _cameraRotation;
329 Util::Normalize( newTargetOrientation, false );
330 _rotationDirty = false;
331 }
332
333 _data._orientation.fromEuler( Angle::to_DEGREES( newTargetOrientation ) );
334
335 _minRadius = std::max( _minRadius, 0.01f );
336 if ( _minRadius > _maxRadius )
337 {
338 std::swap( _minRadius, _maxRadius );
339 }
340 CLAMP<F32>( _curRadius, _minRadius, _maxRadius );
341
343 setEye( _data._orientation.zAxis() * _curRadius + targetPos );
344 _viewMatrixDirty = true;
345 }
346 }
347
348 void Camera::setTarget( TransformComponent* tComp, const vec3<F32>& offsetDirection ) noexcept
349 {
350 _targetTransform = tComp;
351 _offsetDir = Normalized( offsetDirection );
352 }
353
354 const mat4<F32>& Camera::lookAt( const mat4<F32>& viewMatrix )
355 {
357
358 _data._eye.set( ExtractCameraPos2( viewMatrix ) );
360 _viewMatrixDirty = true;
361 _frustumDirty = true;
363
364 return _data._viewMatrix;
365 }
366
368 const vec3<F32>& target,
369 const vec3<F32>& up )
370 {
372
373 _data._eye.set( eye );
374 _data._orientation.fromMatrix( LookAt( eye, target, up ) );
375 _viewMatrixDirty = true;
376 _frustumDirty = true;
377
379
380 return _data._viewMatrix;
381 }
382
385 {
387
388 bool cameraUpdated = updateViewMatrix();
389 cameraUpdated = updateProjection() || cameraUpdated;
390 cameraUpdated = updateFrustum() || cameraUpdated;
391
392 if ( cameraUpdated )
393 {
395
396 for ( const auto& it : _updateCameraListeners )
397 {
398 it.second( *this );
399 }
400 }
401
402 return cameraUpdated;
403 }
404
405 void Camera::setGlobalRotation( const F32 yaw, const F32 pitch, const F32 roll ) noexcept
406 {
407 if ( _rotationLocked )
408 {
409 return;
410 }
411
413
414 const Quaternion<F32> pitchRot( WORLD_X_AXIS, -pitch );
415 const Quaternion<F32> yawRot( WORLD_Y_AXIS, -yaw );
416
417 if ( !IS_ZERO( roll ) )
418 {
419 setRotation( yawRot * pitchRot * Quaternion<F32>( WORLD_Z_AXIS, -roll ) );
420 }
421 else
422 {
423 setRotation( yawRot * pitchRot );
424 }
425 }
426
428 {
429 if ( _rotationLocked )
430 {
431 return;
432 }
433
435
436 if ( mode() == Mode::FIRST_PERSON )
437 {
439 rotate( euler.yaw, euler.pitch, euler.roll );
440 }
441 else
442 {
445 }
446
447 _viewMatrixDirty = true;
448 }
449
451 {
453
454 const auto& it = _updateCameraListeners.find( id );
455 if ( it != std::cend( _updateCameraListeners ) )
456 {
457 _updateCameraListeners.erase( it );
458 return true;
459 }
460
461 return false;
462 }
463
465 {
467
469 return _updateCameraId;
470 }
471
472 void Camera::setReflection( const Plane<F32>& reflectionPlane ) noexcept
473 {
474 _reflectionPlane = reflectionPlane;
475 _reflectionActive = true;
476 _viewMatrixDirty = true;
477 }
478
480 {
481 _reflectionActive = false;
482 _viewMatrixDirty = true;
483 }
484
486 {
488
489 if ( _projectionDirty )
490 {
491 if ( _data._isOrthoCamera )
492 {
493 _data._projectionMatrix = Ortho( _orthoRect.left,
494 _orthoRect.right,
495 _orthoRect.bottom,
496 _orthoRect.top,
498 _data._zPlanes.y );
499 }
500 else
501 {
505 _data._zPlanes.y );
506 }
508 _frustumDirty = true;
509 _projectionDirty = false;
510 return true;
511 }
512
513 return false;
514 }
515
517 {
518 return setProjection( _data._fov, zPlanes );
519 }
520
521 const mat4<F32>& Camera::setProjection( const F32 verticalFoV, const vec2<F32> zPlanes )
522 {
523 return setProjection( _data._aspectRatio, verticalFoV, zPlanes );
524 }
525
526 const mat4<F32>& Camera::setProjection( const F32 aspectRatio, const F32 verticalFoV, const vec2<F32> zPlanes )
527 {
529
530 setAspectRatio( aspectRatio );
531 setVerticalFoV( verticalFoV );
532
533 _data._zPlanes = zPlanes;
534 _data._isOrthoCamera = false;
535 _projectionDirty = true;
537
538 return projectionMatrix();
539 }
540
541 const mat4<F32>& Camera::setProjection( const vec4<F32>& rect, const vec2<F32> zPlanes )
542 {
544
545 _data._zPlanes = zPlanes;
546 _orthoRect = rect;
547 _data._isOrthoCamera = true;
548 _projectionDirty = true;
550
551 return projectionMatrix();
552 }
553
554 const mat4<F32>& Camera::setProjection( const mat4<F32>& projection, const vec2<F32> zPlanes, const bool isOrtho ) noexcept
555 {
557
558 _data._projectionMatrix.set( projection );
559 _data._projectionMatrix.getInverse( _data._invProjectionMatrix );
560 _data._zPlanes = zPlanes;
561 _projectionDirty = false;
562 _frustumDirty = true;
563 _data._isOrthoCamera = isOrtho;
564
565 return _data._projectionMatrix;
566 }
567
568 void Camera::setAspectRatio( const F32 ratio ) noexcept
569 {
570 _data._aspectRatio = ratio;
571 _projectionDirty = true;
572 }
573
574 void Camera::setVerticalFoV( const Angle::DEGREES<F32> verticalFoV ) noexcept
575 {
576 _data._fov = verticalFoV;
577 _projectionDirty = true;
578 }
579
580 void Camera::setHorizontalFoV( const Angle::DEGREES<F32> horizontalFoV ) noexcept
581 {
582 _data._fov = Angle::to_VerticalFoV( horizontalFoV, to_D64( _data._aspectRatio ) );
583 _projectionDirty = true;
584 }
585
587 {
588 const Angle::RADIANS<F32> halfFoV = Angle::to_RADIANS( _data._fov ) * 0.5f;
589 return Angle::to_DEGREES( 2.0f * std::atan( tan( halfFoV ) * _data._aspectRatio ) );
590 }
591
592 void Camera::setRotation( const Angle::DEGREES<F32> yaw, const Angle::DEGREES<F32> pitch, const Angle::DEGREES<F32> roll ) noexcept
593 {
594 setRotation( Quaternion<F32>( pitch, yaw, roll ) );
595 }
596
598 {
599 if ( _rotationLocked )
600 {
601 return;
602 }
603
605
606 const F32 turnSpeed = speedFactor().turn * s_lastFrameTimeSec;
607 yaw = -yaw * turnSpeed;
608 pitch = -pitch * turnSpeed;
609 roll = -roll * turnSpeed;
610
611 Quaternion<F32> tempOrientation;
612 if ( mode() == Mode::FIRST_PERSON )
613 {
614 _accumPitchDegrees += pitch;
615
616 if ( _accumPitchDegrees > 90.0f )
617 {
618 pitch = 90.0f - (_accumPitchDegrees - pitch);
619 _accumPitchDegrees = 90.0f;
620 }
621
622 if ( _accumPitchDegrees < -90.0f )
623 {
624 pitch = -90.0f - (_accumPitchDegrees - pitch);
625 _accumPitchDegrees = -90.0f;
626 }
627
628 // Rotate camera about the world y axis.
629 // Note the order the quaternions are multiplied. That is important!
630 if ( !IS_ZERO( yaw ) )
631 {
632 tempOrientation.fromAxisAngle( WORLD_Y_AXIS, yaw );
633 _data._orientation = tempOrientation * _data._orientation;
634 }
635
636 // Rotate camera about its local x axis.
637 // Note the order the quaternions are multiplied. That is important!
638 if ( !IS_ZERO( pitch ) )
639 {
640 tempOrientation.fromAxisAngle( WORLD_X_AXIS, pitch );
641 _data._orientation = _data._orientation * tempOrientation;
642 }
643 }
644 else
645 {
646 tempOrientation.fromEuler( pitch, yaw, roll );
647 _data._orientation *= tempOrientation;
648 }
649
650 _viewMatrixDirty = true;
651 }
652
654 {
655 rotate( Quaternion<F32>( _yawFixed ? _fixedYawAxis : _data._orientation * WORLD_Y_AXIS, -angle * speedFactor().turn * s_lastFrameTimeSec ) );
656 }
657
659 {
660 rotate( Quaternion<F32>( _data._orientation * WORLD_Z_AXIS, -angle * speedFactor().turn * s_lastFrameTimeSec ) );
661 }
662
664 {
665 rotate( Quaternion<F32>( _data._orientation * WORLD_X_AXIS, -angle * speedFactor().turn * s_lastFrameTimeSec ) );
666 }
667
668 void Camera::move( F32 dx, F32 dy, F32 dz ) noexcept
669 {
670 if ( _movementLocked )
671 {
672 return;
673 }
674
676
677 const F32 moveSpeed = speedFactor().move * s_lastFrameTimeSec;
678 dx *= moveSpeed;
679 dy *= moveSpeed;
680 dz *= moveSpeed;
681
682 const mat4<F32>& viewMat = viewMatrix();
683 const vec3<F32> rightDir = viewMat.getRightDirection();
684
685 _data._eye += rightDir * dx;
686 _data._eye += WORLD_Y_AXIS * dy;
687
688 if ( mode() == Mode::FIRST_PERSON )
689 {
690 // Calculate the forward direction. Can't just use the camera's local
691 // z axis as doing so will cause the camera to move more slowly as the
692 // camera's view approaches 90 degrees straight up and down.
693 const vec3<F32> forward = Normalized( Cross( WORLD_Y_AXIS, rightDir ) );
694 _data._eye += forward * dz;
695 }
696 else
697 {
698 _data._eye += viewMat.getForwardDirection() * dz;
699 }
700
701 _viewMatrixDirty = true;
702 }
703
705 {
707
708 bool updated = false;
709 if ( mode() == Mode::FREE_FLY )
710 {
711 updated = moveRelative(
712 {
713 playerState._moveFB.topValue(),
714 playerState._moveLR.topValue(),
715 playerState._moveUD.topValue()
716 }) || updated;
717 }
718
719
720
721 updated = rotateRelative(
722 {
723 playerState._angleUD.topValue(),
724 playerState._angleLR.topValue(),
725 playerState._roll.topValue()
726 }) || updated;
727
728 if ( mode() == Mode::ORBIT || mode() == Mode::THIRD_PERSON )
729 {
730 updated = zoom( playerState._zoom.topValue() ) || updated;
731 }
732
733 return updated;
734
735 }
736
737 bool Camera::moveRelative( const vec3<F32>& relMovement )
738 {
739 if ( relMovement.lengthSquared() > 0 )
740 {
741 move( relMovement.y, relMovement.z, relMovement.x );
742 return true;
743 }
744
745 return false;
746 }
747
748 bool Camera::rotateRelative( const vec3<F32>& relRotation )
749 {
750 if ( relRotation.lengthSquared() <= 0.f )
751 {
752 return false;
753 }
754
756
757 vec3<Angle::DEGREES<F32>> rotation( relRotation * speedFactor().turn * s_lastFrameTimeSec );
758
759 if ( mode() == Mode::THIRD_PERSON || mode() == Mode::ORBIT )
760 {
761 constexpr F32 rotationLimitRollLower = M_PI_f * 0.30f - Angle::to_RADIANS( 1 );
762 constexpr F32 rotationLimitRollUpper = M_PI_f * 0.175f - Angle::to_RADIANS( 1 );
763 constexpr F32 rotationLimitPitch = M_PI_f - Angle::to_RADIANS( 1 );
764
765 if ( !IS_ZERO( rotation.yaw ) )
766 {
767 const Angle::RADIANS<F32> yawRad = Angle::DegreesToRadians( rotation.yaw );
768
769 const F32 targetYaw = _cameraRotation.yaw - yawRad;
770 if ( mode() == Mode::ORBIT || (targetYaw > -rotationLimitRollLower && targetYaw < rotationLimitRollUpper) )
771 {
772 _cameraRotation.yaw -= yawRad;
773 _rotationDirty = true;
774 }
775 }
776
777 if ( !IS_ZERO( rotation.pitch ) )
778 {
779 const Angle::RADIANS<F32> pitchRad = Angle::DegreesToRadians( rotation.pitch );
780
781 const F32 targetPitch = _cameraRotation.yaw - pitchRad;
782 if ( mode() == Mode::ORBIT || (targetPitch > -rotationLimitPitch && targetPitch < rotationLimitPitch) )
783 {
784 _cameraRotation.pitch -= pitchRad;
785 _rotationDirty = true;
786 }
787 }
788
789 if ( _rotationDirty )
790 {
791 Util::Normalize( _cameraRotation, false, true, false, true );
792 return true;
793 }
794 }
795 else
796 {
800 return true;
801 }
802
803 return false;
804 }
805
806 bool Camera::zoom( const F32 zoomFactor ) noexcept
807 {
808 if ( !IS_ZERO( zoomFactor ) )
809 {
810 curRadius( _curRadius += zoomFactor * speedFactor().zoom * s_lastFrameTimeSec * -0.01f );
811 return true;
812 }
813
814 return false;
815 }
816
817
819 {
820 if ( !_viewMatrixDirty )
821 {
822 return false;
823 }
824
826
828
829 //_target = -zAxis + _data._eye;
830
831 // Reconstruct the view matrix.
837 1.f );
838
840
841 // Extract the pitch angle from the view matrix.
843
844 if ( _reflectionActive )
845 {
847 _data._eye.set( mat4<F32>( _reflectionPlane ).transformNonHomogeneous( _data._eye ) );
848 }
850 _viewMatrixDirty = false;
851 _frustumDirty = true;
852
853 return true;
854 }
855
857 {
858 if ( _frustumLocked )
859 {
860 return true;
861 }
862 if ( !_frustumDirty )
863 {
864 return false;
865 }
866
868
869 _frustumLocked = true;
870 updateLookAt();
871 _frustumLocked = false;
872
874 _frustumDirty = false;
875
876 return true;
877 }
878
879 vec3<F32> Camera::unProject( const F32 winCoordsX, const F32 winCoordsY, const Rect<I32>& viewport ) const noexcept
880 {
882
883 const F32 offsetWinCoordsX = winCoordsX - viewport.x;
884 const F32 offsetWinCoordsY = winCoordsY - viewport.y;
885 const I32 winWidth = viewport.z;
886 const I32 winHeight = viewport.w;
887
888 const vec2<F32> ndcSpace =
889 {
890 offsetWinCoordsX / (winWidth * 0.5f) - 1.0f,
891 offsetWinCoordsY / (winHeight * 0.5f) - 1.0f
892 };
893
894 const vec4<F32> clipSpace = {
895 ndcSpace.x,
896 ndcSpace.y,
897 0.0f, //z
898 1.0f //w
899 };
900
901 const mat4<F32> invProjMatrix = GetInverse( projectionMatrix() );
902
903 const vec2<F32> tempEyeSpace = (invProjMatrix * clipSpace).xy;
904
905 const vec4<F32> eyeSpace = {
906 tempEyeSpace.x,
907 tempEyeSpace.y,
908 -1.0f, // z
909 0.0f // w
910 };
911
912 const vec3<F32> worldSpace = (worldMatrix() * eyeSpace).xyz;
913
914 return Normalized( worldSpace );
915 }
916
917 vec2<F32> Camera::project( const vec3<F32>& worldCoords, const Rect<I32>& viewport ) const noexcept
918 {
920
921 const vec2<F32> winOffset = viewport.xy;
922
923 const vec2<F32> winSize = viewport.zw;
924
925 const vec4<F32> viewSpace = viewMatrix() * vec4<F32>( worldCoords, 1.0f );
926
927 const vec4<F32> clipSpace = projectionMatrix() * viewSpace;
928
929 const F32 clampedClipW = std::max( clipSpace.w, EPSILON_F32 );
930
931 const vec2<F32> ndcSpace = clipSpace.xy / clampedClipW;
932
933 const vec2<F32> winSpace = (ndcSpace + 1.0f) * 0.5f * winSize;
934
935 return winOffset + winSpace;
936 }
937
938 mat4<F32> Camera::LookAt( const vec3<F32>& eye, const vec3<F32>& target, const vec3<F32>& up ) noexcept
939 {
940 const vec3<F32> zAxis( Normalized( eye - target ) );
941 const vec3<F32> xAxis( Normalized( Cross( up, zAxis ) ) );
942 const vec3<F32> yAxis( Normalized( Cross( zAxis, xAxis ) ) );
943
944 mat4<F32> ret;
945
946 ret.m[0][0] = xAxis.x;
947 ret.m[1][0] = xAxis.y;
948 ret.m[2][0] = xAxis.z;
949 ret.m[3][0] = -xAxis.dot( eye );
950
951 ret.m[0][1] = yAxis.x;
952 ret.m[1][1] = yAxis.y;
953 ret.m[2][1] = yAxis.z;
954 ret.m[3][1] = -yAxis.dot( eye );
955
956 ret.m[0][2] = zAxis.x;
957 ret.m[1][2] = zAxis.y;
958 ret.m[2][2] = zAxis.z;
959 ret.m[3][2] = -zAxis.dot( eye );
960
961 ret.m[0][3] = 0;
962 ret.m[1][3] = 0;
963 ret.m[2][3] = 0;
964 ret.m[3][3] = 1;
965
966 return ret;
967 }
968
969 void Camera::saveToXML( boost::property_tree::ptree& pt, const std::string prefix ) const
970 {
971 const vec4<F32> orientation = _data._orientation.asVec4();
972
973 std::string savePath = (prefix.empty() ? "camera." : (prefix + ".camera."));
974 savePath.append(Util::MakeXMLSafe(resourceName()));
975
976 pt.put( savePath + ".reflectionPlane.normal.<xmlattr>.x", _reflectionPlane._normal.x );
977 pt.put( savePath + ".reflectionPlane.normal.<xmlattr>.y", _reflectionPlane._normal.y );
978 pt.put( savePath + ".reflectionPlane.normal.<xmlattr>.z", _reflectionPlane._normal.z );
979 pt.put( savePath + ".reflectionPlane.distance", _reflectionPlane._distance );
980 pt.put( savePath + ".reflectionPlane.active", _reflectionActive );
981 pt.put( savePath + ".accumPitchDegrees", _accumPitchDegrees );
982 pt.put( savePath + ".frustumLocked", _frustumLocked );
983 pt.put( savePath + ".euler.<xmlattr>.x", _euler.x );
984 pt.put( savePath + ".euler.<xmlattr>.y", _euler.y );
985 pt.put( savePath + ".euler.<xmlattr>.z", _euler.z );
986 pt.put( savePath + ".eye.<xmlattr>.x", _data._eye.x );
987 pt.put( savePath + ".eye.<xmlattr>.y", _data._eye.y );
988 pt.put( savePath + ".eye.<xmlattr>.z", _data._eye.z );
989 pt.put( savePath + ".orientation.<xmlattr>.x", orientation.x );
990 pt.put( savePath + ".orientation.<xmlattr>.y", orientation.y );
991 pt.put( savePath + ".orientation.<xmlattr>.z", orientation.z );
992 pt.put( savePath + ".orientation.<xmlattr>.w", orientation.w );
993 pt.put( savePath + ".aspectRatio", _data._aspectRatio );
994 pt.put( savePath + ".zPlanes.<xmlattr>.min", _data._zPlanes.min );
995 pt.put( savePath + ".zPlanes.<xmlattr>.max", _data._zPlanes.max );
996 pt.put( savePath + ".FoV", _data._fov );
997 pt.put( savePath + ".speedFactor.<xmlattr>.turn", _speedFactor.turn );
998 pt.put( savePath + ".speedFactor.<xmlattr>.move", _speedFactor.move );
999 pt.put( savePath + ".speedFactor.<xmlattr>.zoom", _speedFactor.zoom );
1000 pt.put( savePath + ".fixedYawAxis.<xmlattr>.x", _fixedYawAxis.x );
1001 pt.put( savePath + ".fixedYawAxis.<xmlattr>.y", _fixedYawAxis.y );
1002 pt.put( savePath + ".fixedYawAxis.<xmlattr>.z", _fixedYawAxis.z );
1003 pt.put( savePath + ".yawFixed", _yawFixed );
1004 pt.put( savePath + ".rotationLocked", _rotationLocked );
1005 pt.put( savePath + ".movementLocked", _movementLocked );
1006 pt.put( savePath + ".maxRadius", maxRadius() );
1007 pt.put( savePath + ".minRadius", minRadius() );
1008 pt.put( savePath + ".curRadius", curRadius() );
1009 pt.put( savePath + ".cameraRotation.<xmlattr>.x", _cameraRotation.x );
1010 pt.put( savePath + ".cameraRotation.<xmlattr>.y", _cameraRotation.y );
1011 pt.put( savePath + ".cameraRotation.<xmlattr>.z", _cameraRotation.z );
1012 pt.put( savePath + ".offsetDir.<xmlattr>.x", _offsetDir.x );
1013 pt.put( savePath + ".offsetDir.<xmlattr>.y", _offsetDir.y );
1014 pt.put( savePath + ".offsetDir.<xmlattr>.z", _offsetDir.z );
1015 }
1016
1017 void Camera::loadFromXML( const boost::property_tree::ptree& pt, const std::string prefix )
1018 {
1019 const vec4<F32> orientation = _data._orientation.asVec4();
1020
1021 std::string savePath = (prefix.empty() ? "camera." : (prefix + ".camera."));
1022 savePath.append(Util::MakeXMLSafe(resourceName()));
1023
1025 pt.get( savePath + ".reflectionPlane.normal.<xmlattr>.x", _reflectionPlane._normal.x ),
1026 pt.get( savePath + ".reflectionPlane.normal.<xmlattr>.y", _reflectionPlane._normal.y ),
1027 pt.get( savePath + ".reflectionPlane.normal.<xmlattr>.z", _reflectionPlane._normal.z ),
1028 pt.get( savePath + ".reflectionPlane.distance", _reflectionPlane._distance )
1029 );
1030 _reflectionActive = pt.get( savePath + ".reflectionPlane.active", _reflectionActive );
1031
1032 _accumPitchDegrees = pt.get( savePath + ".accumPitchDegrees", _accumPitchDegrees );
1033 _frustumLocked = pt.get( savePath + ".frustumLocked", _frustumLocked );
1034 _euler.set(
1035 pt.get( savePath + ".euler.<xmlattr>.x", _euler.x ),
1036 pt.get( savePath + ".euler.<xmlattr>.y", _euler.y ),
1037 pt.get( savePath + ".euler.<xmlattr>.z", _euler.z )
1038 );
1039 _data._eye.set(
1040 pt.get( savePath + ".eye.<xmlattr>.x", _data._eye.x ),
1041 pt.get( savePath + ".eye.<xmlattr>.y", _data._eye.y ),
1042 pt.get( savePath + ".eye.<xmlattr>.z", _data._eye.z )
1043 );
1045 pt.get( savePath + ".orientation.<xmlattr>.x", orientation.x ),
1046 pt.get( savePath + ".orientation.<xmlattr>.y", orientation.y ),
1047 pt.get( savePath + ".orientation.<xmlattr>.z", orientation.z ),
1048 pt.get( savePath + ".orientation.<xmlattr>.w", orientation.w )
1049 );
1051 pt.get( savePath + ".zPlanes.<xmlattr>.min", _data._zPlanes.min ),
1052 pt.get( savePath + ".zPlanes.<xmlattr>.max", _data._zPlanes.max )
1053 );
1054 _data._aspectRatio = pt.get( savePath + ".aspectRatio", _data._aspectRatio );
1055 _data._fov = pt.get( savePath + ".FoV", _data._fov );
1056
1057
1058 _speedFactor.turn = pt.get( savePath + ".speedFactor.<xmlattr>.turn", _speedFactor.turn );
1059 _speedFactor.move = pt.get( savePath + ".speedFactor.<xmlattr>.move", _speedFactor.move );
1060 _speedFactor.zoom = pt.get( savePath + ".speedFactor.<xmlattr>.zoom", _speedFactor.zoom );
1062 pt.get( savePath + ".fixedYawAxis.<xmlattr>.x", _fixedYawAxis.x ),
1063 pt.get( savePath + ".fixedYawAxis.<xmlattr>.y", _fixedYawAxis.y ),
1064 pt.get( savePath + ".fixedYawAxis.<xmlattr>.z", _fixedYawAxis.z )
1065 );
1066 _yawFixed = pt.get( savePath + ".yawFixed", _yawFixed );
1067 _rotationLocked = pt.get( savePath + ".rotationLocked", _rotationLocked );
1068 _movementLocked = pt.get( savePath + ".movementLocked", _movementLocked );
1069 maxRadius( pt.get( savePath + ".maxRadius", maxRadius() ) );
1070 minRadius( pt.get( savePath + ".minRadius", minRadius() ) );
1071 curRadius( pt.get( savePath + ".curRadius", curRadius() ) );
1073 pt.get( savePath + ".cameraRotation.<xmlattr>.x", _cameraRotation.x ),
1074 pt.get( savePath + ".cameraRotation.<xmlattr>.y", _cameraRotation.y ),
1075 pt.get( savePath + ".cameraRotation.<xmlattr>.z", _cameraRotation.z )
1076 );
1078 pt.get( savePath + ".offsetDir.<xmlattr>.x", _offsetDir.x ),
1079 pt.get( savePath + ".offsetDir.<xmlattr>.y", _offsetDir.y ),
1080 pt.get( savePath + ".offsetDir.<xmlattr>.z", _offsetDir.z )
1081 );
1083 }
1084
1085} //namespace Divide
#define LOCALE_STR(X)
Definition: Localization.h:91
#define PROFILE_SCOPE_AUTO(CATEGORY)
Definition: Profiler.h:87
F32 _currentRotationY
Definition: Camera.h:288
const mat4< F32 > & projectionMatrix() const noexcept
Returns the most recent/up-to-date projection matrix.
Definition: Camera.inl:168
static void DestroyPool()
Definition: Camera.cpp:139
const mat4< F32 > & setProjection(vec2< F32 > zPlanes)
Definition: Camera.cpp:516
vec3< F32 > _fixedYawAxis
Definition: Camera.h:284
bool updateViewMatrix() noexcept
Definition: Camera.cpp:818
void rotatePitch(Angle::DEGREES< F32 > angle)
Change camera's pitch.
Definition: Camera.cpp:663
bool rotateRelative(const vec3< F32 > &relRotation)
Definition: Camera.cpp:748
static CameraEntry * FindCameraEntryLocked(const U64 nameHash)
Definition: Camera.cpp:208
mat4< F32 > _viewProjectionMatrix
Definition: Camera.h:281
const mat4< F32 > & viewMatrix() const noexcept
Returns the most recent/up-to-date view matrix.
Definition: Camera.inl:157
static Camera * GetUtilityCamera(const UtilityCamera type)
Definition: Camera.cpp:120
const mat4< F32 > & lookAt(const mat4< F32 > &viewMatrix)
Sets the camera's view matrix to specify the specified value by extracting the eye position,...
Definition: Camera.cpp:354
bool updateFrustum()
Extract the frustum associated with our current PoV.
Definition: Camera.cpp:856
Angle::DEGREES< F32 > getHorizontalFoV() const noexcept
Returns the horizontal field of view, calculated from the vertical FoV and aspect ratio.
Definition: Camera.cpp:586
void rotateYaw(Angle::DEGREES< F32 > angle)
Definition: Camera.cpp:653
static Camera * CreateCamera(const Str< 256 > &cameraName, Mode cameraMode)
Definition: Camera.cpp:147
const CameraSnapshot & snapshot() const noexcept
Returns the internal camera snapshot data (eye, orientation, etc)
Definition: Camera.inl:43
bool _rotationDirty
Definition: Camera.h:294
static void InitPool()
Definition: Camera.cpp:130
static mat4< F32 > LookAt(const vec3< F32 > &eye, const vec3< F32 > &target, const vec3< F32 > &up) noexcept
Definition: Camera.cpp:938
void setAspectRatio(F32 ratio) noexcept
Definition: Camera.cpp:568
Plane< F32 > _reflectionPlane
Definition: Camera.h:282
bool updateLookAt()
Return true if the cached camera state wasn't up-to-date.
Definition: Camera.cpp:384
void fromSnapshot(const CameraSnapshot &snapshot)
Sets the internal snapshot data (eye, orientation, etc) to match the specified value.
Definition: Camera.cpp:297
bool _yawFixed
Definition: Camera.h:293
Frustum _frustum
Definition: Camera.h:279
void rotateRoll(Angle::DEGREES< F32 > angle)
Change camera's roll.
Definition: Camera.cpp:658
CameraListenerMap _updateCameraListeners
Definition: Camera.h:277
static Camera * FindCamera(const U64 nameHash)
Definition: Camera.cpp:224
void setFixedYawAxis(const bool useFixed, const vec3< F32 > &fixedAxis=WORLD_Y_AXIS) noexcept
Exactly as in Ogre3D: locks the yaw movement to the specified axis.
Definition: Camera.inl:141
void rotate(const Quaternion< F32 > &q)
Rotates the camera (changes its orientation) by the specified quaternion (_orientation *= q)
Definition: Camera.cpp:427
bool _projectionDirty
Definition: Camera.h:290
void setGlobalRotation(F32 yaw, F32 pitch, F32 roll=0.0f) noexcept
Global rotations are applied relative to the world axis, not the camera's.
Definition: Camera.cpp:405
void setHorizontalFoV(Angle::DEGREES< F32 > horizontalFoV) noexcept
Definition: Camera.cpp:580
vec3< Angle::RADIANS< F32 > > _cameraRotation
Definition: Camera.h:283
bool removeUpdateListener(U32 id)
Definition: Camera.cpp:450
Angle::DEGREES< F32 > _accumPitchDegrees
Definition: Camera.h:286
void setTarget(TransformComponent *tComp, const vec3< F32 > &offsetDirection=VECTOR3_ZERO) noexcept
Offset direction is a (eventually normalized) vector that is scaled by curRadius and applied to the c...
Definition: Camera.cpp:348
bool moveFromPlayerState(const SceneStatePerPlayer &playerState)
Definition: Camera.cpp:704
vec3< F32 > unProject(F32 winCoordsX, F32 winCoordsY, const Rect< I32 > &viewport) const noexcept
Definition: Camera.cpp:879
void setVerticalFoV(Angle::DEGREES< F32 > verticalFoV) noexcept
Definition: Camera.cpp:574
void setEye(const F32 x, const F32 y, const F32 z) noexcept
Sets the camera's eye position.
Definition: Camera.inl:100
static mat4< F32 > Perspective(Angle::DEGREES< F32 > fovyRad, F32 aspect, F32 zNear, F32 zFar) noexcept
Definition: Camera.inl:245
static CameraEntry * FindCameraEntry(const U64 nameHash)
Definition: Camera.cpp:200
TransformComponent * _targetTransform
Definition: Camera.h:280
CameraSnapshot _data
Definition: Camera.h:278
static mat4< F32 > Ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar) noexcept
Definition: Camera.inl:219
void saveToXML(boost::property_tree::ptree &pt, std::string prefix="") const
Definition: Camera.cpp:969
void fromCamera(const Camera &camera)
Copies all of the internal data from the specified camera to the current one.
Definition: Camera.cpp:272
U32 _updateCameraId
Definition: Camera.h:289
bool _frustumDirty
Definition: Camera.h:292
F32 _currentRotationX
Definition: Camera.h:287
bool zoom(F32 zoomFactor) noexcept
Definition: Camera.cpp:806
Camera(const std::string_view name, Mode mode, const vec3< F32 > &eye=VECTOR3_ZERO)
Definition: Camera.cpp:257
void setReflection(const Plane< F32 > &reflectionPlane) noexcept
Specify a reflection plane that alters the final view matrix to be a mirror of the internal lookAt ma...
Definition: Camera.cpp:472
bool updateProjection() noexcept
Definition: Camera.cpp:485
static U32 AddChangeListener(const CameraListener &f)
Definition: Camera.cpp:249
static bool RemoveChangeListener(U32 id)
Definition: Camera.cpp:235
bool _viewMatrixDirty
Definition: Camera.h:291
static bool DestroyCamera(Camera *&camera)
Definition: Camera.cpp:175
bool moveRelative(const vec3< F32 > &relMovement)
Definition: Camera.cpp:737
vec2< F32 > project(const vec3< F32 > &worldCoords, const Rect< I32 > &viewport) const noexcept
Definition: Camera.cpp:917
void loadFromXML(const boost::property_tree::ptree &pt, std::string prefix="")
Definition: Camera.cpp:1017
void setRotation(const Quaternion< F32 > &q) noexcept
Sets the camera's orientation.
Definition: Camera.inl:111
void clearReflection() noexcept
Clears the reflection plane specified (if any)
Definition: Camera.cpp:479
vec3< F32 > _offsetDir
Definition: Camera.h:285
static void Update(U64 deltaTimeUS)
Definition: Camera.cpp:107
U32 addUpdateListener(const CameraListener &f)
Definition: Camera.cpp:464
void move(F32 dx, F32 dy, F32 dz) noexcept
Moves the camera by the specified offsets in each direction.
Definition: Camera.cpp:668
void update() noexcept
Definition: Camera.cpp:317
const std::array< Plane< F32 >, to_base(FrustumPlane::COUNT)> & computePlanes(const mat4< F32 > &viewProjMatrix)
Definition: Frustum.cpp:226
void set(const vec4< T > &equation) noexcept
Definition: Plane.h:127
vec3< T > _normal
Definition: Plane.h:180
void fromMatrix(const mat3< T > &rotationMatrix) noexcept
Definition: Quaternion.inl:402
vec3< T > xAxis() const noexcept
Definition: Quaternion.inl:548
void fromAxisAngle(const vec3< T > &v, Angle::DEGREES< T > angle) noexcept
Convert from Axis Angle.
Definition: Quaternion.inl:310
void set(const vec4< T > &values) noexcept
Definition: Quaternion.inl:149
const vec4< T > & asVec4() const noexcept
Definition: Quaternion.inl:662
void identity() noexcept
Definition: Quaternion.inl:657
void normalize() noexcept
normalizing a quaternion works similar to a vector. This method will not
Definition: Quaternion.inl:164
vec3< T > yAxis() const noexcept
Definition: Quaternion.inl:568
vec3< T > zAxis() const noexcept
Definition: Quaternion.inl:588
vec3< Angle::RADIANS< T > > getEuler() const noexcept
Definition: Quaternion.inl:478
void fromEuler(const vec3< Angle::DEGREES< T > > &v) noexcept
Definition: Quaternion.inl:316
Quaternion< F32 > getWorldOrientation() const
Return the orientation quaternion.
vec3< F32 > getWorldPosition() const
Return the position.
vec3< T > getForwardDirection() const noexcept
Returns normalized(getForwardVec())
const mat4 & reflect(U x, U y, U z, U w) noexcept
void setRow(I32 index, U value) noexcept
mat4 getInverse() const noexcept
void identity() noexcept
static mat4< T > Multiply(const mat4< T > &matrixA, const mat4< T > &matrixB) noexcept
ret = A * B
vec3< T > getRightDirection() const noexcept
Returns normalized(getRightVec())
const vec4< T > & getRow(I32 index) const noexcept
void set(std::initializer_list< T > matrix) noexcept
void set(const T *v) noexcept
set the 2 components of the vector manually using a source pointer to a (large enough) array
Definition: MathVectors.h:335
T dot(const vec3 &v) const noexcept
calculate the dot product between this vector and the specified one
T lengthSquared() const noexcept
return the squared distance of the vector
void set(const T *v) noexcept
set the 3 components of the vector manually using a source pointer to a (large enough) array
Definition: MathVectors.h:707
vec2< T > xy
Definition: MathVectors.h:1366
vec3< T > xyz
Definition: MathVectors.h:1374
constexpr T DegreesToRadians(T angleDegrees) noexcept
Return the radian equivalent of the given degree value.
Definition: MathHelper.inl:429
constexpr DEGREES< T > to_DEGREES(RADIANS< T > angle) noexcept
Definition: MathHelper.inl:380
constexpr RADIANS< T > to_RADIANS(DEGREES< T > angle) noexcept
Definition: MathHelper.inl:368
constexpr DEGREES< T > to_VerticalFoV(DEGREES< T > horizontalFoV, D64 aspectRatio) noexcept
Definition: MathHelper.inl:352
static const char * fStops[]
Definition: Camera.h:62
static const char * cameraMode[]
Definition: Camera.h:321
constexpr Optick::Category::Type GameLogic
Definition: Profiler.h:63
const char * CameraModeToString(const Camera::Mode mode) noexcept
Definition: Camera.cpp:34
Camera::Mode StringToCameraMode(const string &name)
Definition: Camera.cpp:39
FStops StringToFStops(const string &name)
Definition: Camera.cpp:21
const char * FStopsToString(const FStops stop) noexcept
Definition: Camera.cpp:16
void Normalize(vec3< F32 > &inputRotation, bool degrees=false, bool normYaw=true, bool normPitch=true, bool normRoll=true) noexcept
Normalise the selected rotations to be within the +/-180 degree range.
Definition: MathHelper.cpp:449
string MakeXMLSafe(std::string_view subject)
std::array< Camera *, to_base(Camera::UtilityCamera::COUNT)> _utilityCameras
Definition: Camera.cpp:65
CameraListenerMap s_changeCameraListeners
Definition: Camera.cpp:67
eastl::list< CameraEntry > CameraPool
Definition: Camera.cpp:63
vec3< F32 > ExtractCameraPos2(const mat4< F32 > &a_modelView) noexcept
Definition: Camera.cpp:71
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
constexpr F32 M_PI_f
Definition: MathHelper.h:86
vec2< T > Normalized(vec2< T > vector) noexcept
Definition: MathVectors.inl:98
std::lock_guard< mutex > LockGuard
Definition: SharedMutex.h:55
bool IS_ZERO(const T X) noexcept
void insert(eastl::vector< T, A1 > &target, const eastl::vector< T, A2 > &source)
Definition: Vector.h:97
static const vec3< F32 > WORLD_X_AXIS
Definition: MathVectors.h:1439
int32_t I32
uint8_t U8
hashMap< U32, CameraListener > CameraListenerMap
Definition: Camera.h:80
static const vec3< F32 > WORLD_Z_AXIS
Definition: MathVectors.h:1441
constexpr D64 to_D64(const T value)
std::shared_mutex SharedMutex
Definition: SharedMutex.h:43
void GetInverse(const mat4< T > &inM, mat4< T > &r) noexcept
T Dot(vec2< T > a, vec2< T > b) noexcept
general vec2 dot product
constexpr F32 EPSILON_F32
std::shared_lock< mutex > SharedLock
Definition: SharedMutex.h:49
constexpr U64 _ID(const char *const str, const U64 value=val_64_const) noexcept
FStops
Definition: Camera.h:44
constexpr U8 to_U8(const T value)
vec2< T > Cross(vec2< T > v1, vec2< T > v2) noexcept
general vec2 cross function
Definition: MathVectors.inl:80
DELEGATE< void, const Camera & > CameraListener
Definition: Camera.h:79
mat3< T > GetMatrix(const Quaternion< T > &q) noexcept
Definition: Quaternion.inl:719
uint32_t U32
Project const SceneEntry & entry
Definition: DefaultScene.h:41
uint64_t U64
static const vec3< F32 > WORLD_Y_AXIS
Definition: MathVectors.h:1440
constexpr auto to_base(const Type value) -> Type
float asinf(const float in)
Definition: Camera.cpp:55
Camera_uptr _camera
Definition: Camera.cpp:56
std::atomic_size_t _useCount
Definition: Camera.cpp:57
Quaternion< F32 > _orientation
mat4< F32 > _invViewMatrix
mat4< F32 > _projectionMatrix
std::array< Plane< F32 >, 6 > _frustumPlanes
mat4< F32 > _invProjectionMatrix
Angle::DEGREES< F32 > _fov
static NO_INLINE void printfn(const char *format, T &&... args)
F32 topValue() const noexcept
Definition: SceneState.h:157