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:
+10
-1
@@ -131,7 +131,16 @@ void Editor::Draw()
|
|||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
// 常规面板窗口(窗口名 = docking 身份)
|
// 常规面板窗口(窗口名 = docking 身份)
|
||||||
if (m_ShowHierarchy) m_Hierarchy->Draw(m_Ctx, m_Selected);
|
if (m_ShowHierarchy)
|
||||||
|
{
|
||||||
|
const entt::entity prev = m_Selected;
|
||||||
|
m_Hierarchy->Draw(m_Ctx, m_Selected);
|
||||||
|
// 树点选同步描边(面板直写 m_Selected,不走 Viewport 的
|
||||||
|
// SelectEntity 返回值通道;对比前后变化触发)
|
||||||
|
if (m_Selected != prev) {
|
||||||
|
SelectEntity(m_Selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (m_ShowInspector) m_Inspector->Draw(m_Ctx, m_Selected);
|
if (m_ShowInspector) m_Inspector->Draw(m_Ctx, m_Selected);
|
||||||
if (m_ShowViewport)
|
if (m_ShowViewport)
|
||||||
{
|
{
|
||||||
|
|||||||
+7
-4
@@ -21,6 +21,7 @@
|
|||||||
#include <entt/entt.hpp>
|
#include <entt/entt.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
class HierarchyPanel;
|
class HierarchyPanel;
|
||||||
class InspectorPanel;
|
class InspectorPanel;
|
||||||
@@ -67,16 +68,18 @@ private:
|
|||||||
void DoStop(); // TogglePlay 的 Stop 半程(恢复 + 回编辑器 + 冻结)
|
void DoStop(); // TogglePlay 的 Stop 半程(恢复 + 回编辑器 + 冻结)
|
||||||
|
|
||||||
// ---- 选中状态 ----
|
// ---- 选中状态 ----
|
||||||
// 同步描边:Renderer 落帧后 SelectionMask/Outline 只画选中实体
|
// 同步描边:Renderer 落帧后 SelectionMask/Outline 只画选中实体。
|
||||||
//(bits = 实体位模式,0 = 清选中)
|
// nullopt = 清选中——实体 0 号(场景首个创建)位模式 = 0,
|
||||||
|
// 不能拿位值兼作哨兵("第一个模型无描边"的根因)
|
||||||
void SelectEntity(entt::entity e)
|
void SelectEntity(entt::entity e)
|
||||||
{
|
{
|
||||||
m_Selected = e;
|
m_Selected = e;
|
||||||
if (m_Ctx.renderer) {
|
if (m_Ctx.renderer) {
|
||||||
m_Ctx.renderer->SetSelectedEntity(
|
m_Ctx.renderer->SetSelectedEntity(
|
||||||
e == entt::null
|
e == entt::null
|
||||||
? 0u
|
? std::optional<Engine::u32>{}
|
||||||
: static_cast<Engine::u32>(entt::to_integral(e)));
|
: std::optional<Engine::u32>(
|
||||||
|
static_cast<Engine::u32>(entt::to_integral(e))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entt::entity GetSelected() const { return m_Selected; }
|
entt::entity GetSelected() const { return m_Selected; }
|
||||||
|
|||||||
@@ -164,9 +164,10 @@ namespace Engine {
|
|||||||
std::optional<u32> TakePickResult();
|
std::optional<u32> TakePickResult();
|
||||||
|
|
||||||
// ---- Editor 选中描边(UE 编辑器选中轮廓)----
|
// ---- Editor 选中描边(UE 编辑器选中轮廓)----
|
||||||
// UI 段选中变化时调用(bits = 实体位模式,0 = 清选中);
|
// UI 段选中变化时调用;下一帧 SelectionMask 只画该实体,Outline
|
||||||
// 下一帧 SelectionMask 只画该实体,Outline 在其轮廓叠加描边色
|
// 在其轮廓叠加描边色。nullopt = 清选中(实体 0 号位模式 = 0,
|
||||||
void SetSelectedEntity(u32 entityBits);
|
// 不能拿位值兼作哨兵)
|
||||||
|
void SetSelectedEntity(std::optional<u32> entityBits);
|
||||||
|
|
||||||
// 垂直同步开关(present mode 切换会重建 swapchain),
|
// 垂直同步开关(present mode 切换会重建 swapchain),
|
||||||
// 只应在帧 UI 构建段调用(Render 之前)
|
// 只应在帧 UI 构建段调用(Render 之前)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <Engine/Renderer/EditorCamera.h>
|
#include <Engine/Renderer/EditorCamera.h>
|
||||||
@@ -73,8 +74,12 @@ namespace Engine {
|
|||||||
{
|
{
|
||||||
m_PendingPick = PickRequest{true, ndc};
|
m_PendingPick = PickRequest{true, ndc};
|
||||||
}
|
}
|
||||||
// Editor 选中实体(描边):UI 段写入,BuildFrame 落帧并筛出绘制
|
// Editor 选中实体(描边):UI 段写入,BuildFrame 落帧并筛出绘制。
|
||||||
void SetSelectedEntity(u32 entityBits) { m_PendingSelected = entityBits; }
|
// nullopt = 清选中(实体 0 号位模式 = 0,不能拿位值兼作哨兵)
|
||||||
|
void SetSelectedEntity(std::optional<u32> entityBits)
|
||||||
|
{
|
||||||
|
m_PendingSelected = entityBits;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// CSM:把相机视锥按实用分割切 N 段,每段独立拟合光源正交投影
|
// CSM:把相机视锥按实用分割切 N 段,每段独立拟合光源正交投影
|
||||||
@@ -91,7 +96,7 @@ namespace Engine {
|
|||||||
FrameSceneData m_Frame;
|
FrameSceneData m_Frame;
|
||||||
EditorCamera m_EditorCamera; // 编辑器相机(视口 UI 状态,见 GetEditorCamera)
|
EditorCamera m_EditorCamera; // 编辑器相机(视口 UI 状态,见 GetEditorCamera)
|
||||||
PickRequest m_PendingPick{}; // 拾取请求缓冲(BuildFrame 落帧后清除)
|
PickRequest m_PendingPick{}; // 拾取请求缓冲(BuildFrame 落帧后清除)
|
||||||
u32 m_PendingSelected = 0; // 选中实体缓冲(描边)
|
std::optional<u32> m_PendingSelected; // 选中实体缓冲(nullopt = 无选中)
|
||||||
|
|
||||||
// ---- 剔除中间量(每帧 clear 复用,拼接进 m_Frame 后保留容量)----
|
// ---- 剔除中间量(每帧 clear 复用,拼接进 m_Frame 后保留容量)----
|
||||||
struct ViewScratch {
|
struct ViewScratch {
|
||||||
@@ -102,12 +107,18 @@ namespace Engine {
|
|||||||
u32 skinBase = 0; // palette 区段基址(0 = identity 槽)
|
u32 skinBase = 0; // palette 区段基址(0 = identity 槽)
|
||||||
u32 entityBits = 0; // 实体位模式(HitProxy id pass 消费)
|
u32 entityBits = 0; // 实体位模式(HitProxy id pass 消费)
|
||||||
};
|
};
|
||||||
|
// 链表尾哨兵:kMaxInstances 远小于 u32 最大值,安全
|
||||||
|
static constexpr u32 kNoInstance = 0xFFFFFFFFu;
|
||||||
CullResult result;
|
CullResult result;
|
||||||
// 扁平实例数组(所有 batch 的实例共用一份连续内存)。
|
// 扁平实例数组(所有 batch 的实例共用一份连续内存)。
|
||||||
// InstanceBatch::first/count 在本数组里切片——大场景下避免
|
// 实体收集序下同 batch 实例会散布(多实体共享 mesh 交错插入),
|
||||||
// vector<vector> 的小块分配(每个 batch 自己一个 vector,push_back
|
// 组内连接关系由 instanceNext 链表维护——appendView 时按 batch
|
||||||
// 触发各自重分配,cache miss 严重)。每帧 clear() 复用容量
|
// 聚合拷成连续区间(firstInstance 连续语义的前提)。大场景下
|
||||||
|
// 避免 vector<vector> 的小块分配,每帧 clear() 复用容量
|
||||||
std::vector<InstanceMatrices> instances;
|
std::vector<InstanceMatrices> instances;
|
||||||
|
std::vector<u32> instanceNext; // 与 instances 平行:同 batch 下一实例
|
||||||
|
// 每 batch 实例链头(与 result.batches 平行;kNoInstance = 空)
|
||||||
|
std::vector<u32> batchHead;
|
||||||
// 每 batch 实例距离累加(透明排序用:平均距离降序 = 远→近)
|
// 每 batch 实例距离累加(透明排序用:平均距离降序 = 远→近)
|
||||||
std::vector<f32> batchDistSum;
|
std::vector<f32> batchDistSum;
|
||||||
// batch 查找:数组寻址(下标 = Mesh::GetSlot(),值 = 每 LOD 的
|
// batch 查找:数组寻址(下标 = Mesh::GetSlot(),值 = 每 LOD 的
|
||||||
@@ -119,6 +130,8 @@ namespace Engine {
|
|||||||
result.batches.clear();
|
result.batches.clear();
|
||||||
result.instanceCount = 0;
|
result.instanceCount = 0;
|
||||||
instances.clear(); // 容量保留,复用
|
instances.clear(); // 容量保留,复用
|
||||||
|
instanceNext.clear();
|
||||||
|
batchHead.clear();
|
||||||
batchDistSum.clear();
|
batchDistSum.clear();
|
||||||
for (auto& e : lookup) e.fill(0); // 容量保留,置零复用
|
for (auto& e : lookup) e.fill(0); // 容量保留,置零复用
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,9 +167,12 @@ namespace Engine {
|
|||||||
// HitProxy/HitProxyCopy 两 pass 据此决定是否绘制/拷贝)
|
// HitProxy/HitProxyCopy 两 pass 据此决定是否绘制/拷贝)
|
||||||
PickRequest pickRequest{};
|
PickRequest pickRequest{};
|
||||||
|
|
||||||
// 选中描边(UE 编辑器语义):选中实体的位模式(0 = 无选中)。
|
// 选中描边(UE 编辑器语义):选中实体 + 位模式。位模式不能兼作
|
||||||
|
// "无选中"哨兵——entt 首个实体 0 号的 to_integral == 0("点击
|
||||||
|
// 场景第一个创建的实体没有描边"的根因),有效性与位值解耦。
|
||||||
// BuildFrame 据此从实例表筛出 selectionDraws,SelectionMask pass
|
// BuildFrame 据此从实例表筛出 selectionDraws,SelectionMask pass
|
||||||
// 只画选中实体 → Outline pass 在 mask 边缘叠加描边色
|
// 只画选中实体 → Outline pass 在 mask 边缘叠加描边色
|
||||||
|
bool selectedEntityValid = false;
|
||||||
u32 selectedEntityBits = 0;
|
u32 selectedEntityBits = 0;
|
||||||
std::vector<SelectionDraw> selectionDraws;
|
std::vector<SelectionDraw> selectionDraws;
|
||||||
|
|
||||||
|
|||||||
@@ -38,8 +38,9 @@ namespace Engine::Passes
|
|||||||
void OutlinePass::Register(RG::RenderGraph& rg)
|
void OutlinePass::Register(RG::RenderGraph& rg)
|
||||||
{
|
{
|
||||||
rg.AddPass("Outline", [this](RG::RenderGraphContext& ctx) {
|
rg.AddPass("Outline", [this](RG::RenderGraphContext& ctx) {
|
||||||
// 无选中零 GPU(mask 已由 SelectionMask pass 清 0,无描边)
|
// 无选中零 GPU(mask 已由 SelectionMask pass 清 0,无描边)。
|
||||||
if (m_Frame.selectedEntityBits == 0) return;
|
// 有效位判断:实体 0 号位模式 = 0,不能拿位值当哨兵
|
||||||
|
if (!m_Frame.selectedEntityValid) return;
|
||||||
|
|
||||||
const vk::CommandBuffer cmd = ctx.cmd;
|
const vk::CommandBuffer cmd = ctx.cmd;
|
||||||
|
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ namespace Engine
|
|||||||
m_SceneRenderer->SetPickRequest(ndc);
|
m_SceneRenderer->SetPickRequest(ndc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetSelectedEntity(u32 entityBits)
|
void Renderer::SetSelectedEntity(std::optional<u32> entityBits)
|
||||||
{
|
{
|
||||||
m_SceneRenderer->SetSelectedEntity(entityBits);
|
m_SceneRenderer->SetSelectedEntity(entityBits);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -289,8 +289,10 @@ namespace Engine
|
|||||||
// 放在相机校验之后:跳帧时请求保留,不丢点击
|
// 放在相机校验之后:跳帧时请求保留,不丢点击
|
||||||
m_Frame.pickRequest = m_PendingPick;
|
m_Frame.pickRequest = m_PendingPick;
|
||||||
m_PendingPick.active = false;
|
m_PendingPick.active = false;
|
||||||
// 选中实体落帧(持续状态,不做一次性清除)
|
// 选中实体落帧(持续状态,不做一次性清除)。
|
||||||
m_Frame.selectedEntityBits = m_PendingSelected;
|
// 有效性与位值分离:0 号实体(场景首个创建)位模式 = 0
|
||||||
|
m_Frame.selectedEntityValid = m_PendingSelected.has_value();
|
||||||
|
m_Frame.selectedEntityBits = m_PendingSelected.value_or(0);
|
||||||
|
|
||||||
const f32 aspect = static_cast<f32>(targetExtent.width) /
|
const f32 aspect = static_cast<f32>(targetExtent.width) /
|
||||||
static_cast<f32>(targetExtent.height);
|
static_cast<f32>(targetExtent.height);
|
||||||
@@ -613,18 +615,23 @@ namespace Engine
|
|||||||
if (batchIdx == 0) {
|
if (batchIdx == 0) {
|
||||||
batchIdx = static_cast<u32>(s.result.batches.size()) + 1;
|
batchIdx = static_cast<u32>(s.result.batches.size()) + 1;
|
||||||
lodSlots[lod] = batchIdx;
|
lodSlots[lod] = batchIdx;
|
||||||
// first = 当前 instances 数组大小(batch 还没实例)
|
// first 是占位:真实基址在 appendView 聚合时
|
||||||
// push_back 实例后区间自然连续
|
// 回填(收集序下 batch 实例散布,见链表注释)
|
||||||
s.result.batches.push_back(
|
s.result.batches.push_back({mesh.get(), 0, 0, lod});
|
||||||
{mesh.get(), static_cast<u32>(s.instances.size()), 0, lod});
|
|
||||||
s.batchDistSum.push_back(0.0f);
|
s.batchDistSum.push_back(0.0f);
|
||||||
|
s.batchHead.push_back(ViewScratch::kNoInstance);
|
||||||
}
|
}
|
||||||
// 实例归入自己的 batch(mesh 分组),保证同 batch
|
// 实例归入自己的 batch(mesh 分组):收集序散布,
|
||||||
// 实例在扁平数组里连续——firstInstance 语义的前提
|
// 组内连接用链表维护(O(1) push,无 per-batch 分配)
|
||||||
const u32 bi = batchIdx - 1;
|
const u32 bi = batchIdx - 1;
|
||||||
s.result.batches[bi].count++;
|
s.result.batches[bi].count++;
|
||||||
|
const u32 ii =
|
||||||
|
static_cast<u32>(s.instances.size());
|
||||||
s.instances.push_back(
|
s.instances.push_back(
|
||||||
{t.World(), prevWorld, skinBase, entKey}); // 单 vector push
|
{t.World(), prevWorld, skinBase, entKey});
|
||||||
|
s.instanceNext.push_back(s.batchHead[bi]);
|
||||||
|
s.batchHead[bi] = ii; // 头插:链序 = push 逆序(无妨,
|
||||||
|
// 实例对齐性由 (矩阵,id) 成对保证)
|
||||||
s.batchDistSum[bi] += dist; // 透明排序用
|
s.batchDistSum[bi] += dist; // 透明排序用
|
||||||
s.result.instanceCount++;
|
s.result.instanceCount++;
|
||||||
++totalInstances;
|
++totalInstances;
|
||||||
@@ -657,15 +664,16 @@ namespace Engine
|
|||||||
dst.batches.reserve(s.result.batches.size());
|
dst.batches.reserve(s.result.batches.size());
|
||||||
for (size_t i = 0; i < s.result.batches.size(); ++i) {
|
for (size_t i = 0; i < s.result.batches.size(); ++i) {
|
||||||
InstanceBatch b = s.result.batches[i];
|
InstanceBatch b = s.result.batches[i];
|
||||||
// ✅ 保存原 first(s.instances 数组里的下标),b.first 改成
|
|
||||||
// m_Frame 数组里的基址
|
|
||||||
const u32 srcFirst = b.first;
|
|
||||||
b.first = base; // 扁平化后的连续区间基址
|
b.first = base; // 扁平化后的连续区间基址
|
||||||
base += b.count;
|
base += b.count;
|
||||||
dst.batches.push_back(b);
|
dst.batches.push_back(b);
|
||||||
// 按 batch 的 (srcFirst, count) 切片扁平数组
|
// 链表遍历:收集序下同 batch 实例散布在扁平数组各处
|
||||||
for (u32 j = 0; j < b.count; ++j) {
|
//(多实体共享 mesh 交错插入),按组聚合拷成连续区间
|
||||||
const auto& m = s.instances[srcFirst + j];
|
//——firstInstance 连续语义的前提
|
||||||
|
for (u32 idx = s.batchHead[i];
|
||||||
|
idx != ViewScratch::kNoInstance;
|
||||||
|
idx = s.instanceNext[idx]) {
|
||||||
|
const auto& m = s.instances[idx];
|
||||||
m_Frame.instanceModels.push_back(m.cur);
|
m_Frame.instanceModels.push_back(m.cur);
|
||||||
m_Frame.prevInstanceModels.push_back(m.prev);
|
m_Frame.prevInstanceModels.push_back(m.prev);
|
||||||
// 与实例序平行对齐(shader 按 gl_InstanceIndex 取)
|
// 与实例序平行对齐(shader 按 gl_InstanceIndex 取)
|
||||||
@@ -688,10 +696,9 @@ namespace Engine
|
|||||||
// PackIndirect(m_Frame.shadowCascades[c], false);
|
// PackIndirect(m_Frame.shadowCascades[c], false);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// ---- 5. 透明批次排序:平均距离降序(远 → 近),连同实例列表同步重排
|
|
||||||
// ---- 5. 透明批次排序:平均距离降序(远 → 近),连同实例列表同步重排。
|
// ---- 5. 透明批次排序:平均距离降序(远 → 近),连同实例列表同步重排。
|
||||||
// 扁平 instances 数组按 order 顺序构建新数组(每个 batch 的
|
// 实例按链表逐 batch 搬运(收集序散布,不能按 (first,count) 切片);
|
||||||
// (first,count) 切片搬过去,新 first = 当前已搬数量)----
|
// 搬完的新数组天然按 batch 连续 → 链表确定性重建(顺序遍历)
|
||||||
{
|
{
|
||||||
auto& tb = m_TranslucentScratch.result.batches;
|
auto& tb = m_TranslucentScratch.result.batches;
|
||||||
if (tb.size() > 1) {
|
if (tb.size() > 1) {
|
||||||
@@ -704,11 +711,15 @@ namespace Engine
|
|||||||
// 临时构建(容量保留由 swap 进 m_TranslucentScratch 复用)
|
// 临时构建(容量保留由 swap 进 m_TranslucentScratch 复用)
|
||||||
std::vector<InstanceBatch> sortedBatches;
|
std::vector<InstanceBatch> sortedBatches;
|
||||||
std::vector<ViewScratch::InstanceMatrices> sortedInstances;
|
std::vector<ViewScratch::InstanceMatrices> sortedInstances;
|
||||||
|
std::vector<u32> sortedNext;
|
||||||
|
std::vector<u32> sortedHead;
|
||||||
std::vector<f32> sortedDist;
|
std::vector<f32> sortedDist;
|
||||||
sortedBatches.reserve(tb.size());
|
sortedBatches.reserve(tb.size());
|
||||||
|
sortedHead.reserve(tb.size());
|
||||||
sortedDist.reserve(tb.size());
|
sortedDist.reserve(tb.size());
|
||||||
// 同场景实例总数不变,capacity 可直接复用(reserve 不浪费)
|
// 同场景实例总数不变,capacity 可直接复用(reserve 不浪费)
|
||||||
sortedInstances.reserve(m_TranslucentScratch.instances.size());
|
sortedInstances.reserve(m_TranslucentScratch.instances.size());
|
||||||
|
sortedNext.reserve(m_TranslucentScratch.instances.size());
|
||||||
|
|
||||||
for (const u32 i : order) {
|
for (const u32 i : order) {
|
||||||
// 新 batch first = 已搬过去的新 instances 数量
|
// 新 batch first = 已搬过去的新 instances 数量
|
||||||
@@ -716,13 +727,29 @@ namespace Engine
|
|||||||
b.first = static_cast<u32>(sortedInstances.size());
|
b.first = static_cast<u32>(sortedInstances.size());
|
||||||
sortedBatches.push_back(b);
|
sortedBatches.push_back(b);
|
||||||
sortedDist.push_back(m_TranslucentScratch.batchDistSum[i]);
|
sortedDist.push_back(m_TranslucentScratch.batchDistSum[i]);
|
||||||
// 按 (原 first, count) 切片搬运原扁平数组
|
// 链表逐实例搬运;新布局按 batch 连续 → next = 顺序+1。
|
||||||
for (u32 j = 0; j < tb[i].count; ++j) {
|
// 新实例下标 = b.first + n(n = 本 batch 已搬数量),
|
||||||
|
// 前一个实例的 next 指向它
|
||||||
|
u32 prev = ViewScratch::kNoInstance;
|
||||||
|
u32 n = 0;
|
||||||
|
for (u32 idx = m_TranslucentScratch.batchHead[i];
|
||||||
|
idx != ViewScratch::kNoInstance;
|
||||||
|
idx = m_TranslucentScratch.instanceNext[idx]) {
|
||||||
sortedInstances.push_back(std::move(
|
sortedInstances.push_back(std::move(
|
||||||
m_TranslucentScratch.instances[tb[i].first + j]));
|
m_TranslucentScratch.instances[idx]));
|
||||||
|
sortedNext.push_back(ViewScratch::kNoInstance);
|
||||||
|
if (prev != ViewScratch::kNoInstance) {
|
||||||
|
sortedNext[prev] = b.first + n;
|
||||||
}
|
}
|
||||||
|
prev = b.first + n;
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
sortedHead.push_back(
|
||||||
|
n > 0 ? b.first : ViewScratch::kNoInstance);
|
||||||
}
|
}
|
||||||
m_TranslucentScratch.result.batches = std::move(sortedBatches);
|
m_TranslucentScratch.result.batches = std::move(sortedBatches);
|
||||||
|
m_TranslucentScratch.batchHead = std::move(sortedHead);
|
||||||
|
m_TranslucentScratch.instanceNext = std::move(sortedNext);
|
||||||
m_TranslucentScratch.batchDistSum = std::move(sortedDist);
|
m_TranslucentScratch.batchDistSum = std::move(sortedDist);
|
||||||
m_TranslucentScratch.instances = std::move(sortedInstances);
|
m_TranslucentScratch.instances = std::move(sortedInstances);
|
||||||
// instanceCount 不变(重排不丢实例)
|
// instanceCount 不变(重排不丢实例)
|
||||||
@@ -734,7 +761,7 @@ namespace Engine
|
|||||||
//(不透明 + 透明队列都查——选中玻璃也要有描边)。
|
//(不透明 + 透明队列都查——选中玻璃也要有描边)。
|
||||||
// 无选中时保持空表,SelectionMask pass 只 clear 不绘制
|
// 无选中时保持空表,SelectionMask pass 只 clear 不绘制
|
||||||
m_Frame.selectionDraws.clear();
|
m_Frame.selectionDraws.clear();
|
||||||
if (m_Frame.selectedEntityBits != 0) {
|
if (m_Frame.selectedEntityValid) {
|
||||||
auto collect = [&](const CullResult& view) {
|
auto collect = [&](const CullResult& view) {
|
||||||
for (const auto& b : view.batches) {
|
for (const auto& b : view.batches) {
|
||||||
for (u32 i = 0; i < b.count; ++i) {
|
for (u32 i = 0; i < b.count; ++i) {
|
||||||
|
|||||||
Reference in New Issue
Block a user