First implementation of new camera systems
This commit is contained in:
@@ -13,6 +13,7 @@ add_library(fever_engine
|
||||
mesh.cpp
|
||||
gltf_loader.cpp
|
||||
material.cpp
|
||||
camera.cpp
|
||||
)
|
||||
|
||||
target_compile_features(fever_engine PUBLIC cxx_std_20)
|
||||
|
||||
@@ -28,11 +28,6 @@ void Camera::translate(glm::vec3 translateVector)
|
||||
m_viewMatrix = glm::translate(m_viewMatrix, translateVector * -1.F);
|
||||
}
|
||||
|
||||
void Camera::lookAtTarget(glm::vec3 target)
|
||||
{
|
||||
m_viewMatrix = glm::lookAt(m_position, target, UP_VEC);
|
||||
}
|
||||
|
||||
void Camera::lookForward()
|
||||
{
|
||||
m_viewMatrix = glm::lookAt(m_position, m_position + m_front_vec, UP_VEC);
|
||||
@@ -98,21 +93,6 @@ void Camera::updateDirectionFromMouseInput(MouseCursorInput const &mouse_cursor_
|
||||
m_front_vec = glm::normalize(direction);
|
||||
}
|
||||
|
||||
void Camera::setPosition(glm::vec3 position)
|
||||
{
|
||||
this->m_position = position;
|
||||
}
|
||||
|
||||
auto Camera::getView() const -> glm::mat4
|
||||
{
|
||||
return m_viewMatrix;
|
||||
}
|
||||
|
||||
auto Camera::getProj() const -> glm::mat4
|
||||
{
|
||||
return m_projectionMatrix;
|
||||
}
|
||||
|
||||
auto Camera::getViewProj() const -> glm::mat4
|
||||
{
|
||||
return m_viewProjectionMatrix;
|
||||
@@ -123,7 +103,3 @@ auto Camera::getPosition() const -> glm::vec3
|
||||
return m_position;
|
||||
}
|
||||
|
||||
auto Camera::getDirection() const -> glm::vec3
|
||||
{
|
||||
return m_front_vec;
|
||||
}
|
||||
|
||||
@@ -15,17 +15,10 @@ public:
|
||||
void updateDirectionFromMouseInput(MouseCursorInput const &mouse_cursor_input);
|
||||
|
||||
void translate(glm::vec3 translateVector);
|
||||
|
||||
void lookAtTarget(glm::vec3 target);
|
||||
void lookForward();
|
||||
|
||||
[[nodiscard]] auto getView() const -> glm::mat4;
|
||||
[[nodiscard]] auto getProj() const -> glm::mat4;
|
||||
[[nodiscard]] auto getViewProj() const -> glm::mat4;
|
||||
[[nodiscard]] auto getPosition() const -> glm::vec3;
|
||||
[[nodiscard]] auto getDirection() const -> glm::vec3;
|
||||
|
||||
void setPosition(glm::vec3 position);
|
||||
|
||||
private:
|
||||
glm::mat4 m_viewMatrix;
|
||||
|
||||
@@ -36,7 +36,7 @@ Controller::Controller()
|
||||
|
||||
// m_camera = std::make_shared<Camera>(perspective.yfov, perspective.aspectRatio);
|
||||
// } else {
|
||||
m_camera = std::make_shared<Camera>(90., m_gameWindow->aspectRatio());
|
||||
// m_camera = std::make_shared<Camera>(90., m_gameWindow->aspectRatio());
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ void Controller::run()
|
||||
{
|
||||
updateExposure(postProcessingProgram);
|
||||
|
||||
m_camera->translate(glm::vec3(0., .5, 2.));
|
||||
// m_camera->translate(glm::vec3(0., .5, 2.));
|
||||
|
||||
DirectionalLight directional_light(
|
||||
DirectionalLight::Prototype("", glm::vec3(-0.2, -1.0, -0.3), glm::vec3(1.0f), 5.f),
|
||||
&defaultProgram);
|
||||
@@ -70,17 +71,22 @@ void Controller::run()
|
||||
m_postProcessFrameBuffer.bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
m_camera->lookForward();
|
||||
m_camera->updateVPM();
|
||||
// m_camera->lookForward();
|
||||
// m_camera->updateVPM();
|
||||
|
||||
m_gameWindow->clear_mouse_cursor_input(); // MOVE DOWN AGAIN!
|
||||
glfwPollEvents();
|
||||
|
||||
auto const &key_input = m_gameWindow->key_input();
|
||||
auto const &mouse_cursor_input = m_gameWindow->mouse_cursor_input();
|
||||
|
||||
static constexpr auto MICROSECONDS_PER_SECOND = 1'000'000;
|
||||
m_scene.update(
|
||||
std::chrono::microseconds(static_cast<unsigned>(m_deltaTime * MICROSECONDS_PER_SECOND)),
|
||||
&defaultProgram,
|
||||
m_camera->getViewProj(),
|
||||
m_camera->getPosition());
|
||||
key_input,mouse_cursor_input, m_gameWindow->aspectRatio());
|
||||
|
||||
m_postProcessFrameBuffer.unbind();
|
||||
Framebuffer::unbind();
|
||||
m_postProcessFrameBuffer.drawOnEntireScreen();
|
||||
|
||||
glfwSwapBuffers(&m_gameWindow->glfw_window());
|
||||
@@ -92,17 +98,17 @@ void Controller::run()
|
||||
}
|
||||
|
||||
// --- Check events, handle input ---
|
||||
m_gameWindow->clear_mouse_cursor_input();
|
||||
glfwPollEvents();
|
||||
// m_gameWindow->clear_mouse_cursor_input();
|
||||
// glfwPollEvents();
|
||||
|
||||
auto const &key_input = m_gameWindow->key_input();
|
||||
auto const &mouse_cursor_input = m_gameWindow->mouse_cursor_input();
|
||||
// auto const &key_input = m_gameWindow->key_input();
|
||||
// auto const &mouse_cursor_input = m_gameWindow->mouse_cursor_input();
|
||||
|
||||
m_camera->updatePositionFromKeyboardInput(key_input, (float)m_deltaTime);
|
||||
// m_camera->updatePositionFromKeyboardInput(key_input, (float)m_deltaTime);
|
||||
|
||||
if (m_gameWindow->cursor_catched()) {
|
||||
m_camera->updateDirectionFromMouseInput(mouse_cursor_input);
|
||||
}
|
||||
// if (m_gameWindow->cursor_catched()) {
|
||||
// m_camera->updateDirectionFromMouseInput(mouse_cursor_input);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +134,7 @@ void Controller::limit_framerate()
|
||||
|
||||
void Controller::update_window_dimensions()
|
||||
{
|
||||
m_camera->updateAspectRatio(m_gameWindow->aspectRatio());
|
||||
// m_camera->updateAspectRatio(m_gameWindow->aspectRatio());
|
||||
// m_gameEventHandler->setFirstMouseInput(1);
|
||||
|
||||
auto dimensions = m_gameWindow->dimensions();
|
||||
|
||||
@@ -28,7 +28,6 @@ private:
|
||||
void update_window_dimensions();
|
||||
|
||||
std::shared_ptr<Window> m_gameWindow;
|
||||
std::shared_ptr<Camera> m_camera;
|
||||
|
||||
ShaderProgram defaultProgram{{"defaultProgram", "data/shaders/basic.vert", "data/shaders/basic.frag"}};
|
||||
ShaderProgram skyboxProgram{{"skyboxProgram", "data/shaders/skybox.vert", "data/shaders/skybox.frag"}};
|
||||
|
||||
171
src/Scene.cpp
171
src/Scene.cpp
@@ -1,11 +1,15 @@
|
||||
#include "Scene.h"
|
||||
#include "ShaderProgram.h"
|
||||
#include "camera.h"
|
||||
#include "mesh.h"
|
||||
#include "name.h"
|
||||
#include "relationship.h"
|
||||
#include "transform.h"
|
||||
#include "util/Log.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace entt::literals;
|
||||
|
||||
// TODO: make scene initialization part of gltf loader as seen in bevy
|
||||
@@ -87,29 +91,40 @@ Scene::Scene()
|
||||
// Remove Material resource as it is no longer needed.
|
||||
m_registry.erase<entt::resource<Material>>(entity);
|
||||
}
|
||||
|
||||
// Spawn the camera
|
||||
auto entity = m_registry.create();
|
||||
m_registry.emplace<Name>(entity, "Camera");
|
||||
m_registry.emplace<Transform>(entity, Transform{.translation = glm::vec3(0.0, 0.5, -2.0)});
|
||||
m_registry.emplace<GlobalTransform>(entity, GlobalTransform{});
|
||||
m_registry.emplace<Camera>(entity,
|
||||
Camera{.projection = Camera::Perspective{.aspect_ratio = 1.6}});
|
||||
}
|
||||
|
||||
void Scene::update(std::chrono::duration<float> delta,
|
||||
ShaderProgram *shaderprogram,
|
||||
glm::mat4 viewProjMatrix,
|
||||
glm::vec3 viewPosition)
|
||||
KeyInput const &key_input,
|
||||
MouseCursorInput const &mouse_cursor_input,
|
||||
float aspect_ratio)
|
||||
{
|
||||
// Update GlobalTransform components
|
||||
// TODO: Only do this when the Transform changed.
|
||||
auto root_transform_view =
|
||||
m_registry.view<Transform const, GlobalTransform>(entt::exclude<Parent>);
|
||||
auto transform_view = m_registry.view<Transform const, GlobalTransform, Parent const>();
|
||||
{
|
||||
// Update GlobalTransform components
|
||||
// TODO: Only do this when the Transform changed.
|
||||
auto root_transform_view =
|
||||
m_registry.view<Transform const, GlobalTransform>(entt::exclude<Parent>);
|
||||
auto transform_view = m_registry.view<Transform const, GlobalTransform, Parent const>();
|
||||
|
||||
for (auto [entity, transform, global_transform] : root_transform_view.each()) {
|
||||
global_transform = transform;
|
||||
for (auto [entity, transform, global_transform] : root_transform_view.each()) {
|
||||
global_transform = transform;
|
||||
|
||||
auto parent_global_transform = global_transform;
|
||||
if (auto *children = m_registry.try_get<Children>(entity)) {
|
||||
for (auto child : children->children) {
|
||||
std::function<void(entt::entity entity, GlobalTransform parent_global_transform)>
|
||||
transform_propagate =
|
||||
[this, &transform_propagate, &transform_view](
|
||||
entt::entity entity, GlobalTransform parent_global_transform) {
|
||||
auto parent_global_transform = global_transform;
|
||||
if (auto *children = m_registry.try_get<Children>(entity)) {
|
||||
for (auto child : children->children) {
|
||||
std::function<void(entt::entity entity,
|
||||
GlobalTransform parent_global_transform)>
|
||||
transform_propagate = [this, &transform_propagate, &transform_view](
|
||||
entt::entity entity,
|
||||
GlobalTransform parent_global_transform) {
|
||||
auto [transform, global_transform, parent] = transform_view.get(entity);
|
||||
global_transform.transform = parent_global_transform.transform *
|
||||
GlobalTransform(transform).transform;
|
||||
@@ -121,30 +136,120 @@ void Scene::update(std::chrono::duration<float> delta,
|
||||
}
|
||||
};
|
||||
|
||||
transform_propagate(child, parent_global_transform);
|
||||
transform_propagate(child, parent_global_transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto mesh_view = m_registry.view<GpuMesh const, GpuMaterial const, GlobalTransform const>();
|
||||
for (auto [entity, mesh, material, transform] : mesh_view.each()) {
|
||||
shaderprogram->bind();
|
||||
{
|
||||
auto mesh_view = m_registry.view<GpuMesh const, GpuMaterial const, GlobalTransform const>();
|
||||
auto camera_view = m_registry.view<Camera const, GlobalTransform const>();
|
||||
auto camera_entity = camera_view.front();
|
||||
auto [camera, camera_transform] = camera_view.get(camera_entity);
|
||||
glm::mat4 view_projection_matrix =
|
||||
camera.projection_matrix() * Camera::view_matrix(camera_transform);
|
||||
|
||||
// Bind textures
|
||||
material.bind(*shaderprogram);
|
||||
for (auto [entity, mesh, material, transform] : mesh_view.each()) {
|
||||
shaderprogram->bind();
|
||||
|
||||
// Bind modelview matrix uniform
|
||||
{
|
||||
glm::mat4 modelViewProj = viewProjMatrix * transform.transform;
|
||||
shaderprogram->setUniform("u_modelViewProjMatrix", modelViewProj);
|
||||
shaderprogram->setUniform("u_modelMatrix", transform.transform);
|
||||
shaderprogram->setUniform("u_viewPosition", viewPosition);
|
||||
// Bind textures
|
||||
material.bind(*shaderprogram);
|
||||
|
||||
// Bind modelview matrix uniform
|
||||
{
|
||||
glm::mat4 modelViewProj = view_projection_matrix * transform.transform;
|
||||
shaderprogram->setUniform("u_modelViewProjMatrix", modelViewProj);
|
||||
shaderprogram->setUniform("u_modelMatrix", transform.transform);
|
||||
shaderprogram->setUniform("u_viewPosition", camera_transform.position());
|
||||
}
|
||||
|
||||
glBindVertexArray(mesh.vao);
|
||||
glDrawElements(GL_TRIANGLES, mesh.indices_count, mesh.indices_type, nullptr);
|
||||
glBindVertexArray(0);
|
||||
|
||||
ShaderProgram::unbind();
|
||||
}
|
||||
}
|
||||
|
||||
// Camera keyboard update
|
||||
{
|
||||
auto camera_view = m_registry.view<Camera const, Transform, GlobalTransform const>();
|
||||
auto camera_entity = camera_view.front();
|
||||
auto [camera, camera_transform, camera_global_transform] = camera_view.get(camera_entity);
|
||||
|
||||
glm::vec3 front_vec = Camera::front_vector(camera_global_transform);
|
||||
glm::vec3 front_vec_without_y = glm::vec3(front_vec.x, 0., front_vec.z);
|
||||
glm::vec3 deltaPos = glm::vec3(0., 0., 0.);
|
||||
// float deltaFactor = SPEED * deltaTime * (m_accellerate ? 5.0 : 1.0);
|
||||
float delta_factor = 0.5 * delta.count();
|
||||
// m_accellerate = false;
|
||||
|
||||
for (auto const &[key, pressed] : key_input) {
|
||||
if (key == GLFW_KEY_W && pressed) {
|
||||
deltaPos += delta_factor * glm::normalize(front_vec_without_y);
|
||||
}
|
||||
if (key == GLFW_KEY_S && pressed) {
|
||||
deltaPos -= delta_factor * glm::normalize(front_vec_without_y);
|
||||
}
|
||||
if (key == GLFW_KEY_A && pressed) {
|
||||
deltaPos -= delta_factor * glm::normalize(glm::cross(front_vec, Camera::UP_VECTOR));
|
||||
}
|
||||
if (key == GLFW_KEY_D && pressed) {
|
||||
deltaPos += delta_factor * glm::normalize(glm::cross(front_vec, Camera::UP_VECTOR));
|
||||
}
|
||||
if (key == GLFW_KEY_SPACE && pressed) {
|
||||
deltaPos += delta_factor * Camera::UP_VECTOR;
|
||||
}
|
||||
if (key == GLFW_KEY_LEFT_SHIFT && pressed) {
|
||||
deltaPos -= delta_factor * Camera::UP_VECTOR;
|
||||
}
|
||||
// if (key == GLFW_KEY_LEFT_ALT && pressed) {
|
||||
// m_accellerate = true;
|
||||
// }
|
||||
}
|
||||
camera_transform.translation += deltaPos;
|
||||
}
|
||||
|
||||
// Camera mouse update
|
||||
{
|
||||
auto camera_view = m_registry.view<Camera, Transform>();
|
||||
auto camera_entity = camera_view.front();
|
||||
auto [camera, camera_transform] = camera_view.get(camera_entity);
|
||||
|
||||
auto [deltaX, deltaY] = mouse_cursor_input;
|
||||
|
||||
if (std::abs(deltaX) < std::numeric_limits<double>::epsilon() &&
|
||||
std::abs(deltaY) < std::numeric_limits<double>::epsilon()) {
|
||||
return;
|
||||
}
|
||||
|
||||
glBindVertexArray(mesh.vao);
|
||||
glDrawElements(GL_TRIANGLES, mesh.indices_count, mesh.indices_type, nullptr);
|
||||
glBindVertexArray(0);
|
||||
auto pitch = static_cast<float>(deltaY);
|
||||
auto yaw = static_cast<float>(deltaX);
|
||||
auto roll = 0.0F;
|
||||
|
||||
ShaderProgram::unbind();
|
||||
// Orthographic projection currently unsupported
|
||||
auto &camera_perspective = std::get<Camera::Perspective>(camera.projection);
|
||||
|
||||
camera_perspective.pitch += glm::radians(pitch);
|
||||
camera_perspective.yaw += glm::radians(yaw);
|
||||
|
||||
static constexpr float PITCH_CLIP = glm::radians(89.);
|
||||
camera_perspective.pitch =
|
||||
std::clamp(static_cast<float>(camera_perspective.pitch), -PITCH_CLIP, PITCH_CLIP);
|
||||
|
||||
camera_transform.orientation =
|
||||
glm::quat(glm::vec3(-camera_perspective.pitch, -camera_perspective.yaw, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
// Camera aspect ratio update
|
||||
{
|
||||
auto camera_view = m_registry.view<Camera>();
|
||||
auto camera_entity = camera_view.front();
|
||||
auto [camera] = camera_view.get(camera_entity);
|
||||
|
||||
// Orthographic projection currently unsupported
|
||||
auto &camera_perspective = std::get<Camera::Perspective>(camera.projection);
|
||||
camera_perspective.aspect_ratio = aspect_ratio;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "gltf_loader.h"
|
||||
#include "material.h"
|
||||
#include "mesh.h"
|
||||
#include "Window.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <entt/entt.hpp>
|
||||
@@ -15,9 +16,7 @@ public:
|
||||
Scene();
|
||||
|
||||
void update(std::chrono::duration<float> delta,
|
||||
ShaderProgram *shaderprogram,
|
||||
glm::mat4 viewProjMatrix,
|
||||
glm::vec3 viewPosition);
|
||||
ShaderProgram *shaderprogram, KeyInput const &key_input,MouseCursorInput const &mouse_cursor_input, float aspect_ratio);
|
||||
|
||||
private:
|
||||
entt::registry m_registry;
|
||||
|
||||
@@ -24,12 +24,12 @@ ShaderProgram::ShaderProgram(Prototype prototype) : m_shaderProgramId(glCreatePr
|
||||
Log::logger().warn(R"(Failed to link shaderProgram "{}", "{}")", prototype.vertexPath, prototype.fragmentPath);
|
||||
}
|
||||
|
||||
#ifdef _RELEASE
|
||||
glDetachShader(program, vs);
|
||||
glDetachShader(program, fs);
|
||||
#ifdef NDEBUG
|
||||
glDetachShader(m_shaderProgramId, vertexShader);
|
||||
glDetachShader(m_shaderProgramId, fragmentShader);
|
||||
|
||||
glDeleteShader(vs);
|
||||
glDeleteShader(fs);
|
||||
glDeleteShader(vertexShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
#endif
|
||||
|
||||
Log::logger().trace(R"(Loaded shaderprogram "{}".)", prototype.name);
|
||||
|
||||
28
src/camera.cpp
Normal file
28
src/camera.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "camera.h"
|
||||
#include "util/Log.h"
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
auto Camera::projection_matrix() const -> glm::mat4
|
||||
{
|
||||
return std::visit(
|
||||
[](auto &&arg) -> glm::mat4 {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, Perspective>) {
|
||||
return glm::perspective(arg.fov / 2, arg.aspect_ratio, arg.near, arg.far);
|
||||
} else {
|
||||
return glm::ortho(arg.left, arg.right, arg.bottom, arg.top);
|
||||
}
|
||||
},
|
||||
projection);
|
||||
};
|
||||
|
||||
auto Camera::view_matrix(GlobalTransform const &transform) -> glm::mat4
|
||||
{
|
||||
return glm::lookAt(
|
||||
transform.position(), transform.position() + front_vector(transform), UP_VECTOR);
|
||||
}
|
||||
|
||||
auto Camera::front_vector(GlobalTransform const &transform) -> glm::vec3
|
||||
{
|
||||
return glm::normalize(transform.transform * glm::vec4(0.0, 0.0, 1.0, 0.0));
|
||||
}
|
||||
42
src/camera.h
Normal file
42
src/camera.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "transform.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <variant>
|
||||
|
||||
struct Camera
|
||||
{
|
||||
static constexpr float DEFAULT_NEAR = 0.01;
|
||||
static constexpr float DEFAULT_FAR = 1000.0;
|
||||
static constexpr float DEFAULT_FOV = 90.0;
|
||||
|
||||
static constexpr glm::vec3 UP_VECTOR = glm::vec3(0.0, 1.0, 0.0);
|
||||
|
||||
struct Perspective
|
||||
{
|
||||
float fov = DEFAULT_FOV;
|
||||
float aspect_ratio;
|
||||
float near = DEFAULT_NEAR;
|
||||
float far = DEFAULT_FAR;
|
||||
|
||||
float pitch{};
|
||||
float yaw{};
|
||||
};
|
||||
|
||||
struct Orthographic
|
||||
{
|
||||
float left;
|
||||
float right;
|
||||
float top;
|
||||
float bottom;
|
||||
float near = DEFAULT_NEAR;
|
||||
float far = DEFAULT_FAR;
|
||||
};
|
||||
|
||||
std::variant<Perspective, Orthographic> projection;
|
||||
|
||||
[[nodiscard]] auto projection_matrix() const -> glm::mat4;
|
||||
[[nodiscard]] static auto view_matrix(GlobalTransform const &transform) -> glm::mat4;
|
||||
[[nodiscard]] static auto front_vector(GlobalTransform const &transform) -> glm::vec3;
|
||||
};
|
||||
@@ -313,7 +313,7 @@ auto GltfLoader::operator()(std::filesystem::path const &document_path) -> resul
|
||||
glm::quat rotation(node.rotation[3], node.rotation[0], node.rotation[1], node.rotation[2]);
|
||||
glm::vec3 scale(node.scale[0], node.scale[1], node.scale[2]);
|
||||
|
||||
Transform transform{.translation = translation, .rotation = rotation, .scale = scale};
|
||||
Transform transform{.translation = translation, .orientation = rotation, .scale = scale};
|
||||
|
||||
if (node.name.empty()) {
|
||||
Log::logger().warn("glTF node has no name.");
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
struct Transform
|
||||
{
|
||||
glm::vec3 translation;
|
||||
glm::quat rotation;
|
||||
glm::quat orientation;
|
||||
glm::vec3 scale{1.0, 1.0, 1.0};
|
||||
};
|
||||
|
||||
@@ -19,16 +19,18 @@ struct GlobalTransform
|
||||
// First scaling, then rotation, then translation
|
||||
|
||||
// Translate
|
||||
glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0F), transform.translation);
|
||||
glm::mat4 translation_matrix = glm::translate(glm::mat4(1.0F), transform.translation);
|
||||
|
||||
// Rotate
|
||||
glm::mat4 rotationMatrix = glm::toMat4(transform.rotation);
|
||||
glm::mat4 rotation_matrix = glm::toMat4(transform.orientation);
|
||||
|
||||
// Scale
|
||||
glm::mat4 scaleMatrix = glm::scale(glm::mat4(1.0F), transform.scale);
|
||||
glm::mat4 scale_matrix = glm::scale(glm::mat4(1.0F), transform.scale);
|
||||
|
||||
this->transform = translationMatrix * rotationMatrix * scaleMatrix;
|
||||
this->transform = translation_matrix * rotation_matrix * scale_matrix;
|
||||
}
|
||||
|
||||
glm::mat4 transform{};
|
||||
|
||||
[[nodiscard]] auto position() const -> glm::vec3 { return transform[3]; };
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user