// // Copyright Contributors to the MaterialX Project // SPDX-License-Identifier: Apache-2.0 // #ifndef MATERIALX_CAMERA_H #define MATERIALX_CAMERA_H #include MATERIALX_NAMESPACE_BEGIN /// Shared pointer to a Camera using CameraPtr = std::shared_ptr; /// @class Camera /// A simple camera class, supporting transform matrices and arcball /// functionality for object-viewing applications. class MX_RENDER_API Camera { public: Camera() : _worldMatrix(Matrix44::IDENTITY), _viewMatrix(Matrix44::IDENTITY), _projectionMatrix(Matrix44::IDENTITY), _arcballActive(false), _arcballQuat(Quaternion::IDENTITY), _arcballDelta(Quaternion::IDENTITY), _arcballSpeed(2.0f) { } ~Camera() { } /// Create a new camera. static CameraPtr create() { return std::make_shared(); } /// @name Transform Matrices /// @{ /// Set the world matrix. void setWorldMatrix(const Matrix44& mat) { _worldMatrix = mat; } /// Return the world matrix. const Matrix44& getWorldMatrix() const { return _worldMatrix; } /// Set the view matrix. void setViewMatrix(const Matrix44& mat) { _viewMatrix = mat; } /// Return the view matrix. const Matrix44& getViewMatrix() const { return _viewMatrix; } /// Set the projection matrix. void setProjectionMatrix(const Matrix44& mat) { _projectionMatrix = mat; } /// Return the projection matrix. const Matrix44& getProjectionMatrix() const { return _projectionMatrix; } /// Compute our full model-view-projection matrix. Matrix44 getWorldViewProjMatrix() const { return _worldMatrix * _viewMatrix * _projectionMatrix; } /// Derive viewer position from the view matrix. Vector3 getViewPosition() const { Matrix44 invView = _viewMatrix.getInverse(); return Vector3(invView[3][0], invView[3][1], invView[3][2]); } /// Derive viewer direction from the view matrix. Vector3 getViewDirection() const { Matrix44 invView = _viewMatrix.getInverse(); return Vector3(invView[2][0], invView[2][1], invView[2][2]); } /// @} /// @name Viewport /// @{ /// Set the size of the viewport window. void setViewportSize(const Vector2& size) { _viewportSize = size; } /// Return the size of the viewport window. const Vector2& getViewportSize() const { return _viewportSize; } /// Project a position from object to viewport space. Vector3 projectToViewport(Vector3 v) { v = transformPointPerspective(getWorldViewProjMatrix(), v); v = v * 0.5f + Vector3(0.5f); v[0] *= _viewportSize[0]; v[1] *= _viewportSize[1]; return v; } /// Unproject a position from viewport to object space. Vector3 unprojectFromViewport(Vector3 v) { v[0] /= _viewportSize[0]; v[1] /= _viewportSize[1]; v = v * 2.0f - Vector3(1.0f); v = transformPointPerspective(getWorldViewProjMatrix().getInverse(), v); return v; } /// @} /// @name Arcball /// @{ /// Indicates a button state change, with pos being the instantaneous location of the mouse. void arcballButtonEvent(const Vector2& pos, bool pressed); /// Apply mouse motion to the arcball state. bool applyArcballMotion(const Vector2& pos); /// Return the arcball matrix. Matrix44 arcballMatrix() const { return (_arcballDelta * _arcballQuat).toMatrix(); } /// @} /// @name Utilities /// @{ /// Create a view matrix given an eye position, a target position and an up vector. static Matrix44 createViewMatrix(const Vector3& eye, const Vector3& target, const Vector3& up); /// Create a perspective projection matrix given a set of clip planes with [-1,1] projected Z. static Matrix44 createPerspectiveMatrix(float left, float right, float bottom, float top, float nearP, float farP); /// Create an orthographic projection matrix given a set of clip planes with [-1,1] projected Z. static Matrix44 createOrthographicMatrix(float left, float right, float bottom, float top, float nearP, float farP); /// Create a perspective projection matrix given a set of clip planes with [0,1] projected Z. static Matrix44 createPerspectiveMatrixZP(float left, float right, float bottom, float top, float nearP, float farP); /// Create an orthographic projection matrix given a set of clip planes with [0,1] projected Z. static Matrix44 createOrthographicMatrixZP(float left, float right, float bottom, float top, float nearP, float farP); /// Apply a perspective transform to the given 3D point, performing a /// homogeneous divide on the transformed result. static Vector3 transformPointPerspective(const Matrix44& m, const Vector3& v) { Vector4 res = m.multiply(Vector4(v[0], v[1], v[2], 1.0f)); return Vector3(res[0], res[1], res[2]) / res[3]; } /// @} protected: // Transform matrices Matrix44 _worldMatrix; Matrix44 _viewMatrix; Matrix44 _projectionMatrix; // Viewport size Vector2 _viewportSize; // Arcball properties bool _arcballActive; Vector2 _arcballLastPos; Quaternion _arcballQuat; Quaternion _arcballDelta; float _arcballSpeed; }; MATERIALX_NAMESPACE_END #endif