add ImViewzmo, add floating window for QWER(select, translate, rotate, scale) , and add new debug button to floating (Experimental)

This commit is contained in:
2026-03-02 17:10:03 +08:00
parent a0086020c1
commit 57e14bc3d2
11 changed files with 337 additions and 134 deletions

View File

@ -6,6 +6,9 @@
#include <ImGuizmo.h>
#include <filesystem>
#define IMVIEWGUIZMO_IMPLEMENTATION
#include "ImViewGuizmo.h"
#define GLM_ENABLE_EXPERIMENTAL
#include "glm/gtx/matrix_decompose.hpp"
@ -46,7 +49,7 @@ namespace Prism
// OpenScene("assets/scenes/FPSDemo.scene");
NewScene();
m_CurrentScene = m_RuntimeScene;
m_CurrentScene = m_EditorScene;
AssetEditorPanel::RegisterDefaultEditors();
FileSystem::StartWatching();
@ -589,122 +592,272 @@ namespace Prism
auto viewportOffset = ImGui::GetCursorPos(); // includes tab bar
auto viewportSize = ImGui::GetContentRegionAvail();
SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
m_EditorScene->SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
if (m_RuntimeScene)
m_RuntimeScene->SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
m_EditorCamera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
m_EditorCamera.SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
static int counter = 0;
auto windowSize = ImGui::GetWindowSize();
ImVec2 minBound = ImGui::GetWindowPos();
minBound.x += viewportOffset.x;
minBound.y += viewportOffset.y;
ImVec2 maxBound = { minBound.x + windowSize.x, minBound.y + windowSize.y };
m_ViewportBounds[0] = { minBound.x, minBound.y };
m_ViewportBounds[1] = { maxBound.x, maxBound.y };
m_AllowViewportCameraEvents = ImGui::IsMouseHoveringRect(minBound, maxBound);
// ImGuizmo
if (m_GizmoType != -1 && !m_SelectionContext.empty())
if (viewportSize.x != 0 && viewportSize.y != 0)
{
auto& selection = m_SelectionContext[0];
SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
m_EditorScene->SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
m_EditorCamera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
m_EditorCamera.SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
const auto rw = (float)ImGui::GetWindowWidth();
const auto rh = (float)ImGui::GetWindowHeight();
ImGuizmo::SetOrthographic(false);
ImGuizmo::SetDrawlist();
ImGuizmo::SetRect(ImGui::GetWindowPos().x, ImGui::GetWindowPos().y, rw, rh);
bool snap = Input::IsKeyPressed(Key::LEFT_CONTROL);
TransformComponent& entityTransform = selection.Entity.Transform();
// glm::mat4 transform = entityTransform.GetTransform();
glm::mat4 transform = m_CurrentScene->GetTransformRelativeToParent(selection.Entity);
float snapValue = GetSnapValue();
float snapValues[3] = { snapValue, snapValue, snapValue };
if (m_SelectionMode == SelectionMode::Entity)
if (ImGui::BeginDragDropTarget())
{
ImGuizmo::Manipulate(glm::value_ptr(m_EditorCamera.GetViewMatrix()),
glm::value_ptr(m_EditorCamera.GetProjectionMatrix()),
(ImGuizmo::OPERATION)m_GizmoType,
ImGuizmo::LOCAL,
glm::value_ptr(transform),
nullptr,
snap ? snapValues : nullptr);
if (ImGuizmo::IsUsing())
auto payload = ImGui::AcceptDragDropPayload("asset_payload");
if (payload)
{
glm::vec3 translation, rotation, scale;
Math::DecomposeTransform(transform, translation,rotation,scale);
int count = payload->DataSize / sizeof(AssetHandle);
if (Entity parent = m_CurrentScene->FindEntityByUUID(selection.Entity.GetParentUUID()))
for (int i = 0; i < count; i++)
{
glm::vec3 parentTranslation, parentRotation, parentScale;
Math::DecomposeTransform(m_CurrentScene->GetTransformRelativeToParent(parent), parentTranslation, parentRotation, parentScale);
AssetHandle assetHandle = *(((AssetHandle*)payload->Data) + i);
Ref<Asset> asset = AssetsManager::GetAsset<Asset>(assetHandle);
glm::vec3 deltaRotation = (rotation - parentRotation) - entityTransform.Rotation;
entityTransform.Translation = translation - parentTranslation;
entityTransform.Rotation += deltaRotation;
entityTransform.Scale = scale;
}
else
{
glm::vec3 deltaRotation = rotation - entityTransform.Rotation;
entityTransform.Translation = translation;
entityTransform.Rotation += deltaRotation;
entityTransform.Scale = scale;
// We can't really support dragging and dropping scenes when we're dropping multiple assets
if (count == 1 && asset->Type == AssetType::Scene)
{
OpenScene(asset->FilePath);
}
if (asset->Type == AssetType::Mesh)
{
Entity entity = m_EditorScene->CreateEntity(asset->FileName);
entity.AddComponent<MeshComponent>(Ref<Mesh>(asset));
SelectEntity(entity);
}
}
}
}else
{
glm::mat4 transformBase = transform * selection.Mesh->Transform;
ImGuizmo::Manipulate(glm::value_ptr(m_EditorCamera.GetViewMatrix()),
glm::value_ptr(m_EditorCamera.GetProjectionMatrix()),
(ImGuizmo::OPERATION)m_GizmoType,
ImGuizmo::LOCAL,
glm::value_ptr(transformBase),
nullptr,
snap ? snapValues : nullptr);
if (ImGuizmo::IsUsing())
{
selection.Mesh->Transform = glm::inverse(entityTransform.GetTransform()) * transformBase;
}
ImGui::EndDragDropTarget();
}
}
if (ImGui::BeginDragDropTarget())
{
auto payload = ImGui::AcceptDragDropPayload("asset_payload");
if (payload)
auto windowSize = ImGui::GetWindowSize();
ImVec2 minBound = ImGui::GetWindowPos();
minBound.x += viewportOffset.x;
minBound.y += viewportOffset.y;
ImVec2 maxBound = { minBound.x + windowSize.x, minBound.y + windowSize.y };
m_ViewportBounds[0] = { minBound.x, minBound.y };
m_ViewportBounds[1] = { maxBound.x, maxBound.y };
m_AllowViewportCameraEvents = ImGui::IsMouseHoveringRect(minBound, maxBound);
// ImGuizmo
if (m_GizmoType != -1 && !m_SelectionContext.empty())
{
int count = payload->DataSize / sizeof(AssetHandle);
auto& selection = m_SelectionContext[0];
for (int i = 0; i < count; i++)
const auto rw = (float)ImGui::GetWindowWidth();
const auto rh = (float)ImGui::GetWindowHeight();
ImGuizmo::SetOrthographic(false);
ImGuizmo::SetDrawlist();
ImGuizmo::SetRect(ImGui::GetWindowPos().x, ImGui::GetWindowPos().y, rw, rh);
bool snap = Input::IsKeyPressed(Key::LEFT_CONTROL);
TransformComponent& entityTransform = selection.Entity.Transform();
// glm::mat4 transform = entityTransform.GetTransform();
glm::mat4 transform = m_CurrentScene->GetTransformRelativeToParent(selection.Entity);
float snapValue = GetSnapValue();
float snapValues[3] = { snapValue, snapValue, snapValue };
if (m_SelectionMode == SelectionMode::Entity)
{
AssetHandle assetHandle = *(((AssetHandle*)payload->Data) + i);
Ref<Asset> asset = AssetsManager::GetAsset<Asset>(assetHandle);
ImGuizmo::Manipulate(glm::value_ptr(m_EditorCamera.GetViewMatrix()),
glm::value_ptr(m_EditorCamera.GetProjectionMatrix()),
(ImGuizmo::OPERATION)m_GizmoType,
ImGuizmo::LOCAL,
glm::value_ptr(transform),
nullptr,
snap ? snapValues : nullptr);
// We can't really support dragging and dropping scenes when we're dropping multiple assets
if (count == 1 && asset->Type == AssetType::Scene)
if (ImGuizmo::IsUsing())
{
OpenScene(asset->FilePath);
glm::vec3 translation, rotation, scale;
Math::DecomposeTransform(transform, translation,rotation,scale);
if (Entity parent = m_CurrentScene->FindEntityByUUID(selection.Entity.GetParentUUID()))
{
glm::vec3 parentTranslation, parentRotation, parentScale;
Math::DecomposeTransform(m_CurrentScene->GetTransformRelativeToParent(parent), parentTranslation, parentRotation, parentScale);
glm::vec3 deltaRotation = (rotation - parentRotation) - entityTransform.Rotation;
entityTransform.Translation = translation - parentTranslation;
entityTransform.Rotation += deltaRotation;
entityTransform.Scale = scale;
}
else
{
glm::vec3 deltaRotation = rotation - entityTransform.Rotation;
entityTransform.Translation = translation;
entityTransform.Rotation += deltaRotation;
entityTransform.Scale = scale;
}
}
}else
{
glm::mat4 transformBase = transform * selection.Mesh->Transform;
ImGuizmo::Manipulate(glm::value_ptr(m_EditorCamera.GetViewMatrix()),
glm::value_ptr(m_EditorCamera.GetProjectionMatrix()),
(ImGuizmo::OPERATION)m_GizmoType,
ImGuizmo::LOCAL,
glm::value_ptr(transformBase),
nullptr,
snap ? snapValues : nullptr);
if (asset->Type == AssetType::Mesh)
if (ImGuizmo::IsUsing())
{
Entity entity = m_EditorScene->CreateEntity(asset->FileName);
entity.AddComponent<MeshComponent>(Ref<Mesh>(asset));
SelectEntity(entity);
selection.Mesh->Transform = glm::inverse(entityTransform.GetTransform()) * transformBase;
}
}
}
ImGui::EndDragDropTarget();
// ImZmoToolBar
{
const float iconSize = 28.0f;
const float padding = 6.0f;
const ImU32 backgroundColor = IM_COL32(30, 30, 30, 140);
const ImVec4 orangeMain = ImVec4(0.92f, 0.45f, 0.11f, 0.8f);
ImGuiChildFlags child_flags = ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY;
ImGuiWindowFlags Gizmo_window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground;
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 6.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(padding, padding));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 0));
ImGui::SetCursorPos(ImVec2(10.0f, viewportOffset.y + 10.0f));
if (m_SceneState != SceneState::Play)
{
if (ImGui::BeginChild("GizmoToolbar", ImVec2(0, 0), child_flags, Gizmo_window_flags))
{
ImDrawList *draw_list = ImGui::GetWindowDrawList();
draw_list->AddRectFilled(ImGui::GetWindowPos(),
ImVec2(ImGui::GetWindowPos().x + ImGui::GetWindowWidth(), ImGui::GetWindowPos().y + ImGui::GetWindowHeight()),
backgroundColor, 6.0f);
auto drawGizmoBtn = [&](const char *label, int type, const char *tooltip)
{
bool isActive = (m_GizmoType == type);
if (isActive)
ImGui::PushStyleColor(ImGuiCol_Button, orangeMain);
else
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
if (ImGui::Button(label, ImVec2(iconSize, iconSize)))
m_GizmoType = type;
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort))
ImGui::SetTooltip("%s", tooltip);
ImGui::PopStyleColor();
};
drawGizmoBtn("Q", -1, "Select (Q)");
ImGui::SameLine();
drawGizmoBtn("W", (int)ImGuizmo::TRANSLATE, "Translate (W)");
ImGui::SameLine();
drawGizmoBtn("E", (int)ImGuizmo::ROTATE, "Rotate (E)");
ImGui::SameLine();
drawGizmoBtn("R", (int)ImGuizmo::SCALE, "Scale (R)");
}
ImGui::EndChild();
}
float centerX = minBound.x + viewportOffset.x + viewportSize.x * 0.5f;
float topY = minBound.y + 10.0f;
ImGui::SetNextWindowPos(ImVec2(centerX, topY), ImGuiCond_Always, ImVec2(0.5f, 0.0f));
if (ImGui::BeginChild("DebugButton", ImVec2(0, 0), child_flags, Gizmo_window_flags))
{
ImDrawList *draw_list = ImGui::GetWindowDrawList();
draw_list->AddRectFilled(ImGui::GetWindowPos(),
ImVec2(ImGui::GetWindowPos().x + ImGui::GetWindowWidth(), ImGui::GetWindowPos().y + ImGui::GetWindowHeight()),
backgroundColor, 6.0f);
// Scene control buttons
const bool toolbarEnabled = (bool)m_CurrentScene;
ImVec4 tintColor = toolbarEnabled ? ImVec4(1, 1, 1, 1) : ImVec4(1, 1, 1, 0.5f);
bool isEdit = m_SceneState == SceneState::Edit;
bool isPlay = m_SceneState == SceneState::Play;
// bool isSim = m_SceneState == SceneState::Pause;
auto drawImgBtn = [&](const char *id, Ref<Texture2D> iconRef, ImVec4 bg, auto func)
{
ImGui::PushStyleColor(ImGuiCol_Button, bg);
const auto textureID = (ImTextureID)(uintptr_t)iconRef->GetRendererID();
if (ImGui::ImageButton(id, textureID, ImVec2(iconSize - 6, iconSize - 6), {0, 0}, {1, 1}, {0, 0, 0, 0}, tintColor))
{
if (toolbarEnabled)
func();
}
ImGui::PopStyleColor();
};
if (isEdit)
{
drawImgBtn("##Play", m_PlayButtonTex, ImVec4(0, 0, 0, 0), [this]()
{ OnScenePlay(); });
}
else if (isPlay)
{
drawImgBtn("##Stop", m_StopButtonTex, ImVec4(0.8f, 0.1f, 0.1f, 0.6f), [this]()
{ OnSceneStop(); });
}
}
ImGui::EndChild();
ImGui::PopStyleVar(3);
}
// ImViewGuizmo
if (m_SceneState != SceneState::Play)
{
ImViewGuizmo::BeginFrame();
auto &style = ImViewGuizmo::GetStyle();
style.scale = 0.8f;
const float gizmoSize = 256.0f * style.scale;
const float inset = gizmoSize * 0.1f;
const ImVec2 gizmoCenter = ImVec2(
maxBound.x - gizmoSize * 0.5f + inset,
minBound.y + gizmoSize * 0.5f - inset);
glm::vec3 cameraPos = m_EditorCamera.GetPosition();
glm::vec3 focusPosition = m_EditorCamera.GetFocusPosition();
float CameraYaw = m_EditorCamera.GetYaw();
float CameraPitch = -m_EditorCamera.GetPitch();
glm::quat qYaw = glm::angleAxis(CameraYaw, glm::vec3(0.0f, 1.0f, 0.0f));
glm::quat qPitch = glm::angleAxis(CameraPitch, glm::vec3(1.0f, 0.0f, 0.0f));
glm::quat cameraRot = qYaw * qPitch;
if (ImViewGuizmo::Rotate(cameraPos, cameraRot, glm::vec3(0.0f), gizmoCenter))
{
glm::vec3 forward = cameraRot * glm::vec3(0.0f, 0.0f, -1.0f);
float newPitch = glm::asin(glm::clamp(-forward.y, -1.0f, 1.0f));
float newYaw = -glm::atan(forward.x, -forward.z);
float distance = glm::length(cameraPos - focusPosition);
m_EditorCamera.SetDistance(distance);
m_EditorCamera.SetFocusPosition(focusPosition);
m_EditorCamera.SetYawPitch(newYaw, newPitch);
}
}
if (m_RuntimeScene)
m_RuntimeScene->SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
}
}
@ -756,7 +909,7 @@ namespace Prism
break;
Entity selectedEntity = m_SelectionContext[0].Entity;
m_EditorCamera.Focus(selectedEntity.Transform().Translation);
m_EditorCamera.SetFocusPosition(selectedEntity.Transform().Translation);
break;
}
}
@ -1059,23 +1212,25 @@ namespace Prism
m_RuntimeScene = Ref<Scene>::Create();
m_EditorScene->CopyTo(m_RuntimeScene);
m_RuntimeScene->OnRuntimeStart();
m_SceneHierarchyPanel->SetContext(m_RuntimeScene);
m_CurrentScene = m_RuntimeScene;
m_SceneHierarchyPanel->SetContext(m_CurrentScene);
m_CurrentScene->OnRuntimeStart();
}
void EditorLayer::OnSceneStop()
{
m_RuntimeScene->OnRuntimeStop();
m_CurrentScene->OnRuntimeStop();
m_SceneState = SceneState::Edit;
// Unload runtime scene
m_RuntimeScene = nullptr;
m_SelectionContext.clear();
ScriptEngine::SetSceneContext(m_EditorScene);
m_SceneHierarchyPanel->SetContext(m_EditorScene);
m_CurrentScene = m_EditorScene;
ScriptEngine::SetSceneContext(m_CurrentScene);
m_SceneHierarchyPanel->SetContext(m_CurrentScene);
}
float EditorLayer::GetSnapValue() const

