feat(editor): add scene view selection markers

This commit is contained in:
ayuan9957 2026-06-23 16:09:40 +08:00
parent 922858b135
commit b12c88c478

View File

@ -4,6 +4,7 @@
#include "MetaCoreEditor/MetaCoreEditorServices.h"
#include "MetaCoreFoundation/MetaCoreProject.h"
#include "MetaCoreEditorCameraController.h"
#include "MetaCoreScene/MetaCoreTransformUtils.h"
#include <imgui.h>
#include <imgui_internal.h>
@ -21,6 +22,7 @@
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <array>
#include <cmath>
#include <exception>
#include <filesystem>
@ -297,6 +299,26 @@ bool MetaCoreProjectWorldPointToViewport(
return true;
}
glm::mat4 MetaCoreBuildEditorOverlayWorldMatrix(const MetaCoreScene& scene, MetaCoreId objectId) {
const MetaCoreGameObject object = scene.FindGameObject(objectId);
if (!object) {
return glm::mat4(1.0F);
}
glm::mat4 worldMatrix = MetaCoreBuildTransformMatrix(object.GetComponent<MetaCoreTransformComponent>());
MetaCoreId parentId = object.GetParentId();
while (parentId != 0) {
const MetaCoreGameObject parentObject = scene.FindGameObject(parentId);
if (!parentObject) {
break;
}
worldMatrix = MetaCoreBuildTransformMatrix(parentObject.GetComponent<MetaCoreTransformComponent>()) * worldMatrix;
parentId = parentObject.GetParentId();
}
return worldMatrix;
}
void MetaCoreDrawWorldOriginOverlay(
const MetaCoreEditorContext&,
const MetaCoreSceneView&,
@ -459,13 +481,112 @@ void MetaCoreDrawViewportGridOverlay(
}
void MetaCoreDrawSelectionBoundsOverlay(
const MetaCoreEditorContext&,
const MetaCoreScene&,
const MetaCoreSceneView&,
const MetaCoreSceneViewportState&
const MetaCoreEditorContext& editorContext,
const MetaCoreScene& scene,
const MetaCoreSceneView& sceneView,
const MetaCoreSceneViewportState& viewportState
) {
// 用户要求去掉左下角的黄色框和文字
return;
if (!editorContext.GetShowViewportSelectionOverlay() || viewportState.Width <= 1.0F || viewportState.Height <= 1.0F) {
return;
}
ImDrawList* drawList = ImGui::GetForegroundDrawList();
const ImVec2 clipMin(viewportState.Left, viewportState.Top);
const ImVec2 clipMax(viewportState.Left + viewportState.Width, viewportState.Top + viewportState.Height);
const auto drawObjectMarker = [&](MetaCoreId objectId, ImU32 color, float thickness, float minimumSize) {
const MetaCoreGameObject gameObject = scene.FindGameObject(objectId);
if (!gameObject) {
return;
}
if (gameObject.HasComponent<MetaCoreMeshRendererComponent>() && !gameObject.GetComponent<MetaCoreMeshRendererComponent>().Visible) {
return;
}
const glm::mat4 worldMatrix = MetaCoreBuildEditorOverlayWorldMatrix(scene, objectId);
const std::array<glm::vec3, 8> localCorners = {
glm::vec3(-0.5F, -0.5F, -0.5F),
glm::vec3( 0.5F, -0.5F, -0.5F),
glm::vec3(-0.5F, 0.5F, -0.5F),
glm::vec3( 0.5F, 0.5F, -0.5F),
glm::vec3(-0.5F, -0.5F, 0.5F),
glm::vec3( 0.5F, -0.5F, 0.5F),
glm::vec3(-0.5F, 0.5F, 0.5F),
glm::vec3( 0.5F, 0.5F, 0.5F)
};
bool anyPointVisible = false;
ImVec2 minPoint(FLT_MAX, FLT_MAX);
ImVec2 maxPoint(-FLT_MAX, -FLT_MAX);
for (const glm::vec3& localCorner : localCorners) {
const glm::vec3 worldCorner = glm::vec3(worldMatrix * glm::vec4(localCorner, 1.0F));
ImVec2 screenPoint{};
if (!MetaCoreProjectWorldPointToViewport(sceneView, viewportState, worldCorner, screenPoint)) {
continue;
}
anyPointVisible = true;
minPoint.x = std::min(minPoint.x, screenPoint.x);
minPoint.y = std::min(minPoint.y, screenPoint.y);
maxPoint.x = std::max(maxPoint.x, screenPoint.x);
maxPoint.y = std::max(maxPoint.y, screenPoint.y);
}
if (!anyPointVisible) {
const glm::vec3 worldPosition = glm::vec3(worldMatrix[3]);
ImVec2 screenPoint{};
if (!MetaCoreProjectWorldPointToViewport(sceneView, viewportState, worldPosition, screenPoint)) {
return;
}
minPoint = screenPoint;
maxPoint = screenPoint;
}
const float halfMinimumSize = minimumSize * 0.5F;
if (maxPoint.x - minPoint.x < minimumSize) {
const float centerX = (minPoint.x + maxPoint.x) * 0.5F;
minPoint.x = centerX - halfMinimumSize;
maxPoint.x = centerX + halfMinimumSize;
}
if (maxPoint.y - minPoint.y < minimumSize) {
const float centerY = (minPoint.y + maxPoint.y) * 0.5F;
minPoint.y = centerY - halfMinimumSize;
maxPoint.y = centerY + halfMinimumSize;
}
minPoint.x = std::clamp(minPoint.x, clipMin.x, clipMax.x);
minPoint.y = std::clamp(minPoint.y, clipMin.y, clipMax.y);
maxPoint.x = std::clamp(maxPoint.x, clipMin.x, clipMax.x);
maxPoint.y = std::clamp(maxPoint.y, clipMin.y, clipMax.y);
if (maxPoint.x <= minPoint.x || maxPoint.y <= minPoint.y) {
return;
}
const float bracketLength = std::min({18.0F, (maxPoint.x - minPoint.x) * 0.35F, (maxPoint.y - minPoint.y) * 0.35F});
drawList->AddLine(minPoint, ImVec2(minPoint.x + bracketLength, minPoint.y), color, thickness);
drawList->AddLine(minPoint, ImVec2(minPoint.x, minPoint.y + bracketLength), color, thickness);
drawList->AddLine(ImVec2(maxPoint.x, minPoint.y), ImVec2(maxPoint.x - bracketLength, minPoint.y), color, thickness);
drawList->AddLine(ImVec2(maxPoint.x, minPoint.y), ImVec2(maxPoint.x, minPoint.y + bracketLength), color, thickness);
drawList->AddLine(ImVec2(minPoint.x, maxPoint.y), ImVec2(minPoint.x + bracketLength, maxPoint.y), color, thickness);
drawList->AddLine(ImVec2(minPoint.x, maxPoint.y), ImVec2(minPoint.x, maxPoint.y - bracketLength), color, thickness);
drawList->AddLine(maxPoint, ImVec2(maxPoint.x - bracketLength, maxPoint.y), color, thickness);
drawList->AddLine(maxPoint, ImVec2(maxPoint.x, maxPoint.y - bracketLength), color, thickness);
};
drawList->PushClipRect(clipMin, clipMax, true);
const MetaCoreId hoveredObjectId = editorContext.GetHoveredObjectId();
if (hoveredObjectId != 0 && !editorContext.IsObjectSelected(hoveredObjectId)) {
drawObjectMarker(hoveredObjectId, IM_COL32(110, 175, 255, 190), 1.5F, 18.0F);
}
for (const MetaCoreId selectedObjectId : editorContext.GetSelectedObjectIds()) {
const bool isActiveObject = selectedObjectId == editorContext.GetActiveObjectId();
drawObjectMarker(
selectedObjectId,
isActiveObject ? IM_COL32(235, 87, 87, 245) : IM_COL32(235, 135, 135, 205),
isActiveObject ? 2.0F : 1.5F,
22.0F
);
}
drawList->PopClipRect();
}
void MetaCoreDrawCompatibilityScenePreviewOverlay(