gfx-playground
cross platform rendering playgroundfix(editor): cache euler edits per target, double-cover-safe quaternion compare
| 4 files changed, 38 insertions(+), 34 deletions(-) | |||
|---|---|---|---|
| MOD | src/core/math_rtm.cpp | +8 | -14 |
| MOD | src/core/math_rtm.h | +7 | -8 |
| MOD | src/editor/editor.cpp | +1 | -1 |
| MOD | src/editor/inspector.cpp | +22 | -11 |
--- a/src/core/math_rtm.cpp
+++ b/src/core/math_rtm.cpp
@@ -185,22 +185,16 @@ TRS mat4_to_trs(const mat4 &m) {
}
vec3 quat_to_euler(const quat &q) {
- // rot matrix for q (row-vector convention), via the T*R*S path with identity T/S.
const mat4 m = trs_to_mat4(TRS{vec3(0.0f), q, vec3(1.0f)});
- // RTM stores each mat row as vector type: element [row][col] = m.m[row*4 + col].
- const f32 m00 = m.m[0];
- const f32 m01 = m.m[1];
- const f32 m02 = m.m[2];
- const f32 m12 = m.m[6];
- const f32 m22 = m.m[10];
-
- f32 pitch = std::asin(std::min(1.0f, std::max(-1.0f, m02)));
- f32 yaw = std::atan2(m01, m00);
- f32 roll = std::atan2(-m12, m22);
-
- return {degrees(pitch), degrees(yaw), degrees(roll)};
+ const f32 pitch = std::asin(std::clamp(m.m[2], -1.0f, 1.0f));
+ const f32 yaw = std::atan2(m.m[1], m.m[0]);
+ const f32 roll = std::atan2(-m.m[6], m.m[10]);
+ return vec3(degrees(pitch), degrees(yaw), degrees(roll));
}
quat euler_to_quat(const vec3 &euler) {
- return rtm::quat_from_euler(radians(euler.x), radians(euler.y), radians(euler.z));
+ quat qz = quat::from_axis_angle(vec3(0, 0, 1), radians(euler.z));
+ quat qy = quat::from_axis_angle(vec3(0, 1, 0), radians(euler.y));
+ quat qx = quat::from_axis_angle(vec3(1, 0, 0), radians(euler.x));
+ return (qz * qy * qx).normalized();
}MOD · src/core/math_rtm.h +7 -8--- a/src/core/math_rtm.h
+++ b/src/core/math_rtm.h
@@ -8,6 +8,8 @@
#include "core/globals.h"
+constexpr double PI = 3.14159265358979323846;
+
using vec_work = rtm::vector4f;
inline f32 radians(f32 deg) {
@@ -486,10 +488,6 @@ static_assert(std::is_standard_layout_v<vec4>);
static_assert(std::is_standard_layout_v<mat3>);
static_assert(std::is_standard_layout_v<mat4>);
-// =========================================================================
-// Quaternion (WIP)
-// =========================================================================
-
struct quat {
rtm::quatf q;
@@ -514,15 +512,16 @@ struct quat {
operator rtm::quatf() const {
return q;
}
+
+ bool same_rotation(const quat &rhs, f32 epsilon = 1e-6f) const {
+ f32 dot = rtm::scalar_cast(rtm::quat_dot_as_scalar(q, rhs.q));
+ return dot * dot > 1.0f - epsilon;
+ }
};
static_assert(sizeof(quat) == 16, "quat must be 16 bytes");
static_assert(std::is_trivially_copyable_v<quat>);
-// =========================================================================
-// TRS decomposition
-// =========================================================================
-
struct TRS {
vec3 translation = vec3(0.0f);
quat rotation;MOD · src/editor/editor.cpp +1 -1--- a/src/editor/editor.cpp
+++ b/src/editor/editor.cpp
@@ -302,7 +302,7 @@ void end_frame(Editor &e, Scene &scene, RenderData &rd, const PassInspectorEntry
draw_scene_graph_window(scene, *e.assets, e.selected_node);
}
if (e.show_inspector && e.assets) {
- draw_inspector_window(scene, *e.assets, e.font_mono, e.selected_node);
+ draw_inspector_window(scene, *e.assets, e.font_mono, e);
}
if (e.show_viewport) {
draw_viewport_central(e, rd);MOD · src/editor/inspector.cpp +22 -11--- a/src/editor/inspector.cpp
+++ b/src/editor/inspector.cpp
@@ -15,7 +15,16 @@ namespace editor {
namespace {
-void draw_transform_panel(SceneGraph &sg, u32 node) {
+inline bool edit_euler_cached(const char *label, EulerEdit &st, int id, const quat &cur) {
+ if (st.id != id || !st.sync.same_rotation(cur)) {
+ st.id = id;
+ st.euler = quat_to_euler(cur);
+ st.sync = cur;
+ }
+ return ImGui::DragFloat3(label, &st.euler.x, 0.5f);
+}
+
+void draw_transform_panel(SceneGraph &sg, u32 node, EulerEdit &rot_state) {
ImGui::Text("Index: %u", node);
ImGui::Text("Parent: %d", sg.parent[node]);
ImGui::Text("Children: %s", sg.first_child[node] == SCENE_INVALID ? "none" : "yes");
@@ -26,9 +35,9 @@ void draw_transform_panel(SceneGraph &sg, u32 node) {
sg.set_translation(node, t);
}
- vec3 euler = quat_to_euler(quat(sg.rotations[node]));
- if (ImGui::DragFloat3("Rotation (pitch, yaw, roll) deg", &euler.x, 0.5f)) {
- sg.set_rotation(node, rtm::quat_normalize((rtm::quatf)euler_to_quat(euler)));
+ if (edit_euler_cached("Rotation (pitch, yaw, roll) deg", rot_state, (int)node, quat(sg.rotations[node]))) {
+ sg.set_rotation(node, rtm::quat_normalize((rtm::quatf)euler_to_quat(rot_state.euler).normalized()));
+ rot_state.sync = quat(sg.rotations[node]);
}
vec3 s = sg.scales[node];
@@ -40,7 +49,7 @@ void draw_transform_panel(SceneGraph &sg, u32 node) {
ImGui::Text("World pos: %.3f %.3f %.3f", wh.x, wh.y, wh.z);
}
-void draw_mesh_inspector(Scene &scene, const AssetManager &mgr, u32 node) {
+void draw_mesh_inspector(Scene &scene, const AssetManager &mgr, u32 node, EulerEdit &inst_rot_state) {
SceneGraph &sg = scene.scene_graph;
bool is_mesh = false;
@@ -98,9 +107,10 @@ void draw_mesh_inspector(Scene &scene, const AssetManager &mgr, u32 node) {
if (ImGui::TreeNode(lb)) {
ImGui::DragFloat3("Translation (local)", &trs.translation.x, 0.05f);
- vec3 euler = quat_to_euler(trs.rotation);
- if (ImGui::DragFloat3("Rotation (pitch, yaw, roll) deg", &euler.x, 0.5f)) {
- trs.rotation = euler_to_quat(euler);
+ int slot = (int)(base + k);
+ if (edit_euler_cached("Rotation (pitch, yaw, roll) deg", inst_rot_state, slot, trs.rotation)) {
+ trs.rotation = euler_to_quat(inst_rot_state.euler).normalized();
+ inst_rot_state.sync = trs.rotation;
}
if (ImGui::DragFloat3("Scale", &trs.scale.x, 0.01f)) {
@@ -211,7 +221,7 @@ void draw_point_light_inspector(Scene &scene, u32 node) {
} // anonymous namespace
-void draw_inspector_window(Scene &scene, const AssetManager &mgr, ImFont *mono_font, int &selected_node) {
+void draw_inspector_window(Scene &scene, const AssetManager &mgr, ImFont *mono_font, Editor &e) {
if (ImGui::Begin("Inspector", nullptr, PANEL_FLAGS)) {
SceneGraph *sc = &scene.scene_graph;
if (!sc || sc->node_count == 0) {
@@ -219,6 +229,7 @@ void draw_inspector_window(Scene &scene, const AssetManager &mgr, ImFont *mono_f
ImGui::End();
return;
}
+ int &selected_node = e.selected_node;
if (selected_node >= 0 && selected_node < (int)sc->node_count) {
u32 node = (u32)selected_node;
if (!sc->is_node_alive(node)) {
@@ -226,8 +237,8 @@ void draw_inspector_window(Scene &scene, const AssetManager &mgr, ImFont *mono_f
ImGui::End();
return;
}
- draw_transform_panel(*sc, node);
- draw_mesh_inspector(scene, mgr, node);
+ draw_transform_panel(*sc, node, e.node_rot);
+ draw_mesh_inspector(scene, mgr, node, e.inst_rot);
draw_camera_inspector(scene, node);
draw_directional_light_inspector(scene, node);
draw_point_light_inspector(scene, node);