If there are errors in the code, terminology, etc. in the text, please correct me
Article directory
foreword
-
Purpose
In order to realize like most 3D software, click on the object, and there will be auxiliary applets for dragging, zooming, and rotating.
-
How to achieve
Using the open source imguizmo library, URL
-
Introducing imguizmo
ImGizmo is a small (.h and .cpp) library built on top of Dear ImGui that allows you to manipulate (currently rotation and translation) 4x4 floating point matrices, with no other dependencies. Written with the idea of Immediate Mode (IM) in mind.
-
gizmos achieve small points
- Pan, zoom, and rotate can be switched with shortcut keys
- You can set the amount of each movement or rotation like Unity, snap
How to import ImGuiZmo library
-
git join submodule
git submodule add https://github.com/TheCherno/ImGuizmo GameEngineLightWeight/vendor/ImGuizmo
-
premake5.lua modification
Like the glm library, only the directory needs to be included , but it needs to be filtered and precompiled headers are not included
IncludeDir["ImGuizmo"] = "GameEngineLightWeight/vendor/ImGuizmo" files{ "%{prj.name}/src/**.h", "%{prj.name}/src/**.cpp", "%{prj.name}/vendor/stb_image/**.cpp", "%{prj.name}/vendor/stb_image/**.h", "%{prj.name}/vendor/glm/glm/**.hpp", "%{prj.name}/vendor/glm/glm/**.inl", "%{prj.name}/vendor/ImGuizmo/ImGuizmo.h", "%{prj.name}/vendor/ImGuizmo/ImGuizmo.cpp" } includedirs{ "%{prj.name}/src", "%{prj.name}/vendor/spdlog/include", "%{IncludeDir.Glad}", "%{IncludeDir.GLFW}", "%{IncludeDir.ImGui}", "%{IncludeDir.glm}", "%{IncludeDir.stb_image}", "%{IncludeDir.entt}", "%{IncludeDir.yaml_cpp}", "%{IncludeDir.ImGuizmo}" } -- imguizmo不使用编译头? 没用 这句 filter "files:%{prj.name}/vendor/ImGuizmo/**.cpp" flags { "NoPCH" }
key code
void EditorLayer::OnImGuiRender()
{
// ImGuizmos
Entity selectedEntity = m_SceneHierarchyPanel.GetSelectedEntity();
if (selectedEntity && m_GizmoType != -1) {
ImGuizmo::SetOrthographic(false);
ImGuizmo::SetDrawlist();
float windowWidth = (float)ImGui::GetWindowWidth();
float windowHeight = (float)ImGui::GetWindowHeight();
ImGuizmo::SetRect(ImGui::GetWindowPos().x, ImGui::GetWindowPos().y, windowWidth, windowHeight);
// Camera
auto cameraEntity = m_ActiveScene->GetPrimaryCameraEntity();
const auto& camera = cameraEntity.GetComponent<CameraComponent>().camera;
const glm::mat4& cameraProjection = camera.GetProjection();
glm::mat4 cameraView = glm::inverse(cameraEntity.GetComponent<TransformComponent>().GetTransform());
// Entity transform
auto& tc = selectedEntity.GetComponent<TransformComponent>();
glm::mat4 transform = tc.GetTransform();
// Snapping
bool snap = Input::IsKeyPressed(Key::LeftControl);
float snapValue = 0.5f; // 平移的snap
if (m_GizmoType == ImGuizmo::OPERATION::ROTATE) {
// rotate的度数
snapValue = 45.0f;
}
float snapValues[3] = {
snapValue, snapValue,snapValue };
// 这里可以说是传入相应参数,得到绘画出来的gizmos
ImGuizmo::Manipulate(glm::value_ptr(cameraView), glm::value_ptr(cameraProjection),
(ImGuizmo::OPERATION)m_GizmoType, ImGuizmo::LOCAL, glm::value_ptr(transform),
nullptr, snap ? snapValues : nullptr);
// 如果gizmos被使用 或者 说被移动
if (ImGuizmo::IsUsing()) {
glm::vec3 translation, rotation, scale;
Math::DecomposeTransform(transform, translation, rotation, scale);
// 用增量旋转,解决矩阵可能会造成万向锁。
glm::vec3 deltaRotation = rotation - tc.Rotation;
tc.Translation = translation;
tc.Rotation += deltaRotation; // 每一帧增加没有限制角度,而不是固定在360度数。
tc.Scale = scale;
}
}
bool EditorLayer::OnKeyPressed(KeyPressedEvent& e)
{
if (e.GetRepeatCount() > 0) {
return false;
}
bool control = Input::IsKeyPressed(Key::LeftControl) || Input::IsKeyPressed(Key::RightControl);
bool shift = Input::IsKeyPressed(Key::LeftShift) || Input::IsKeyPressed(Key::RightShift);
switch (e.GetKeyCode()) {
case Key::N: {
if (control) {
NewScene();
}
break;
}
case Key::O: {
if (control) {
OpenScene();
}
break;
}
case Key::S: {
if (control && shift) {
SaveSceneAs();
}
// 保存当前场景:要有一个记录当前场景的路径。
//if (control) {
//}
break;
}
// Gizmos
case Key::Q:
m_GizmoType = -1;
break;
case Key::W:
m_GizmoType = ImGuizmo::OPERATION::TRANSLATE;
break;
case Key::E:
m_GizmoType = ImGuizmo::OPERATION::ROTATE;
break;
case Key::R:
m_GizmoType = ImGuizmo::OPERATION::SCALE;
break;
}
Effect
Modify bugs
-
Question details
After the entity is clicked in the Hierarchy, even if the mouse hovers over the viewport window and the shortcut key is pressed, the type of gizmos will not be switched
To modify the mouse to stop on the viewport window, press the shortcut key to switch the type of gizmos
-
before modification
Application::Get().GetImGuiLayer()->BlockEvents(!m_ViewportFocused || !m_ViewportHovered); // 修改之前:意思是当鼠标点击面板并且悬停在面板上,才能接受事件,其它情况均不能接收事件 bool canshu = !m_ViewportFocused || !m_ViewportHovered; m_ViewportFocused = true, m_ViewportHovered = true; canshu = false, m_BlockEvents:false-> viewport面板 能 接收事件 m_ViewportFocused = true, m_ViewportHovered = false;canshu = true, m_BlockEvents:true-> viewport面板 不 能接收事件 m_ViewportFocused = false, m_ViewportHovered = true; canshu = true, m_BlockEvents:true-> viewport面板 不 能接收事件 m_ViewportFocused = false, m_ViewportHovered = false;canshu = true, m_BlockEvents:true-> viewport面板 不 能接收事件
-
after modification
Application::Get().GetImGuiLayer()->BlockEvents(!m_ViewportFocused && !m_ViewportHovered); // 修改之后:意思是当鼠标没有点击面板并且没有悬停在面板上,就不接受事件,其它情况均可接收事件 bool canshu = !m_ViewportFocused && !m_ViewportHovered; m_ViewportFocused = true, m_ViewportHovered = true; canshu = false, m_BlockEvents:false-> viewport面板 能 接收事件 m_ViewportFocused = true, m_ViewportHovered = false;canshu = false, m_BlockEvents:true-> viewport面板 能 接收事件 m_ViewportFocused = false, m_ViewportHovered = true; canshu = false, m_BlockEvents:true-> viewport面板 能 接收事件 m_ViewportFocused = false, m_ViewportHovered = false;canshu = true, m_BlockEvents:true-> viewport面板 不 能接收事件