diff --git a/core/2d/CCCamera.cpp b/core/2d/CCCamera.cpp index a3ca7e792a..ba322c453b 100644 --- a/core/2d/CCCamera.cpp +++ b/core/2d/CCCamera.cpp @@ -94,6 +94,12 @@ const Camera* Camera::getVisitingCamera() // end static methods Camera::Camera() + : _eyeZdistance(1) + , _zoomFactor(1) + , _nearPlane(-1024) + , _farPlane(1024) + , _zoomFactorFarPlane(1024) + , _positionCenter({0, 0}) { // minggo comment // _frustum.setClipZ(true); @@ -137,6 +143,7 @@ void Camera::lookAt(const Vec3& lookAtPos, const Vec3& up) Vec3::cross(zaxis, xaxis, &yaxis); yaxis.normalize(); Mat4 rotation; + rotation.m[0] = xaxis.x; rotation.m[1] = xaxis.y; rotation.m[2] = xaxis.z; @@ -146,6 +153,7 @@ void Camera::lookAt(const Vec3& lookAtPos, const Vec3& up) rotation.m[5] = yaxis.y; rotation.m[6] = yaxis.z; rotation.m[7] = 0; + rotation.m[8] = zaxis.x; rotation.m[9] = zaxis.y; rotation.m[10] = zaxis.z; @@ -177,6 +185,8 @@ void Camera::setAdditionalProjection(const Mat4& mat) bool Camera::initDefault() { + _projectionType = Director::getInstance()->getProjection(); + auto size = _director->getWinSize(); // create default camera auto projection = _director->getProjection(); @@ -185,7 +195,7 @@ bool Camera::initDefault() case Director::Projection::_2D: { initOrthographic(size.width, size.height, -1024, 1024); - setPosition3D(Vec3(0.0f, 0.0f, 0.0f)); + setPosition3D(Vec3(0.f, 0.f, 0.f)); setRotation3D(Vec3(0.f, 0.f, 0.f)); break; } @@ -195,6 +205,7 @@ bool Camera::initDefault() initPerspective(60, (float)size.width / size.height, 10, zeye + size.height / 2.0f); Vec3 eye(size.width / 2, size.height / 2.0f, zeye), center(size.width / 2, size.height / 2, 0.0f), up(0.0f, 1.0f, 0.0f); + _eyeZdistance = eye.z; setPosition3D(eye); lookAt(center, up); break; @@ -203,15 +214,19 @@ bool Camera::initDefault() CCLOG("unrecognized projection"); break; } + if (_zoomFactor != 1.0F) + applyZoom(); return true; } bool Camera::initPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane) { - _fieldOfView = fieldOfView; - _aspectRatio = aspectRatio; - _nearPlane = nearPlane; - _farPlane = farPlane; + _fieldOfView = fieldOfView; + _aspectRatio = aspectRatio; + _nearPlane = nearPlane; + _farPlane = farPlane; + if (_zoomFactorFarPlane == 1024) + _zoomFactorFarPlane = farPlane; Mat4::createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane, &_projection); _viewProjectionDirty = true; _frustumDirty = true; @@ -354,6 +369,82 @@ void Camera::setDepth(int8_t depth) } } +void Camera::setZoom(float factor) +{ + // Stretch the far plane further the more we zoom out. + if (_projectionType == Director::Projection::_3D && _zoomFactorFarPlane * factor > _farPlane) + { + _farPlane = _zoomFactorFarPlane * factor; + applyCustomProperties(); + } + + _zoomFactor = factor; + applyZoom(); + if (_projectionType == Director::Projection::_2D) + setPositionCenter(_positionCenter); +} + +void Camera::setPositionCenter(const Vec2& position) +{ + setPositionCenter(position.x, position.y); +} + +void Camera::setPositionCenter(float x, float y) +{ + Vec2 pos = {x, y}; + _positionCenter = pos; + auto v = Director::getInstance()->getVisibleSize(); + setPosition(pos.x + v.width / 2 * (1.0F - _zoomFactor), pos.y + v.height / 2 * (1.0F - _zoomFactor)); +} + +void Camera::applyZoom() +{ + switch (_projectionType) + { + case cocos2d::Director::Projection::_2D: + { + this->setScale(_zoomFactor); + break; + } + case cocos2d::Director::Projection::_3D: + { + this->setPositionZ(_eyeZdistance * _zoomFactor); + break; + } + } +} + +void Camera::applyCustomProperties() +{ + _projectionType = Director::getInstance()->getProjection(); + + auto& size = _director->getWinSize(); + // create default camera + switch (_projectionType) + { + case Director::Projection::_2D: + { + initOrthographic(size.width, size.height, _nearPlane, _farPlane); + setPosition3D(Vec3(0.f, 0.f, 0.f)); + setRotation3D(Vec3(0.f, 0.f, 0.f)); + break; + } + case Director::Projection::_3D: + { + float zeye = _director->getZEye(); + initPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane); + Vec3 eye(size.width / 2, size.height / 2.0f, zeye), center(size.width / 2, size.height / 2, 0.0f), + up(0.0f, 1.0f, 0.0f); + _eyeZdistance = eye.z; + setPosition3D(eye); + lookAt(center, up); + break; + } + } + if (_zoomFactor != 1.0F) + applyZoom(); +} + void Camera::onEnter() { if (_scene == nullptr) @@ -431,6 +522,30 @@ int Camera::getRenderOrder() const return result; } +void Camera::setAspectRatio(float ratio) +{ + _aspectRatio = ratio; + applyCustomProperties(); +} + +void Camera::setFOV(float fieldOfView) +{ + _fieldOfView = fieldOfView; + applyCustomProperties(); +} + +void Camera::setFarPlane(float farPlane) +{ + _farPlane = farPlane; + applyCustomProperties(); +} + +void Camera::setNearPlane(float nearPlane) +{ + _nearPlane = nearPlane; + applyCustomProperties(); +} + void Camera::visit(Renderer* renderer, const Mat4& parentTransform, uint32_t parentFlags) { _viewProjectionUpdated = _transformUpdated; diff --git a/core/2d/CCCamera.h b/core/2d/CCCamera.h index da5108bd41..d457e02888 100644 --- a/core/2d/CCCamera.h +++ b/core/2d/CCCamera.h @@ -234,22 +234,94 @@ public: int getRenderOrder() const; /** - * Get the frustum's far plane. + * Gets the aspect ratio of the camera if the projection mode is 3D. + */ + float getAspectRatio() const { return _fieldOfView; } + + /** + * Sets the aspect ratio of the camera if the projection mode is 3D. + */ + void setAspectRatio(float ratio); + + /** + * Gets the field of view of the camera if the projection mode is 3D. + */ + float getFOV() const { return _fieldOfView; } + + /** + * Sets the field of view of the camera if the projection mode is 3D. + */ + void setFOV(float fov); + + /** + * Gets the frustum's far plane. */ float getFarPlane() const { return _farPlane; } /** - * Get the frustum's near plane. + * Sets the frustum's far plane. + */ + void setFarPlane(float farPlane); + + /** + * Gets the frustum's near plane. */ float getNearPlane() const { return _nearPlane; } + /** + * Gets the frustum's near plane. + */ + void setNearPlane(float nearPlane); + + /** + * Gets the zoom multiplier of the camera. + */ + float getZoom() const { return _zoomFactor; } + + /** + * Sets the zoom multiplier of the camera. + * This is designed to be used with 2D views only. + * + * For 2D projection mode the zoom will be at the bottom left of the viewport, If you don't want this behaviour and + * want it to be around the center then you need to use the functions 'setPositionCenter()' and 'getPositionCenter()' + * + * @param factor The zoom factor of the camera. + */ + void setZoom(float factor); + + /** + * Gets the position of the camera before any zoom transformations. + * Should only be used If you're zooming in and out while 2D projection mode is set in the director. + */ + const Vec2& getPositionCenter() { return _positionCenter; } + + /** + * Sets the position of the camera with respect to the zoom factor. + * Should only be used If you're zooming in and out while 2D projection mode is set in the director. + */ + void setPositionCenter(const Vec2& position); + + /** + * Sets the position of the camera with respect to the zoom factor. + * Should only be used If you're zooming in and out while 2D projection mode is set in the director. + */ + void setPositionCenter(float x, float y); + + /** + Apply the zoom factor. + */ + void applyZoom(); + + void applyCustomProperties(); + // override virtual void onEnter() override; virtual void onExit() override; /** - Before rendering scene with this camera, the background need to be cleared. It clears the depth buffer with max - depth by default. Use setBackgroundBrush to modify the default behavior + Before rendering the scene with this camera, the background needs to be cleared. + It will clear the depth buffer with max depth by default. + Use setBackgroundBrush to modify this default behavior. */ void clearBackground(); /** @@ -258,8 +330,8 @@ public: void apply(); /** - * Whether or not the viewprojection matrix was updated since the last frame. - * @return True if the viewprojection matrix was updated since the last frame. + * Whether or not the viewprojection matrix was updated last frame. + * @return True if the viewprojection matrix was updated last frame. */ bool isViewProjectionUpdated() const { return _viewProjectionUpdated; } @@ -282,7 +354,7 @@ public: ~Camera(); /** - * Set the scene,this method shall not be invoke manually + * Set the owner scene of the camera, this method shall not be invoked manually */ void setScene(Scene* scene); @@ -300,7 +372,7 @@ protected: static Camera* _visitingCamera; static Viewport _defaultViewport; - Scene* _scene = nullptr; // Scene camera belongs to + Scene* _scene = nullptr; // Scene that owns this camera. Mat4 _projection; mutable Mat4 _view; mutable Mat4 _viewInv; @@ -320,6 +392,12 @@ protected: mutable bool _frustumDirty = true; int8_t _depth = -1; // camera depth, the depth of camera with CameraFlag::DEFAULT flag is 0 by default, a camera // with larger depth is drawn on top of camera with smaller depth + Director::Projection _projectionType; + + float _eyeZdistance; // Z eye projection distance for 2D in 3D projection. + float _zoomFactor; // The zoom factor of the camera. 3D = (cameraZDistance * _zoomFactor), 2D = (cameraScale * _zoomFactor) + float _zoomFactorFarPlane; + Vec2 _positionCenter; CameraBackgroundBrush* _clearBrush = nullptr; // brush used to clear the back ground };