Files
Vulkan-Samples/framework/camera_core.cpp
T
2025-09-04 10:54:47 +08:00

204 lines
5.0 KiB
C++

/* Copyright (c) 2019-2024, Sascha Willems
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "camera.h"
namespace vkb
{
void Camera::update_view_matrix()
{
glm::mat4 rotation_matrix = glm::mat4(1.0f);
glm::mat4 transformation_matrix;
rotation_matrix = glm::rotate(rotation_matrix, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
rotation_matrix = glm::rotate(rotation_matrix, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
rotation_matrix = glm::rotate(rotation_matrix, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
transformation_matrix = glm::translate(glm::mat4(1.0f), position);
if (type == CameraType::FirstPerson)
{
matrices.view = rotation_matrix * transformation_matrix;
}
else
{
matrices.view = transformation_matrix * rotation_matrix;
}
updated = true;
}
bool Camera::moving()
{
return keys.left || keys.right || keys.up || keys.down;
}
float Camera::get_near_clip()
{
return znear;
}
float Camera::get_far_clip()
{
return zfar;
}
void Camera::set_perspective(float fov, float aspect, float znear, float zfar)
{
this->fov = fov;
this->znear = znear;
this->zfar = zfar;
matrices.perspective = glm::perspective(glm::radians(fov), aspect, znear, zfar);
updated = true;
}
void Camera::update_aspect_ratio(float aspect)
{
matrices.perspective = glm::perspective(glm::radians(fov), aspect, znear, zfar);
updated = true;
}
void Camera::set_position(const glm::vec3 &position)
{
this->position = position;
update_view_matrix();
}
void Camera::set_rotation(const glm::vec3 &rotation)
{
this->rotation = rotation;
update_view_matrix();
}
void Camera::rotate(const glm::vec3 &delta)
{
this->rotation += delta;
update_view_matrix();
}
void Camera::set_translation(const glm::vec3 &translation)
{
this->position = translation;
update_view_matrix();
}
void Camera::translate(const glm::vec3 &delta)
{
this->position += delta;
update_view_matrix();
}
void Camera::update(float deltaTime)
{
updated = false;
if (type == CameraType::FirstPerson)
{
if (moving())
{
glm::vec3 front;
front.x = -cos(glm::radians(rotation.x)) * sin(glm::radians(rotation.y));
front.y = sin(glm::radians(rotation.x));
front.z = cos(glm::radians(rotation.x)) * cos(glm::radians(rotation.y));
front = glm::normalize(front);
float move_speed = deltaTime * translation_speed;
if (keys.up)
{
position += front * move_speed;
}
if (keys.down)
{
position -= front * move_speed;
}
if (keys.left)
{
position -= glm::normalize(glm::cross(front, glm::vec3(0.0f, 1.0f, 0.0f))) * move_speed;
}
if (keys.right)
{
position += glm::normalize(glm::cross(front, glm::vec3(0.0f, 1.0f, 0.0f))) * move_speed;
}
update_view_matrix();
}
}
}
bool Camera::update_gamepad(glm::vec2 axis_left, glm::vec2 axis_right, float delta_time)
{
bool changed = false;
if (type == CameraType::FirstPerson)
{
// Use the common console thumbstick layout
// Left = view, right = move
const float dead_zone = 0.0015f;
const float range = 1.0f - dead_zone;
glm::vec3 front;
front.x = -cos(glm::radians(rotation.x)) * sin(glm::radians(rotation.y));
front.y = sin(glm::radians(rotation.x));
front.z = cos(glm::radians(rotation.x)) * cos(glm::radians(rotation.y));
front = glm::normalize(front);
float move_speed = delta_time * translation_speed * 2.0f;
float new_rotation_speed = delta_time * rotation_speed * 50.0f;
// Move
if (fabsf(axis_left.y) > dead_zone)
{
float pos = (fabsf(axis_left.y) - dead_zone) / range;
position -= front * pos * ((axis_left.y < 0.0f) ? -1.0f : 1.0f) * move_speed;
changed = true;
}
if (fabsf(axis_left.x) > dead_zone)
{
float pos = (fabsf(axis_left.x) - dead_zone) / range;
position += glm::normalize(glm::cross(front, glm::vec3(0.0f, 1.0f, 0.0f))) * pos * ((axis_left.x < 0.0f) ? -1.0f : 1.0f) * move_speed;
changed = true;
}
// Rotate
if (fabsf(axis_right.x) > dead_zone)
{
float pos = (fabsf(axis_right.x) - dead_zone) / range;
rotation.y += pos * ((axis_right.x < 0.0f) ? -1.0f : 1.0f) * new_rotation_speed;
changed = true;
}
if (fabsf(axis_right.y) > dead_zone)
{
float pos = (fabsf(axis_right.y) - dead_zone) / range;
rotation.x -= pos * ((axis_right.y < 0.0f) ? -1.0f : 1.0f) * new_rotation_speed;
changed = true;
}
}
else
{
// todo: move code from example base class for look-at
}
if (changed)
{
update_view_matrix();
}
return changed;
}
} // namespace vkb