1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Reflection/BsIReflectable.h"
7#include "Math/BsMatrix4.h"
8#include "Math/BsVector3.h"
9#include "Math/BsVector2.h"
10#include "Math/BsVector2I.h"
11#include "Math/BsAABox.h"
12#include "Math/BsQuaternion.h"
13#include "Math/BsRay.h"
14#include "CoreThread/BsCoreObject.h"
15#include "Math/BsConvexVolume.h"
16#include "Renderer/BsRenderSettings.h"
17#include "Scene/BsSceneActor.h"
18
19namespace bs
20{
21 /** @addtogroup Renderer-Internal
22 * @{
23 */
24
25 /** Signals which portion of a Camera is dirty. */
26 enum class CameraDirtyFlag
27 {
28 // First few bits reserved by ActorDirtyFlag
29 RenderSettings = 1 << 4,
30 Viewport = 1 << 31
31 };
32
33 /** @} */
34 /** @addtogroup Implementation
35 * @{
36 */
37
38 /** Common base class for both sim and core thread implementations of Camera. */
39 class BS_CORE_EXPORT CameraBase : public SceneActor
40 {
41 public:
42 virtual ~CameraBase() = default;
43
44 /** @copydoc SceneActor::setTransform */
45 void setTransform(const Transform& transform) override;
46
47 /**
48 * Determines the camera horizontal field of view. This determines how wide the camera viewing angle is along the
49 * horizontal axis. Vertical FOV is calculated from the horizontal FOV and the aspect ratio.
50 */
51 virtual void setHorzFOV(const Radian& fovy);
52
53 /** @copydoc setHorzFOV() */
54 virtual const Radian& getHorzFOV() const;
55
56 /**
57 * Determines the distance from the frustum to the near clipping plane. Anything closer than the near clipping plane will
58 * not be rendered. Decreasing this value decreases depth buffer precision.
59 */
60 virtual void setNearClipDistance(float nearDist);
61
62 /** @copydoc setNearClipDistance() */
63 virtual float getNearClipDistance() const;
64
65 /**
66 * Determines the distance from the frustum to the far clipping plane. Anything farther than the far clipping plane will
67 * not be rendered. Increasing this value decreases depth buffer precision.
68 */
69 virtual void setFarClipDistance(float farDist);
70
71 /** @copydoc setFarClipDistance() */
72 virtual float getFarClipDistance() const;
73
74 /** Determines the current viewport aspect ratio (width / height). */
75 virtual void setAspectRatio(float ratio);
76
77 /** @copydoc setAspectRatio() */
78 virtual float getAspectRatio() const;
79
80 /** Manually set the extents of the frustum that will be used when calculating the projection matrix. This will
81 * prevents extents for being automatically calculated from aspect and near plane so it is up to the caller to keep
82 * these values accurate.
83 *
84 * @param[in] left The position where the left clip plane intersect the near clip plane, in view space.
85 * @param[in] right The position where the right clip plane intersect the near clip plane, in view space.
86 * @param[in] top The position where the top clip plane intersect the near clip plane, in view space.
87 * @param[in] bottom The position where the bottom clip plane intersect the near clip plane, in view space.
88 */
89 virtual void setFrustumExtents(float left, float right, float top, float bottom);
90
91 /**
92 * Resets frustum extents so they are automatically derived from other values. This is only relevant if you have
93 * previously set custom extents.
94 */
95 virtual void resetFrustumExtents();
96
97 /** Returns the extents of the frustum in view space at the near plane. */
98 virtual void getFrustumExtents(float& outleft, float& outright, float& outtop, float& outbottom) const;
99
100 /**
101 * Returns the standard projection matrix that determines how are 3D points projected to two dimensions. The layout
102 * of this matrix depends on currently used render system.
103 *
104 * @note
105 * You should use this matrix when sending the matrix to the render system to make sure everything works
106 * consistently when other render systems are used.
107 */
108 virtual const Matrix4& getProjectionMatrixRS() const;
109
110 /** Returns the inverse of the render-system specific projection matrix. See getProjectionMatrixRS(). */
111 virtual const Matrix4& getProjectionMatrixRSInv() const;
112
113 /**
114 * Returns the standard projection matrix that determines how are 3D points projected to two dimensions. Returned
115 * matrix is standard following right-hand rules and depth range of [-1, 1]. In case you need a render-system specific
116 * projection matrix call getProjectionMatrixRS().
117 */
118 virtual const Matrix4& getProjectionMatrix() const;
119
120 /** Returns the inverse of the projection matrix. See getProjectionMatrix(). */
121 virtual const Matrix4& getProjectionMatrixInv() const;
122
123 /** Gets the camera view matrix. Used for positioning/orienting the camera. */
124 virtual const Matrix4& getViewMatrix() const;
125
126 /** Returns the inverse of the view matrix. See getViewMatrix(). */
127 virtual const Matrix4& getViewMatrixInv() const;
128
129 /**
130 * Sets whether the camera should use the custom view matrix. When this is enabled camera will no longer calculate
131 * its view matrix based on position/orientation and caller will be resonsible to keep the view matrix up to date.
132 */
133 virtual void setCustomViewMatrix(bool enable, const Matrix4& viewMatrix = Matrix4::IDENTITY);
134
135 /** Returns true if a custom view matrix is used. */
136 virtual bool isCustomViewMatrixEnabled() const { return mCustomViewMatrix; }
137
138 /**
139 * Sets whether the camera should use the custom projection matrix. When this is enabled camera will no longer
140 * calculate its projection matrix based on field of view, aspect and other parameters and caller will be resonsible
141 * to keep the projection matrix up to date.
142 */
143 virtual void setCustomProjectionMatrix(bool enable, const Matrix4& projectionMatrix = Matrix4::IDENTITY);
144
145 /** Returns true if a custom projection matrix is used. */
146 virtual bool isCustomProjectionMatrixEnabled() const { return mCustomProjMatrix; }
147
148 /** Returns a convex volume representing the visible area of the camera, in local space. */
149 virtual const ConvexVolume& getFrustum() const;
150
151 /** Returns a convex volume representing the visible area of the camera, in world space. */
152 virtual ConvexVolume getWorldFrustum() const;
153
154 /** Returns the bounding of the frustum. */
155 const AABox& getBoundingBox() const;
156
157 /**
158 * Determines the type of projection used by the camera. Projection type controls how is 3D geometry projected onto a
159 * 2D plane.
160 */
161 virtual void setProjectionType(ProjectionType pt);
162
163 /** @copydoc setProjectionType() */
164 virtual ProjectionType getProjectionType() const;
165
166 /**
167 * Sets the orthographic window height, for use with orthographic rendering only.
168 *
169 * @param[in] w Width of the window in world units.
170 * @param[in] h Height of the window in world units.
171 *
172 * @note
173 * Calling this method will recalculate the aspect ratio, use setOrthoWindowHeight() or setOrthoWindowWidth() alone
174 * if you wish to preserve the aspect ratio but just fit one or other dimension to a particular size.
175 */
176 virtual void setOrthoWindow(float w, float h);
177
178 /**
179 * Determines the orthographic window height, for use with orthographic rendering only. The width of the window
180 * will be calculated from the aspect ratio. Value is specified in world units.
181 */
182 virtual void setOrthoWindowHeight(float h);
183
184 /** @copydoc setOrthoWindowHeight() */
185 virtual float getOrthoWindowHeight() const;
186
187 /**
188 * Determines the orthographic window width, for use with orthographic rendering only. The height of the window
189 * will be calculated from the aspect ratio. Value is specified in world units.
190 */
191 virtual void setOrthoWindowWidth(float w);
192
193 /** @copydoc setOrthoWindowWidth() */
194 virtual float getOrthoWindowWidth() const;
195
196 /**
197 * Determines a priority that determines in which orders the cameras are rendered. This only applies to cameras rendering
198 * to the same render target. Higher value means the camera will be rendered sooner.
199 */
200 void setPriority(INT32 priority) { mPriority = priority; _markCoreDirty(); }
201
202 /** @copydoc setPriority() */
203 INT32 getPriority() const { return mPriority; }
204
205 /** Determines layer bitfield that is used when determining which object should the camera render. */
206 void setLayers(UINT64 layers) { mLayers = layers; _markCoreDirty(); }
207
208 /** @copydoc setLayers() */
209 UINT64 getLayers() const { return mLayers; }
210
211 /**
212 * Determines number of samples to use when rendering to this camera. Values larger than 1 will enable MSAA
213 * rendering.
214 */
215 void setMSAACount(UINT32 count) { mMSAA = count; _markCoreDirty(); }
216
217 /** @copydoc setMSAACount() */
218 UINT32 getMSAACount() const { return mMSAA; }
219
220 /**
221 * Settings that control rendering for this view. They determine how will the renderer process this view, which
222 * effects will be enabled, and what properties will those effects use.
223 */
224 void setRenderSettings(const SPtr<RenderSettings>& settings)
225 { mRenderSettings = settings; _markCoreDirty((ActorDirtyFlag)CameraDirtyFlag::RenderSettings); }
226
227 /** @copydoc setRenderSettings() */
228 const SPtr<RenderSettings>& getRenderSettings() const { return mRenderSettings; }
229
230 /**
231 * Converts a point in world space to screen coordinates.
232 *
233 * @param[in] worldPoint 3D point in world space.
234 * @return 2D point on the render target attached to the camera's viewport, in pixels.
235 */
236 Vector2I worldToScreenPoint(const Vector3& worldPoint) const;
237
238 /**
239 * Converts a point in world space to normalized device coordinates.
240 *
241 * @param[in] worldPoint 3D point in world space.
242 * @return 2D point in normalized device coordinates ([-1, 1] range), relative to the camera's viewport.
243 */
244 Vector2 worldToNdcPoint(const Vector3& worldPoint) const;
245
246 /**
247 * Converts a point in world space to view space coordinates.
248 *
249 * @param[in] worldPoint 3D point in world space.
250 * @return 3D point relative to the camera's coordinate system.
251 */
252 Vector3 worldToViewPoint(const Vector3& worldPoint) const;
253
254 /**
255 * Converts a point in screen space to a point in world space.
256 *
257 * @param[in] screenPoint 2D point on the render target attached to the camera's viewport, in pixels.
258 * @param[in] depth Depth to place the world point at, in world coordinates. The depth is applied to the
259 * vector going from camera origin to the point on the near plane.
260 * @return 3D point in world space.
261 */
262 Vector3 screenToWorldPoint(const Vector2I& screenPoint, float depth = 0.5f) const;
263
264 /**
265 * Converts a point in screen space (pixels corresponding to render target attached to the camera) to a point in
266 * world space.
267 *
268 * @param[in] screenPoint Point to transform.
269 * @param[in] deviceDepth Depth to place the world point at, in normalized device coordinates.
270 * @return 3D point in world space.
271 */
272 Vector3 screenToWorldPointDeviceDepth(const Vector2I& screenPoint, float deviceDepth = 0.5f) const;
273
274 /**
275 * Converts a point in screen space to a point in view space.
276 *
277 * @param[in] screenPoint 2D point on the render target attached to the camera's viewport, in pixels.
278 * @param[in] depth Depth to place the world point at, in device depth. The depth is applied to the
279 * vector going from camera origin to the point on the near plane.
280 * @return 3D point relative to the camera's coordinate system.
281 */
282 Vector3 screenToViewPoint(const Vector2I& screenPoint, float depth = 0.5f) const;
283
284 /**
285 * Converts a point in screen space to normalized device coordinates.
286 *
287 * @param[in] screenPoint 2D point on the render target attached to the camera's viewport, in pixels.
288 * @return 2D point in normalized device coordinates ([-1, 1] range), relative to
289 * the camera's viewport.
290 */
291 Vector2 screenToNdcPoint(const Vector2I& screenPoint) const;
292
293 /**
294 * Converts a point in view space to world space.
295 *
296 * @param[in] viewPoint 3D point relative to the camera's coordinate system.
297 * @return 3D point in world space.
298 */
299 Vector3 viewToWorldPoint(const Vector3& viewPoint) const;
300
301 /**
302 * Converts a point in view space to screen space.
303 *
304 * @param[in] viewPoint 3D point relative to the camera's coordinate system.
305 * @return 2D point on the render target attached to the camera's viewport, in pixels.
306 */
307 Vector2I viewToScreenPoint(const Vector3& viewPoint) const;
308
309 /**
310 * Converts a point in view space to normalized device coordinates.
311 *
312 * @param[in] viewPoint 3D point relative to the camera's coordinate system.
313 * @return 2D point in normalized device coordinates ([-1, 1] range), relative to
314 * the camera's viewport.
315 */
316 Vector2 viewToNdcPoint(const Vector3& viewPoint) const;
317
318 /**
319 * Converts a point in normalized device coordinates to world space.
320 *
321 * @param[in] ndcPoint 2D point in normalized device coordinates ([-1, 1] range), relative to
322 * the camera's viewport.
323 * @param[in] depth Depth to place the world point at. The depth is applied to the
324 * vector going from camera origin to the point on the near plane.
325 * @return 3D point in world space.
326 */
327 Vector3 ndcToWorldPoint(const Vector2& ndcPoint, float depth = 0.5f) const;
328
329 /**
330 * Converts a point in normalized device coordinates to view space.
331 *
332 * @param[in] ndcPoint 2D point in normalized device coordinates ([-1, 1] range), relative to
333 * the camera's viewport.
334 * @param[in] depth Depth to place the world point at. The depth is applied to the
335 * vector going from camera origin to the point on the near plane.
336 * @return 3D point relative to the camera's coordinate system.
337 */
338 Vector3 ndcToViewPoint(const Vector2& ndcPoint, float depth = 0.5f) const;
339
340 /**
341 * Converts a point in normalized device coordinates to screen space.
342 *
343 * @param[in] ndcPoint 2D point in normalized device coordinates ([-1, 1] range), relative to
344 * the camera's viewport.
345 * @return 2D point on the render target attached to the camera's viewport, in pixels.
346 */
347 Vector2I ndcToScreenPoint(const Vector2& ndcPoint) const;
348
349 /**
350 * Converts a point in screen space to a ray in world space.
351 *
352 * @param[in] screenPoint 2D point on the render target attached to the camera's viewport, in pixels.
353 * @return Ray in world space, originating at the selected point on the camera near plane.
354 */
355 Ray screenPointToRay(const Vector2I& screenPoint) const;
356
357 /**
358 * Projects a point in view space to normalized device coordinates. Similar to viewToNdcPoint() but preserves
359 * the depth component.
360 *
361 * @param[in] point 3D point relative to the camera's coordinate system.
362 * @return 3D point in normalized device coordinates ([-1, 1] range), relative to the
363 * camera's viewport. Z value range depends on active render API.
364 */
365 Vector3 projectPoint(const Vector3& point) const;
366
367 /** Un-projects a point in normalized device space to view space.
368 *
369 * @param[in] point 3D point in normalized device coordinates ([-1, 1] range), relative to the
370 * camera's viewport. Z value range depends on active render API.
371 * @return 3D point relative to the camera's coordinate system.
372 */
373 Vector3 unprojectPoint(const Vector3& point) const;
374
375 static const float INFINITE_FAR_PLANE_ADJUST; /**< Small constant used to reduce far plane projection to avoid inaccuracies. */
376
377 protected:
378 CameraBase();
379
380 /** Calculate projection parameters that are used when constructing the projection matrix. */
381 virtual void calcProjectionParameters(float& left, float& right, float& bottom, float& top) const;
382
383 /** Recalculate frustum if dirty. */
384 virtual void updateFrustum() const;
385
386 /** Recalculate frustum planes if dirty. */
387 virtual void updateFrustumPlanes() const;
388
389 /**
390 * Update view matrix from parent position/orientation.
391 *
392 * @note Does nothing when custom view matrix is set.
393 */
394 virtual void updateView() const;
395
396 /** Checks if the frustum requires updating. */
397 virtual bool isFrustumOutOfDate() const;
398
399 /** Notify camera that the frustum requires to be updated. */
400 virtual void invalidateFrustum() const;
401
402 /** Returns a rectangle that defines the viewport position and size, in pixels. */
403 virtual Rect2I getViewportRect() const = 0;
404
405 protected:
406 UINT64 mLayers = 0xFFFFFFFFFFFFFFFF; /**< Bitfield that can be used for filtering what objects the camera sees. */
407
408 ProjectionType mProjType = PT_PERSPECTIVE; /**< Type of camera projection. */
409 Radian mHorzFOV = Degree(90.0f); /**< Horizontal field of view represents how wide is the camera angle. */
410 float mFarDist = 500.0f; /**< Clip any objects further than this. Larger value decreases depth precision at smaller depths. */
411 float mNearDist = 0.05f; /**< Clip any objects close than this. Smaller value decreases depth precision at larger depths. */
412 float mAspect = 1.33333333333333f; /**< Width/height viewport ratio. */
413 float mOrthoHeight = 5; /**< Height in world units used for orthographic cameras. */
414 INT32 mPriority = 0; /**< Determines in what order will the camera be rendered. Higher priority means the camera will be rendered sooner. */
415 bool mMain = false; /**< Determines does this camera render to the main render surface. */
416
417 bool mCustomViewMatrix = false; /**< Is custom view matrix set. */
418 bool mCustomProjMatrix = false; /**< Is custom projection matrix set. */
419 UINT8 mMSAA = 1; /**< Number of samples to render the scene with. */
420
421 SPtr<RenderSettings> mRenderSettings; /**< Settings used to control rendering for this camera. */
422
423 bool mFrustumExtentsManuallySet = false; /**< Are frustum extents manually set. */
424
425 mutable Matrix4 mProjMatrixRS = BsZero; /**< Cached render-system specific projection matrix. */
426 mutable Matrix4 mProjMatrix = BsZero; /**< Cached projection matrix that determines how are 3D points projected to a 2D viewport. */
427 mutable Matrix4 mViewMatrix = BsZero; /**< Cached view matrix that determines camera position/orientation. */
428 mutable Matrix4 mProjMatrixRSInv = BsZero;
429 mutable Matrix4 mProjMatrixInv = BsZero;
430 mutable Matrix4 mViewMatrixInv = BsZero;
431
432 mutable ConvexVolume mFrustum; /**< Main clipping planes describing cameras visible area. */
433 mutable bool mRecalcFrustum : 1; /**< Should frustum be recalculated. */
434 mutable bool mRecalcFrustumPlanes : 1; /**< Should frustum planes be recalculated. */
435 mutable bool mRecalcView : 1; /**< Should view matrix be recalculated. */
436 mutable float mLeft, mRight, mTop, mBottom; /**< Frustum extents. */
437 mutable AABox mBoundingBox; /**< Frustum bounding box. */
438 };
439
440 /** Templated common base class for both sim and core thread implementations of Camera. */
441 template<bool Core>
442 class TCamera : public CameraBase
443 {
444 using ViewportType = CoreVariantType<Viewport, Core>;
445
446 public:
447 virtual ~TCamera() = default;
448
449 /** Returns the viewport used by the camera. */
450 SPtr<ViewportType> getViewport() const { return mViewport; }
451
452 /** Enumerates all the fields in the type and executes the specified processor action for each field. */
453 template<class P>
454 void rttiEnumFields(P p);
455
456 protected:
457 /** Viewport that describes a 2D rendering surface. */
458 SPtr<ViewportType> mViewport;
459 };
460
461 /** @} */
462
463 /** @addtogroup Renderer-Internal
464 * @{
465 */
466
467 /**
468 * Camera determines how is world geometry projected onto a 2D surface. You may position and orient it in space, set
469 * options like aspect ratio and field or view and it outputs view and projection matrices required for rendering.
470 */
471 class BS_CORE_EXPORT Camera : public IReflectable, public CoreObject, public TCamera<false>
472 {
473 public:
474 /**
475 * Determines whether this is the main application camera. Main camera controls the final render surface that is
476 * displayed to the user.
477 */
478 void setMain(bool main);
479
480 /** @copydoc setMain() */
481 bool isMain() const { return mMain; }
482
483 /** Retrieves an implementation of a camera handler usable only from the core thread. */
484 SPtr<ct::Camera> getCore() const;
485
486 /** Creates a new camera that renders to the specified portion of the provided render target. */
487 static SPtr<Camera> create();
488
489 /**
490 * @name Internal
491 * @{
492 */
493
494 /** @copydoc CoreObject::initialize */
495 void initialize() override;
496
497 /** @copydoc CoreObject::destroy */
498 void destroy() override;
499
500 /** @} */
501 protected:
502 /** @copydoc CameraBase */
503 Rect2I getViewportRect() const override;
504
505 /** @copydoc CoreObject::createCore */
506 SPtr<ct::CoreObject> createCore() const override;
507
508 /** @copydoc CameraBase::_markCoreDirty */
509 void _markCoreDirty(ActorDirtyFlag flag = ActorDirtyFlag::Everything) override;
510
511 /** @copydoc CoreObject::syncToCore */
512 CoreSyncData syncToCore(FrameAlloc* allocator) override;
513
514 /** @copydoc CoreObject::getCoreDependencies */
515 void getCoreDependencies(Vector<CoreObject*>& dependencies) override;
516
517 /** Creates a new camera without initializing it. */
518 static SPtr<Camera> createEmpty();
519
520 /************************************************************************/
521 /* RTTI */
522 /************************************************************************/
523 public:
524 friend class CameraRTTI;
525 static RTTITypeBase* getRTTIStatic();
526 RTTITypeBase* getRTTI() const override;
527 };
528
529 namespace ct
530 {
531 /** @copydoc bs::Camera */
532 class BS_CORE_EXPORT Camera : public CoreObject, public TCamera<true>
533 {
534 public:
535 ~Camera();
536
537 /** @copydoc bs::Camera::setMain() */
538 bool isMain() const { return mMain; }
539
540 /** Sets an ID that can be used for uniquely identifying this object by the renderer. */
541 void setRendererId(UINT32 id) { mRendererId = id; }
542
543 /** Retrieves an ID that can be used for uniquely identifying this object by the renderer. */
544 UINT32 getRendererId() const { return mRendererId; }
545
546 protected:
547 friend class bs::Camera;
548
549 Camera(SPtr<RenderTarget> target = nullptr,
550 float left = 0.0f, float top = 0.0f, float width = 1.0f, float height = 1.0f);
551
552 Camera(const SPtr<Viewport>& viewport);
553
554 /** @copydoc CoreObject::initialize */
555 void initialize() override;
556
557 /** @copydoc CameraBase */
558 Rect2I getViewportRect() const override;
559
560 /** @copydoc CoreObject::syncToCore */
561 void syncToCore(const CoreSyncData& data) override;
562
563 UINT32 mRendererId;
564 };
565 }
566
567 /** @} */
568}
569