#include "Camera.hpp" #include #include #include namespace scene { Camera::Camera () : mPosition( 0.0f, 0.0f, 3.0f ), mFront( 0.0f, 0.0f, -1.0f ), mWorldUp( 0.0f, 1.0f, 0.0f ), mYaw( -90.0f ), mPitch( 0.0f ), mMovementSpeed( 3.0f ), mMouseSensitivity( 0.1f ), mFov( 60.0f ), mVelocity( 0.0f, 0.0f, 0.0f ), mFlying( true ), mGrounded( false ), mSpeedMultiplier( 1.0f ) { updateCameraVectors(); } Camera::Camera ( const glm::vec3& position, const glm::vec3& up, float yaw, float pitch ) : mPosition( position ), mWorldUp( up ), mYaw( yaw ), mPitch( pitch ), mMovementSpeed( 3.0f ), mMouseSensitivity( 0.1f ), mFov( 60.0f ), mVelocity( 0.0f, 0.0f, 0.0f ), mFlying( true ), mGrounded( false ), mSpeedMultiplier( 1.0f ) { mFront = glm::vec3( 0.0f, 0.0f, -1.0f ); updateCameraVectors(); } glm::mat4 Camera::getViewMatrix () const { return glm::lookAt( mPosition, mPosition + mFront, mUp ); } glm::mat4 Camera::getProjectionMatrix ( float aspect ) const { return glm::perspective( glm::radians( mFov ), aspect, 0.1f, 100.0f ); } void Camera::processKeyboard ( Movement dir, float deltaTime ) { float velocity = mMovementSpeed * mSpeedMultiplier * deltaTime; glm::vec3 moveForward = mFront; glm::vec3 moveRight = mRight; if( !mFlying ) { moveForward.y = 0.0f; if( glm::length( moveForward ) < 1e-6f ) moveForward = glm::vec3( 0.0f, 0.0f, -1.0f ); moveForward = glm::normalize( moveForward ); moveRight = glm::normalize( glm::cross( moveForward, mWorldUp ) ); } if( dir == Movement::Forward ) mPosition += moveForward * velocity; if( dir == Movement::Backward ) mPosition -= moveForward * velocity; if( dir == Movement::Left ) mPosition -= moveRight * velocity; if( dir == Movement::Right ) mPosition += moveRight * velocity; if( dir == Movement::Up && mFlying ) mPosition += mWorldUp * velocity; if( dir == Movement::Down && mFlying ) mPosition -= mWorldUp * velocity; } void Camera::toggleFly () { mFlying = !mFlying; if( mFlying ) { mVelocity.y = 0.0f; } } void Camera::setSpeedMultiplier ( float m ) { mSpeedMultiplier = m; } static bool aabbOverlap ( const glm::vec3& amin, const glm::vec3& amax, const glm::vec3& bmin, const glm::vec3& bmax ) { return ( amin.x <= bmax.x && amax.x >= bmin.x ) && ( amin.y <= bmax.y && amax.y >= bmin.y ) && ( amin.z <= bmax.z && amax.z >= bmin.z ); } void Camera::updatePhysics ( float deltaTime, const std::vector>& worldAABBs, float floorY ) { const glm::vec3 halfExtents( 0.3f, 0.9f, 0.3f ); if( mFlying ) { mGrounded = false; return; } if( !mFlying ) { const float gravity = -9.8f; mVelocity.y += gravity * deltaTime; if( mVelocity.y < -50.0f ) mVelocity.y = -50.0f; } glm::vec3 newPos = mPosition + mVelocity * deltaTime; float camBottom = newPos.y - halfExtents.y; if( camBottom < floorY ) { newPos.y = floorY + halfExtents.y; mVelocity.y = 0.0f; mGrounded = true; } else { mGrounded = false; } for( const auto& box : worldAABBs ) { glm::vec3 bmin = box.first; glm::vec3 bmax = box.second; glm::vec3 camMin = newPos - halfExtents; glm::vec3 camMax = newPos + halfExtents; if( !aabbOverlap( camMin, camMax, bmin, bmax ) ) continue; float ox = std::min( camMax.x, bmax.x ) - std::max( camMin.x, bmin.x ); float oy = std::min( camMax.y, bmax.y ) - std::max( camMin.y, bmin.y ); float oz = std::min( camMax.z, bmax.z ) - std::max( camMin.z, bmin.z ); if( ox <= oy && ox <= oz ) { float boxCenterX = ( bmin.x + bmax.x ) * 0.5f; if( newPos.x < boxCenterX ) newPos.x -= ox; else newPos.x += ox; } else if( oy <= ox && oy <= oz ) { float boxCenterY = ( bmin.y + bmax.y ) * 0.5f; if( newPos.y < boxCenterY ) { newPos.y -= oy; mVelocity.y = 0.0f; } else { newPos.y += oy; mVelocity.y = 0.0f; mGrounded = true; } } else { float boxCenterZ = ( bmin.z + bmax.z ) * 0.5f; if( newPos.z < boxCenterZ ) newPos.z -= oz; else newPos.z += oz; } } mPosition = newPos; } void Camera::jump () { if( mFlying ) return; if( mGrounded ) { const float jumpImpulse = 5.0f; mVelocity.y = jumpImpulse; mGrounded = false; } } bool Camera::isFlying () const { return mFlying; } bool Camera::isGrounded () const { return mGrounded; } float Camera::getSpeedMultiplier () const { return mSpeedMultiplier; } void Camera::processMouseMovement ( float xoffset, float yoffset, bool constrainPitch ) { xoffset *= mMouseSensitivity; yoffset *= mMouseSensitivity; mYaw += xoffset; mPitch += yoffset; if( constrainPitch ) { if( mPitch > 89.0f ) mPitch = 89.0f; if( mPitch < -89.0f ) mPitch = -89.0f; } updateCameraVectors(); } void Camera::processMouseScroll ( float yoffset ) { mFov -= yoffset; if( mFov < 1.0f ) mFov = 1.0f; if( mFov > 90.0f ) mFov = 90.0f; } void Camera::updateCameraVectors () { glm::vec3 front; front.x = cos( glm::radians( mYaw ) ) * cos( glm::radians( mPitch ) ); front.y = sin( glm::radians( mPitch ) ); front.z = sin( glm::radians( mYaw ) ) * cos( glm::radians( mPitch ) ); mFront = glm::normalize( front ); mRight = glm::normalize( glm::cross( mFront, mWorldUp ) ); mUp = glm::normalize( glm::cross( mRight, mFront ) ); } } // namespace scene