Fix selection outline never showing for the first entity
entt entity 0's integral bits are 0, colliding with the "no selection"
sentinel: u32 selected == 0 meant "clear selection", so the scene's
first-created entity could never be outlined. Replaced with
std::optional<u32> + FrameSceneData::selectedEntityValid.
Also restore per-batch instance contiguity broken by the batchMats
flattening (e038cb3): entities sharing a mesh scatter across the flat
instance array in collection order. ViewScratch now tracks per-batch
singly-linked lists and appendView aggregates each batch into a
contiguous range, preserving the flat-array performance intent.
Hierarchy click selection now routes through SelectEntity so outline
stays in sync when picking from the panel.
This commit is contained in:
@@ -164,9 +164,10 @@ namespace Engine {
|
||||
std::optional<u32> TakePickResult();
|
||||
|
||||
// ---- Editor 选中描边(UE 编辑器选中轮廓)----
|
||||
// UI 段选中变化时调用(bits = 实体位模式,0 = 清选中);
|
||||
// 下一帧 SelectionMask 只画该实体,Outline 在其轮廓叠加描边色
|
||||
void SetSelectedEntity(u32 entityBits);
|
||||
// UI 段选中变化时调用;下一帧 SelectionMask 只画该实体,Outline
|
||||
// 在其轮廓叠加描边色。nullopt = 清选中(实体 0 号位模式 = 0,
|
||||
// 不能拿位值兼作哨兵)
|
||||
void SetSelectedEntity(std::optional<u32> entityBits);
|
||||
|
||||
// 垂直同步开关(present mode 切换会重建 swapchain),
|
||||
// 只应在帧 UI 构建段调用(Render 之前)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <Engine/Renderer/EditorCamera.h>
|
||||
@@ -73,8 +74,12 @@ namespace Engine {
|
||||
{
|
||||
m_PendingPick = PickRequest{true, ndc};
|
||||
}
|
||||
// Editor 选中实体(描边):UI 段写入,BuildFrame 落帧并筛出绘制
|
||||
void SetSelectedEntity(u32 entityBits) { m_PendingSelected = entityBits; }
|
||||
// Editor 选中实体(描边):UI 段写入,BuildFrame 落帧并筛出绘制。
|
||||
// nullopt = 清选中(实体 0 号位模式 = 0,不能拿位值兼作哨兵)
|
||||
void SetSelectedEntity(std::optional<u32> entityBits)
|
||||
{
|
||||
m_PendingSelected = entityBits;
|
||||
}
|
||||
|
||||
private:
|
||||
// CSM:把相机视锥按实用分割切 N 段,每段独立拟合光源正交投影
|
||||
@@ -91,7 +96,7 @@ namespace Engine {
|
||||
FrameSceneData m_Frame;
|
||||
EditorCamera m_EditorCamera; // 编辑器相机(视口 UI 状态,见 GetEditorCamera)
|
||||
PickRequest m_PendingPick{}; // 拾取请求缓冲(BuildFrame 落帧后清除)
|
||||
u32 m_PendingSelected = 0; // 选中实体缓冲(描边)
|
||||
std::optional<u32> m_PendingSelected; // 选中实体缓冲(nullopt = 无选中)
|
||||
|
||||
// ---- 剔除中间量(每帧 clear 复用,拼接进 m_Frame 后保留容量)----
|
||||
struct ViewScratch {
|
||||
@@ -102,12 +107,18 @@ namespace Engine {
|
||||
u32 skinBase = 0; // palette 区段基址(0 = identity 槽)
|
||||
u32 entityBits = 0; // 实体位模式(HitProxy id pass 消费)
|
||||
};
|
||||
// 链表尾哨兵:kMaxInstances 远小于 u32 最大值,安全
|
||||
static constexpr u32 kNoInstance = 0xFFFFFFFFu;
|
||||
CullResult result;
|
||||
// 扁平实例数组(所有 batch 的实例共用一份连续内存)。
|
||||
// InstanceBatch::first/count 在本数组里切片——大场景下避免
|
||||
// vector<vector> 的小块分配(每个 batch 自己一个 vector,push_back
|
||||
// 触发各自重分配,cache miss 严重)。每帧 clear() 复用容量
|
||||
// 实体收集序下同 batch 实例会散布(多实体共享 mesh 交错插入),
|
||||
// 组内连接关系由 instanceNext 链表维护——appendView 时按 batch
|
||||
// 聚合拷成连续区间(firstInstance 连续语义的前提)。大场景下
|
||||
// 避免 vector<vector> 的小块分配,每帧 clear() 复用容量
|
||||
std::vector<InstanceMatrices> instances;
|
||||
std::vector<u32> instanceNext; // 与 instances 平行:同 batch 下一实例
|
||||
// 每 batch 实例链头(与 result.batches 平行;kNoInstance = 空)
|
||||
std::vector<u32> batchHead;
|
||||
// 每 batch 实例距离累加(透明排序用:平均距离降序 = 远→近)
|
||||
std::vector<f32> batchDistSum;
|
||||
// batch 查找:数组寻址(下标 = Mesh::GetSlot(),值 = 每 LOD 的
|
||||
@@ -119,6 +130,8 @@ namespace Engine {
|
||||
result.batches.clear();
|
||||
result.instanceCount = 0;
|
||||
instances.clear(); // 容量保留,复用
|
||||
instanceNext.clear();
|
||||
batchHead.clear();
|
||||
batchDistSum.clear();
|
||||
for (auto& e : lookup) e.fill(0); // 容量保留,置零复用
|
||||
}
|
||||
|
||||
@@ -167,9 +167,12 @@ namespace Engine {
|
||||
// HitProxy/HitProxyCopy 两 pass 据此决定是否绘制/拷贝)
|
||||
PickRequest pickRequest{};
|
||||
|
||||
// 选中描边(UE 编辑器语义):选中实体的位模式(0 = 无选中)。
|
||||
// 选中描边(UE 编辑器语义):选中实体 + 位模式。位模式不能兼作
|
||||
// "无选中"哨兵——entt 首个实体 0 号的 to_integral == 0("点击
|
||||
// 场景第一个创建的实体没有描边"的根因),有效性与位值解耦。
|
||||
// BuildFrame 据此从实例表筛出 selectionDraws,SelectionMask pass
|
||||
// 只画选中实体 → Outline pass 在 mask 边缘叠加描边色
|
||||
bool selectedEntityValid = false;
|
||||
u32 selectedEntityBits = 0;
|
||||
std::vector<SelectionDraw> selectionDraws;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user