Formalize editor skybox wiring and debug presets

This commit is contained in:
2026-04-06 03:28:20 +08:00
parent c7dc8d7484
commit 3547597bd2
12 changed files with 324 additions and 103 deletions

View File

@@ -378,7 +378,7 @@ bool SceneViewportEditorOverlayPassRenderer::Render(
const Rendering::RenderContext& renderContext,
const Rendering::RenderSurface& surface,
const SceneViewportOverlayFrameData& frameData) {
if (!frameData.HasOverlayPrimitives() || !renderContext.IsValid() || renderContext.commandList == nullptr) {
if (!frameData.HasRenderPassPrimitives() || !renderContext.IsValid() || renderContext.commandList == nullptr) {
return true;
}
@@ -411,33 +411,10 @@ bool SceneViewportEditorOverlayPassRenderer::Render(
AppendScreenTriangleVertices(targetVertices, triangle);
}
std::vector<const SceneViewportOverlaySpritePrimitive*> depthTestedSprites = {};
std::vector<const SceneViewportOverlaySpritePrimitive*> alwaysOnTopSprites = {};
depthTestedSprites.reserve(frameData.worldSprites.size());
alwaysOnTopSprites.reserve(frameData.worldSprites.size());
for (const SceneViewportOverlaySpritePrimitive& sprite : frameData.worldSprites) {
if (sprite.sizePixels.x <= Math::EPSILON || sprite.sizePixels.y <= Math::EPSILON) {
continue;
}
if (sprite.depthMode == SceneViewportOverlayDepthMode::DepthTested) {
depthTestedSprites.push_back(&sprite);
} else {
alwaysOnTopSprites.push_back(&sprite);
}
}
const auto sortBackToFront =
[](const SceneViewportOverlaySpritePrimitive* lhs, const SceneViewportOverlaySpritePrimitive* rhs) {
return lhs->sortDepth > rhs->sortDepth;
};
std::sort(depthTestedSprites.begin(), depthTestedSprites.end(), sortBackToFront);
std::sort(alwaysOnTopSprites.begin(), alwaysOnTopSprites.end(), sortBackToFront);
const size_t lineVertexCount = depthTestedLineVertices.size() + alwaysOnTopLineVertices.size();
const size_t screenTriangleVertexCount =
depthTestedScreenTriangleVertices.size() + alwaysOnTopScreenTriangleVertices.size();
const size_t spriteVertexCount = (depthTestedSprites.size() + alwaysOnTopSprites.size()) * 6u;
const size_t spriteVertexCount = 0u;
if (lineVertexCount == 0u && screenTriangleVertexCount == 0u && spriteVertexCount == 0u) {
return true;
}
@@ -471,35 +448,6 @@ bool SceneViewportEditorOverlayPassRenderer::Render(
screenTriangleVertices.size() * sizeof(OverlayScreenTriangleVertex));
}
std::vector<OverlaySpriteVertex> spriteVertices = {};
std::array<OverlaySpriteBatchRange, kSceneViewportOverlaySpriteResourceCount> depthTestedSpriteBatches = {};
std::array<OverlaySpriteBatchRange, kSceneViewportOverlaySpriteResourceCount> alwaysOnTopSpriteBatches = {};
if (spriteVertexCount > 0u) {
spriteVertices.reserve(spriteVertexCount);
const auto appendSpriteBatches =
[&spriteVertices](
const std::vector<const SceneViewportOverlaySpritePrimitive*>& sprites,
std::array<OverlaySpriteBatchRange, kSceneViewportOverlaySpriteResourceCount>& outBatches) {
for (size_t textureIndex = 0; textureIndex < kSceneViewportOverlaySpriteResourceCount; ++textureIndex) {
OverlaySpriteBatchRange range = {};
range.firstVertex = static_cast<uint32_t>(spriteVertices.size());
for (const SceneViewportOverlaySpritePrimitive* sprite : sprites) {
if (sprite == nullptr ||
GetSceneViewportOverlaySpriteResourceIndex(sprite->textureKind) != textureIndex) {
continue;
}
AppendSpriteVertices(spriteVertices, *sprite);
}
range.vertexCount = static_cast<uint32_t>(spriteVertices.size()) - range.firstVertex;
outBatches[textureIndex] = range;
}
};
appendSpriteBatches(depthTestedSprites, depthTestedSpriteBatches);
appendSpriteBatches(alwaysOnTopSprites, alwaysOnTopSpriteBatches);
m_spriteVertexBuffer->SetData(spriteVertices.data(), spriteVertices.size() * sizeof(OverlaySpriteVertex));
}
OverlayConstants constants = {};
constants.viewProjection = BuildSceneViewportViewProjectionMatrix(
frameData.overlay,
@@ -564,49 +512,6 @@ bool SceneViewportEditorOverlayPassRenderer::Render(
}
}
if (spriteVertexCount > 0u) {
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
RHI::RHIResourceView* vertexBuffers[] = { m_spriteVertexBufferView };
const uint64_t offsets[] = { 0u };
const uint32_t strides[] = { static_cast<uint32_t>(sizeof(OverlaySpriteVertex)) };
commandList->SetVertexBuffers(0, 1, vertexBuffers, offsets, strides);
const auto drawSpriteBatchGroup =
[this, commandList](
RHI::RHIPipelineState* pipelineState,
const std::array<OverlaySpriteBatchRange, kSceneViewportOverlaySpriteResourceCount>& batches) {
if (pipelineState == nullptr) {
return;
}
commandList->SetPipelineState(pipelineState);
for (size_t textureIndex = 0; textureIndex < kSceneViewportOverlaySpriteResourceCount; ++textureIndex) {
const OverlaySpriteBatchRange& batch = batches[textureIndex];
if (!batch.HasVertices()) {
continue;
}
RHI::RHIDescriptorSet* const textureSet =
m_overlaySpriteResources.GetTextureSet(
GetSceneViewportOverlaySpriteTextureKindByIndex(textureIndex));
if (textureSet == nullptr) {
continue;
}
RHI::RHIDescriptorSet* descriptorSets[] = {
m_constantSet,
textureSet,
m_samplerSet
};
commandList->SetGraphicsDescriptorSets(0, 3, descriptorSets, m_spritePipelineLayout);
commandList->Draw(batch.vertexCount, 1, batch.firstVertex, 0);
}
};
drawSpriteBatchGroup(m_depthTestedSpritePipelineState, depthTestedSpriteBatches);
drawSpriteBatchGroup(m_alwaysOnTopSpritePipelineState, alwaysOnTopSpriteBatches);
}
if (screenTriangleVertexCount > 0u) {
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
RHI::RHIResourceView* vertexBuffers[] = { m_screenTriangleVertexBufferView };

View File

@@ -110,6 +110,10 @@ struct SceneViewportOverlayFrameData {
return overlay.valid && (!worldLines.empty() || !worldSprites.empty() || !screenTriangles.empty());
}
bool HasRenderPassPrimitives() const {
return overlay.valid && (!worldLines.empty() || !screenTriangles.empty());
}
bool HasWorldOverlay() const {
return HasOverlayPrimitives();
}

View File

@@ -1,6 +1,12 @@
#include "SceneViewportHudOverlay.h"
#include "SceneViewportOrientationGizmo.h"
#include "SceneViewportMath.h"
#include "UI/BuiltInIcons.h"
#include <algorithm>
#include <vector>
namespace XCEngine {
namespace Editor {
@@ -11,6 +17,97 @@ bool IsViewportRectValid(const ImVec2& viewportMin, const ImVec2& viewportMax) {
viewportMax.y - viewportMin.y > 1.0f;
}
bool DrawSceneViewportSpriteIcon(
ImDrawList* drawList,
const ImVec2& min,
const ImVec2& max,
SceneViewportOverlaySpriteTextureKind textureKind) {
switch (textureKind) {
case SceneViewportOverlaySpriteTextureKind::Camera:
return UI::DrawEditorTextureIcon(
drawList,
min,
max,
UI::EditorTextureIconKind::CameraGizmo);
case SceneViewportOverlaySpriteTextureKind::Light:
return UI::DrawEditorTextureIcon(
drawList,
min,
max,
UI::EditorTextureIconKind::MainLightGizmo);
default:
return false;
}
}
void DrawSceneViewportSceneIcons(
ImDrawList* drawList,
const SceneViewportHudOverlayData& overlay,
const ImVec2& viewportMin,
const ImVec2& viewportMax) {
if (drawList == nullptr ||
!overlay.showSceneIcons ||
overlay.overlayFrameData == nullptr ||
overlay.overlayFrameData->worldSprites.empty()) {
return;
}
const float viewportWidth = viewportMax.x - viewportMin.x;
const float viewportHeight = viewportMax.y - viewportMin.y;
if (viewportWidth <= 1.0f || viewportHeight <= 1.0f) {
return;
}
std::vector<const SceneViewportOverlaySpritePrimitive*> sortedSprites = {};
sortedSprites.reserve(overlay.overlayFrameData->worldSprites.size());
for (const SceneViewportOverlaySpritePrimitive& sprite : overlay.overlayFrameData->worldSprites) {
sortedSprites.push_back(&sprite);
}
std::sort(
sortedSprites.begin(),
sortedSprites.end(),
[](const SceneViewportOverlaySpritePrimitive* lhs, const SceneViewportOverlaySpritePrimitive* rhs) {
if (lhs == rhs) {
return false;
}
if (lhs == nullptr) {
return false;
}
if (rhs == nullptr) {
return true;
}
return lhs->sortDepth > rhs->sortDepth;
});
for (const SceneViewportOverlaySpritePrimitive* sprite : sortedSprites) {
if (sprite == nullptr ||
sprite->sizePixels.x <= Math::EPSILON ||
sprite->sizePixels.y <= Math::EPSILON) {
continue;
}
const SceneViewportProjectedPoint projectedPoint = ProjectSceneViewportWorldPoint(
overlay.sceneOverlay,
viewportWidth,
viewportHeight,
sprite->worldPosition);
if (!projectedPoint.visible) {
continue;
}
const ImVec2 halfSize(sprite->sizePixels.x * 0.5f, sprite->sizePixels.y * 0.5f);
const ImVec2 center(
viewportMin.x + projectedPoint.screenPosition.x,
viewportMin.y + projectedPoint.screenPosition.y);
DrawSceneViewportSpriteIcon(
drawList,
ImVec2(center.x - halfSize.x, center.y - halfSize.y),
ImVec2(center.x + halfSize.x, center.y + halfSize.y),
sprite->textureKind);
}
}
} // namespace
void DrawSceneViewportHudOverlay(
@@ -25,6 +122,11 @@ void DrawSceneViewportHudOverlay(
}
drawList->PushClipRect(viewportMin, viewportMax, true);
DrawSceneViewportSceneIcons(
drawList,
overlay,
viewportMin,
viewportMax);
if (overlay.showOrientationGizmo) {
DrawSceneViewportOrientationGizmo(
drawList,

View File

@@ -1,6 +1,6 @@
#pragma once
#include "IViewportHostService.h"
#include "SceneViewportEditorOverlayData.h"
#include <imgui.h>
@@ -26,18 +26,28 @@ struct SceneViewportHudOverlayHitResult {
struct SceneViewportHudOverlayData {
SceneViewportOverlayData sceneOverlay = {};
bool showOrientationGizmo = true;
bool showSceneIcons = true;
const SceneViewportOverlayFrameData* overlayFrameData = nullptr;
bool HasVisibleElements() const {
return sceneOverlay.valid && showOrientationGizmo;
return sceneOverlay.valid &&
(showOrientationGizmo ||
(showSceneIcons &&
overlayFrameData != nullptr &&
!overlayFrameData->worldSprites.empty()));
}
};
inline SceneViewportHudOverlayData BuildSceneViewportHudOverlayData(
const SceneViewportOverlayData& sceneOverlay,
bool showOrientationGizmo = true) {
bool showOrientationGizmo = true,
const SceneViewportOverlayFrameData* overlayFrameData = nullptr,
bool showSceneIcons = true) {
SceneViewportHudOverlayData data = {};
data.sceneOverlay = sceneOverlay;
data.showOrientationGizmo = showOrientationGizmo;
data.showSceneIcons = showSceneIcons;
data.overlayFrameData = overlayFrameData;
return data;
}

View File

@@ -143,6 +143,7 @@ inline bool ShouldFocusSceneViewportAfterInteraction(
struct SceneViewportPresentationRequest {
IEditorContext* context = nullptr;
IViewportHostService* viewportHostService = nullptr;
const SceneViewportOverlayFrameData* overlayFrameData = nullptr;
bool hasInteractiveViewport = false;
SceneViewportFrameGeometry geometry = {};
SceneViewportTransformGizmoFrameOptions gizmoFrameOptions = {};
@@ -182,7 +183,10 @@ inline void RefreshAndDrawSceneViewportPresentation(const SceneViewportPresentat
DrawSceneViewportHudOverlay(
request.drawList,
BuildSceneViewportHudOverlayData(overlay),
BuildSceneViewportHudOverlayData(
overlay,
true,
request.overlayFrameData),
request.viewportMin,
request.viewportMax);
}

View File

@@ -84,7 +84,7 @@ inline SceneViewportRenderPlanBuildResult BuildSceneViewportRenderPlan(
}
}
if (editorOverlayFrameData.HasOverlayPrimitives() &&
if (editorOverlayFrameData.HasRenderPassPrimitives() &&
overlayPassFactory != nullptr) {
std::unique_ptr<Rendering::RenderPass> overlayPass = overlayPassFactory(editorOverlayFrameData);
if (overlayPass != nullptr) {