ADD: quaternion based rotation
This commit is contained in:
@@ -24,6 +24,37 @@
|
|||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
// Helper utilities for TRS (translation-rotation-scale) transforms using quaternions.
|
||||||
|
inline glm::mat4 make_trs_matrix(const glm::vec3 &translation,
|
||||||
|
const glm::quat &rotation,
|
||||||
|
const glm::vec3 &scale)
|
||||||
|
{
|
||||||
|
glm::mat4 tm = glm::translate(glm::mat4(1.0f), translation);
|
||||||
|
glm::mat4 rm = glm::mat4_cast(rotation);
|
||||||
|
glm::mat4 sm = glm::scale(glm::mat4(1.0f), scale);
|
||||||
|
return tm * rm * sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void decompose_trs_matrix(const glm::mat4 &m,
|
||||||
|
glm::vec3 &out_translation,
|
||||||
|
glm::quat &out_rotation,
|
||||||
|
glm::vec3 &out_scale)
|
||||||
|
{
|
||||||
|
out_translation = glm::vec3(m[3]);
|
||||||
|
|
||||||
|
glm::vec3 col0 = glm::vec3(m[0]);
|
||||||
|
glm::vec3 col1 = glm::vec3(m[1]);
|
||||||
|
glm::vec3 col2 = glm::vec3(m[2]);
|
||||||
|
|
||||||
|
out_scale = glm::vec3(glm::length(col0), glm::length(col1), glm::length(col2));
|
||||||
|
if (out_scale.x != 0.0f) col0 /= out_scale.x;
|
||||||
|
if (out_scale.y != 0.0f) col1 /= out_scale.y;
|
||||||
|
if (out_scale.z != 0.0f) col2 /= out_scale.z;
|
||||||
|
|
||||||
|
glm::mat3 rot_mat(col0, col1, col2);
|
||||||
|
out_rotation = glm::quat_cast(rot_mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define VK_CHECK(x) \
|
#define VK_CHECK(x) \
|
||||||
do { \
|
do { \
|
||||||
@@ -169,10 +200,7 @@ struct Node : public IRenderable {
|
|||||||
|
|
||||||
void updateLocalFromTRS()
|
void updateLocalFromTRS()
|
||||||
{
|
{
|
||||||
glm::mat4 tm = glm::translate(glm::mat4(1.0f), translation);
|
localTransform = make_trs_matrix(translation, rotation, scale);
|
||||||
glm::mat4 rm = glm::mat4_cast(rotation);
|
|
||||||
glm::mat4 sm = glm::scale(glm::mat4(1.0f), scale);
|
|
||||||
localTransform = tm * rm * sm;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTRS(const glm::vec3 &t, const glm::quat &r, const glm::vec3 &s)
|
void setTRS(const glm::vec3 &t, const glm::quat &r, const glm::vec3 &s)
|
||||||
|
|||||||
@@ -38,10 +38,21 @@ void Camera::processSDLEvent(SDL_Event& e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (e.type == SDL_MOUSEMOTION && rmbDown) {
|
if (e.type == SDL_MOUSEMOTION && rmbDown) {
|
||||||
// Mouse right (xrel > 0) turns view right with -Z-forward
|
// Convert mouse motion to incremental yaw/pitch angles.
|
||||||
yaw += (float)e.motion.xrel * lookSensitivity; // axis = +Y
|
float dx = static_cast<float>(e.motion.xrel) * lookSensitivity;
|
||||||
// Mouse up (yrel < 0) looks up with -Z-forward
|
float dy = static_cast<float>(e.motion.yrel) * lookSensitivity;
|
||||||
pitch -= (float)e.motion.yrel * lookSensitivity;
|
|
||||||
|
// Mouse right (xrel > 0) turns view right with -Z-forward: yaw around +Y.
|
||||||
|
glm::quat yawRotation = glm::angleAxis(dx, glm::vec3 { 0.f, 1.f, 0.f });
|
||||||
|
|
||||||
|
// Mouse up (yrel < 0) looks up with -Z-forward: negative dy.
|
||||||
|
float pitchDelta = -dy;
|
||||||
|
// Pitch around the camera's local X (right) axis in world space.
|
||||||
|
glm::vec3 right = glm::rotate(orientation, glm::vec3 { 1.f, 0.f, 0.f });
|
||||||
|
glm::quat pitchRotation = glm::angleAxis(pitchDelta, glm::vec3(right));
|
||||||
|
|
||||||
|
// Apply yaw, then pitch, to the current orientation.
|
||||||
|
orientation = glm::normalize(pitchRotation * yawRotation * orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.type == SDL_MOUSEWHEEL) {
|
if (e.type == SDL_MOUSEWHEEL) {
|
||||||
@@ -72,12 +83,6 @@ glm::mat4 Camera::getViewMatrix()
|
|||||||
|
|
||||||
glm::mat4 Camera::getRotationMatrix()
|
glm::mat4 Camera::getRotationMatrix()
|
||||||
{
|
{
|
||||||
// fairly typical FPS style camera. we join the pitch and yaw rotations into
|
// Use the stored quaternion orientation directly.
|
||||||
// the final rotation matrix
|
return glm::toMat4(orientation);
|
||||||
|
|
||||||
glm::quat pitchRotation = glm::angleAxis(pitch, glm::vec3 { 1.f, 0.f, 0.f });
|
|
||||||
// Yaw around +Y keeps mouse-right -> turn-right with -Z-forward
|
|
||||||
glm::quat yawRotation = glm::angleAxis(yaw, glm::vec3 { 0.f, 1.f, 0.f });
|
|
||||||
|
|
||||||
return glm::toMat4(yawRotation) * glm::toMat4(pitchRotation);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,8 @@ class Camera {
|
|||||||
public:
|
public:
|
||||||
glm::vec3 velocity;
|
glm::vec3 velocity;
|
||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
// vertical rotation
|
// Orientation stored as a quaternion (local -> world).
|
||||||
float pitch { 0.f };
|
glm::quat orientation { 1.0f, 0.0f, 0.0f, 0.0f };
|
||||||
// horizontal rotation
|
|
||||||
float yaw { 0.f };
|
|
||||||
|
|
||||||
// Movement/look tuning
|
// Movement/look tuning
|
||||||
float moveSpeed { 0.03f };
|
float moveSpeed { 0.03f };
|
||||||
|
|||||||
@@ -671,18 +671,10 @@ std::optional<std::shared_ptr<LoadedGLTF> > loadGltf(VulkanEngine *engine, std::
|
|||||||
glm::mat4 m(1.0f);
|
glm::mat4 m(1.0f);
|
||||||
memcpy(&m, matrix.data(), sizeof(matrix));
|
memcpy(&m, matrix.data(), sizeof(matrix));
|
||||||
|
|
||||||
glm::vec3 t = glm::vec3(m[3]);
|
glm::vec3 t;
|
||||||
glm::vec3 col0 = glm::vec3(m[0]);
|
glm::quat r;
|
||||||
glm::vec3 col1 = glm::vec3(m[1]);
|
glm::vec3 s;
|
||||||
glm::vec3 col2 = glm::vec3(m[2]);
|
decompose_trs_matrix(m, t, r, s);
|
||||||
|
|
||||||
glm::vec3 s(glm::length(col0), glm::length(col1), glm::length(col2));
|
|
||||||
if (s.x != 0.0f) col0 /= s.x;
|
|
||||||
if (s.y != 0.0f) col1 /= s.y;
|
|
||||||
if (s.z != 0.0f) col2 /= s.z;
|
|
||||||
glm::mat3 rotMat(col0, col1, col2);
|
|
||||||
glm::quat r = glm::quat_cast(rotMat);
|
|
||||||
|
|
||||||
newNode->setTRS(t, r, s);
|
newNode->setTRS(t, r, s);
|
||||||
},
|
},
|
||||||
[&](fastgltf::Node::TRS transform) {
|
[&](fastgltf::Node::TRS transform) {
|
||||||
|
|||||||
@@ -73,8 +73,7 @@ void SceneManager::init(EngineContext *context)
|
|||||||
|
|
||||||
mainCamera.velocity = glm::vec3(0.f);
|
mainCamera.velocity = glm::vec3(0.f);
|
||||||
mainCamera.position = glm::vec3(30.f, -00.f, 85.f);
|
mainCamera.position = glm::vec3(30.f, -00.f, 85.f);
|
||||||
mainCamera.pitch = 0;
|
mainCamera.orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
|
||||||
mainCamera.yaw = 0;
|
|
||||||
|
|
||||||
sceneData.ambientColor = glm::vec4(0.1f, 0.1f, 0.1f, 1.0f);
|
sceneData.ambientColor = glm::vec4(0.1f, 0.1f, 0.1f, 1.0f);
|
||||||
sceneData.sunlightDirection = glm::vec4(-0.2f, -1.0f, -0.3f, 1.0f);
|
sceneData.sunlightDirection = glm::vec4(-0.2f, -1.0f, -0.3f, 1.0f);
|
||||||
@@ -204,7 +203,8 @@ void SceneManager::update_scene()
|
|||||||
{
|
{
|
||||||
mainDrawContext.gltfNodeLocalOverrides = nullptr;
|
mainDrawContext.gltfNodeLocalOverrides = nullptr;
|
||||||
}
|
}
|
||||||
inst.scene->Draw(inst.transform, mainDrawContext);
|
glm::mat4 instanceTransform = make_trs_matrix(inst.translation, inst.rotation, inst.scale);
|
||||||
|
inst.scene->Draw(instanceTransform, mainDrawContext);
|
||||||
mainDrawContext.gltfNodeLocalOverrides = nullptr;
|
mainDrawContext.gltfNodeLocalOverrides = nullptr;
|
||||||
tagOwner(RenderObject::OwnerType::GLTFInstance, kv.first, opaqueStart, transpStart);
|
tagOwner(RenderObject::OwnerType::GLTFInstance, kv.first, opaqueStart, transpStart);
|
||||||
}
|
}
|
||||||
@@ -216,6 +216,7 @@ void SceneManager::update_scene()
|
|||||||
{
|
{
|
||||||
const MeshInstance &inst = kv.second;
|
const MeshInstance &inst = kv.second;
|
||||||
if (!inst.mesh || inst.mesh->surfaces.empty()) continue;
|
if (!inst.mesh || inst.mesh->surfaces.empty()) continue;
|
||||||
|
glm::mat4 instanceTransform = make_trs_matrix(inst.translation, inst.rotation, inst.scale);
|
||||||
uint32_t surfaceIndex = 0;
|
uint32_t surfaceIndex = 0;
|
||||||
for (const auto &surf: inst.mesh->surfaces)
|
for (const auto &surf: inst.mesh->surfaces)
|
||||||
{
|
{
|
||||||
@@ -231,7 +232,7 @@ void SceneManager::update_scene()
|
|||||||
{
|
{
|
||||||
obj.bounds.type = *inst.boundsTypeOverride;
|
obj.bounds.type = *inst.boundsTypeOverride;
|
||||||
}
|
}
|
||||||
obj.transform = inst.transform;
|
obj.transform = instanceTransform;
|
||||||
obj.sourceMesh = inst.mesh.get();
|
obj.sourceMesh = inst.mesh.get();
|
||||||
obj.surfaceIndex = surfaceIndex++;
|
obj.surfaceIndex = surfaceIndex++;
|
||||||
obj.objectID = mainDrawContext.nextID++;
|
obj.objectID = mainDrawContext.nextID++;
|
||||||
@@ -429,7 +430,7 @@ void SceneManager::addMeshInstance(const std::string &name, std::shared_ptr<Mesh
|
|||||||
if (!mesh) return;
|
if (!mesh) return;
|
||||||
MeshInstance inst{};
|
MeshInstance inst{};
|
||||||
inst.mesh = std::move(mesh);
|
inst.mesh = std::move(mesh);
|
||||||
inst.transform = transform;
|
decompose_trs_matrix(transform, inst.translation, inst.rotation, inst.scale);
|
||||||
inst.boundsTypeOverride = boundsType;
|
inst.boundsTypeOverride = boundsType;
|
||||||
dynamicMeshInstances[name] = std::move(inst);
|
dynamicMeshInstances[name] = std::move(inst);
|
||||||
}
|
}
|
||||||
@@ -441,7 +442,8 @@ bool SceneManager::getMeshInstanceTransform(const std::string &name, glm::mat4 &
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
outTransform = it->second.transform;
|
const MeshInstance &inst = it->second;
|
||||||
|
outTransform = make_trs_matrix(inst.translation, inst.rotation, inst.scale);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,7 +454,8 @@ bool SceneManager::setMeshInstanceTransform(const std::string &name, const glm::
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
it->second.transform = transform;
|
MeshInstance &inst = it->second;
|
||||||
|
decompose_trs_matrix(transform, inst.translation, inst.rotation, inst.scale);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,7 +478,7 @@ void SceneManager::addGLTFInstance(const std::string &name, std::shared_ptr<Load
|
|||||||
scene->debugName.empty() ? "<unnamed>" : scene->debugName.c_str());
|
scene->debugName.empty() ? "<unnamed>" : scene->debugName.c_str());
|
||||||
GLTFInstance inst{};
|
GLTFInstance inst{};
|
||||||
inst.scene = std::move(scene);
|
inst.scene = std::move(scene);
|
||||||
inst.transform = transform;
|
decompose_trs_matrix(transform, inst.translation, inst.rotation, inst.scale);
|
||||||
if (inst.scene && !inst.scene->animations.empty())
|
if (inst.scene && !inst.scene->animations.empty())
|
||||||
{
|
{
|
||||||
inst.animation.activeAnimation = 0;
|
inst.animation.activeAnimation = 0;
|
||||||
@@ -519,7 +522,8 @@ bool SceneManager::getGLTFInstanceTransform(const std::string &name, glm::mat4 &
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
outTransform = it->second.transform;
|
const GLTFInstance &inst = it->second;
|
||||||
|
outTransform = make_trs_matrix(inst.translation, inst.rotation, inst.scale);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,7 +531,8 @@ bool SceneManager::setGLTFInstanceTransform(const std::string &name, const glm::
|
|||||||
{
|
{
|
||||||
auto it = dynamicGLTFInstances.find(name);
|
auto it = dynamicGLTFInstances.find(name);
|
||||||
if (it == dynamicGLTFInstances.end()) return false;
|
if (it == dynamicGLTFInstances.end()) return false;
|
||||||
it->second.transform = transform;
|
GLTFInstance &inst = it->second;
|
||||||
|
decompose_trs_matrix(transform, inst.translation, inst.rotation, inst.scale);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,9 @@ public:
|
|||||||
struct MeshInstance
|
struct MeshInstance
|
||||||
{
|
{
|
||||||
std::shared_ptr<MeshAsset> mesh;
|
std::shared_ptr<MeshAsset> mesh;
|
||||||
glm::mat4 transform{1.f};
|
glm::vec3 translation{0.0f, 0.0f, 0.0f};
|
||||||
|
glm::quat rotation{1.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
glm::vec3 scale{1.0f, 1.0f, 1.0f};
|
||||||
std::optional<BoundsType> boundsTypeOverride;
|
std::optional<BoundsType> boundsTypeOverride;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -107,7 +109,9 @@ public:
|
|||||||
struct GLTFInstance
|
struct GLTFInstance
|
||||||
{
|
{
|
||||||
std::shared_ptr<LoadedGLTF> scene;
|
std::shared_ptr<LoadedGLTF> scene;
|
||||||
glm::mat4 transform{1.f};
|
glm::vec3 translation{0.0f, 0.0f, 0.0f};
|
||||||
|
glm::quat rotation{1.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
glm::vec3 scale{1.0f, 1.0f, 1.0f};
|
||||||
LoadedGLTF::AnimationState animation;
|
LoadedGLTF::AnimationState animation;
|
||||||
// Per-instance local-space pose offsets for nodes in this glTF scene.
|
// Per-instance local-space pose offsets for nodes in this glTF scene.
|
||||||
// The offset matrix is post-multiplied onto the node's localTransform.
|
// The offset matrix is post-multiplied onto the node's localTransform.
|
||||||
|
|||||||
Reference in New Issue
Block a user