View File

@ -12,9 +12,8 @@ uniform mat4 u_Projection;
uniform vec3 u_CameraPosition;
out CameraData{
mat4 View;
mat4 Projection;
vec3 CameraPosition;
mat4 ViewProjection;
vec3 Position;
}CameraOutput;
out vec3 v_NearPoint;
@ -31,9 +30,8 @@ void main() {
v_NearPoint = unprojectPoint(a_Position.x, a_Position.y, 0.0);
v_FarPoint = unprojectPoint(a_Position.x, a_Position.y, 1.0);
CameraOutput.View = u_View;
CameraOutput.Projection = u_Projection;
CameraOutput.CameraPosition = u_CameraPosition;
CameraOutput.ViewProjection = u_Projection * u_View;
CameraOutput.Position = u_CameraPosition;
gl_Position = vec4(a_Position, 1.0);
}
@ -47,22 +45,21 @@ in vec3 v_NearPoint;
in vec3 v_FarPoint;
in CameraData{
mat4 View;
mat4 Projection;
vec3 CameraPosition;
mat4 ViewProjection;
vec3 Position;
}CameraInput;
// Grid plane: 0 = XZ (Y up), 1 = XY (Z forward), 2 = YZ (X right)
uniform int u_GridPlane = 0;
uniform float u_GridScale = 1.0;
uniform vec4 u_GridColorThin = vec4(0.5, 0.5, 0.5, 0.4);
uniform vec4 u_GridColorThick = vec4(0.5, 0.5, 0.5, 0.6);
uniform vec4 u_AxisColorX = vec4(0.9, 0.2, 0.2, 1.0);
uniform vec4 u_AxisColorZ = vec4(0.2, 0.2, 0.9, 1.0);
uniform float u_FadeDistance = 500.0;
uniform int u_GridPlane;
uniform float u_GridScale;
uniform vec4 u_GridColorThin;
uniform vec4 u_GridColorThick;
uniform vec4 u_AxisColorX;
uniform vec4 u_AxisColorZ;
uniform float u_FadeDistance;
float computeDepth(vec3 pos) {
vec4 clipSpacePos = CameraInput.Projection * CameraInput.View * vec4(pos, 1.0);
vec4 clipSpacePos = CameraInput.ViewProjection * vec4(pos, 1.0);
return clipSpacePos.z / clipSpacePos.w;
}
@ -155,11 +152,11 @@ void main() {
// === Fading ===
// Radial fade
float dist = length(fragPos3D - CameraInput.CameraPosition);
float dist = length(fragPos3D - CameraInput.Position);
float radialFade = 1.0 - smoothstep(u_FadeDistance * 0.3, u_FadeDistance, dist);
// Normal fade (view angle)
vec3 viewDir = normalize(fragPos3D - CameraInput.CameraPosition);
vec3 viewDir = normalize(fragPos3D - CameraInput.Position);
float viewAngle = getViewAngleComponent(viewDir);
float normalFade = smoothstep(0.0, 0.15, viewAngle);
@ -179,7 +176,8 @@ void main() {
// LOD blend
vec2 deriv1 = fwidth(gridCoord1);
float lodFactor = smoothstep(0.3, 0.6, max(deriv1.x, deriv1.y));
float lodFactor = smoothstep(20.0, 200.0, dist);
// float lodFactor = smoothstep(0.2, 0.5, max(deriv1.x, deriv1.y));
// Combine grids
float gridIntensity = mix(max(grid1, grid10 * 0.7), grid10, lodFactor);