feat: GPUDriven 实例化渲染——draw 数与实体数解耦
- UniformBuffer ring 支持 eStorageBuffer usage(GPUDriven 实例矩阵 per-frame-slot,正确性保证与 UBO 一致:fence 等待后写入) - DescriptorManager 加 UpdateStorageBuffer;池补 STORAGE_BUFFER 类型 - Set0 新增 binding1 = 实例矩阵 SSBO(vertex 读取,std430) - Forward pass 重写:每帧从 ECS 收集实例矩阵(按 mesh 聚合 batch, 两趟遍历保证 batch 区间连续),同 mesh 的 N 个实体合并为 一次 drawIndexed(instanceCount=N),firstInstance 指向 batch 起点; vertex shader 经 gl_InstanceIndex 取模型矩阵,forward 不再用 push - draw 数 = 唯一 mesh 数,与实体数量解耦(4096 实例上限, 超出截断告警;聚合改哈希为后续 TODO) 验证:8 pass 全活,validation 0 error 0 warning,GPU Timings 面板 实测各 pass 毫秒,场景渲染与阴影正确
This commit is contained in:
@@ -30,7 +30,9 @@ namespace Engine
|
|||||||
Mesh(const Mesh&) = delete;
|
Mesh(const Mesh&) = delete;
|
||||||
Mesh& operator=(const Mesh&) = delete;
|
Mesh& operator=(const Mesh&) = delete;
|
||||||
|
|
||||||
void Draw(vk::CommandBuffer cmd) const;
|
// instanceCount/firstInstance:GPUDriven 按 mesh 分 batch 后,
|
||||||
|
// 同 mesh 的 N 个实体一次 draw 完成,模型矩阵经实例索引取
|
||||||
|
void Draw(vk::CommandBuffer cmd, u32 instanceCount = 1, u32 firstInstance = 0) const;
|
||||||
|
|
||||||
Material* GetMaterial() const { return m_Material.get(); }
|
Material* GetMaterial() const { return m_Material.get(); }
|
||||||
u32 GetIndexCount() const { return m_IndexCount; }
|
u32 GetIndexCount() const { return m_IndexCount; }
|
||||||
|
|||||||
@@ -31,6 +31,14 @@ namespace Engine {
|
|||||||
namespace ECS { class Scene; }
|
namespace ECS { class Scene; }
|
||||||
namespace Assets { class AssetManager; }
|
namespace Assets { class AssetManager; }
|
||||||
class ImGuiLayer;
|
class ImGuiLayer;
|
||||||
|
class Mesh;
|
||||||
|
|
||||||
|
// GPUDriven:按 mesh 聚合的绘制批
|
||||||
|
struct InstanceBatch {
|
||||||
|
Mesh* mesh;
|
||||||
|
u32 first; // 在实例矩阵数组中的起始下标
|
||||||
|
u32 count; // 实例数
|
||||||
|
};
|
||||||
|
|
||||||
// Renderer 职责(收敛后):
|
// Renderer 职责(收敛后):
|
||||||
// 1. 装配底层模块(Device/Swapchain/Sync/Command/Descriptor/Shader)
|
// 1. 装配底层模块(Device/Swapchain/Sync/Command/Descriptor/Shader)
|
||||||
@@ -78,6 +86,7 @@ namespace Engine {
|
|||||||
Scope<SyncManager> m_SyncManager;
|
Scope<SyncManager> m_SyncManager;
|
||||||
Scope<CommandManager> m_CommandManager;
|
Scope<CommandManager> m_CommandManager;
|
||||||
Scope<UniformBuffer> m_UniformBuffer;
|
Scope<UniformBuffer> m_UniformBuffer;
|
||||||
|
Scope<UniformBuffer> m_ObjectBuffer; // GPUDriven 实例矩阵 ring(SSBO)
|
||||||
Scope<RG::RenderGraph> m_RenderGraph;
|
Scope<RG::RenderGraph> m_RenderGraph;
|
||||||
|
|
||||||
// ---- 管线装配(shader object 方案,无 vk::Pipeline)----
|
// ---- 管线装配(shader object 方案,无 vk::Pipeline)----
|
||||||
@@ -128,6 +137,11 @@ namespace Engine {
|
|||||||
Assets::AssetManager* m_BoundAssets = nullptr;
|
Assets::AssetManager* m_BoundAssets = nullptr;
|
||||||
glm::mat4 m_LightSpace{1.0f}; // 阴影光源 VP(每帧由 Render 算好)
|
glm::mat4 m_LightSpace{1.0f}; // 阴影光源 VP(每帧由 Render 算好)
|
||||||
|
|
||||||
|
// GPUDriven:当帧实例数据(Render 期收集,Forward pass 消费)
|
||||||
|
std::vector<InstanceBatch> m_InstanceBatches;
|
||||||
|
std::vector<glm::mat4> m_InstanceModels;
|
||||||
|
static constexpr u32 kMaxInstances = 4096;
|
||||||
|
|
||||||
// 可选叠加层(不拥有;Application 持有)
|
// 可选叠加层(不拥有;Application 持有)
|
||||||
ImGuiLayer* m_ImGuiLayer = nullptr;
|
ImGuiLayer* m_ImGuiLayer = nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ namespace Engine {
|
|||||||
|
|
||||||
void UpdateUniformBuffer(vk::DescriptorSet set, u32 binding,
|
void UpdateUniformBuffer(vk::DescriptorSet set, u32 binding,
|
||||||
vk::Buffer buffer, u64 size);
|
vk::Buffer buffer, u64 size);
|
||||||
|
void UpdateStorageBuffer(vk::DescriptorSet set, u32 binding,
|
||||||
|
vk::Buffer buffer, u64 size);
|
||||||
|
|
||||||
void UpdateTexture(vk::DescriptorSet set, u32 binding,
|
void UpdateTexture(vk::DescriptorSet set, u32 binding,
|
||||||
vk::Sampler sampler, vk::ImageView view);
|
vk::Sampler sampler, vk::ImageView view);
|
||||||
|
|||||||
@@ -25,8 +25,11 @@ namespace Engine {
|
|||||||
// 接口已按"写入哪个槽位"设计,届时只是内部实现替换。
|
// 接口已按"写入哪个槽位"设计,届时只是内部实现替换。
|
||||||
class UniformBuffer {
|
class UniformBuffer {
|
||||||
public:
|
public:
|
||||||
|
// usage:默认 eUniformBuffer;GPUDriven 实例数据传 eStorageBuffer
|
||||||
|
//(ring 化的正确性保证对所有 per-frame 数据一致)
|
||||||
UniformBuffer(Device& device, MemoryAllocator& allocator,
|
UniformBuffer(Device& device, MemoryAllocator& allocator,
|
||||||
u64 size, u32 frameCount);
|
u64 size, u32 frameCount,
|
||||||
|
vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eUniformBuffer);
|
||||||
~UniformBuffer() = default;
|
~UniformBuffer() = default;
|
||||||
|
|
||||||
UniformBuffer(const UniformBuffer&) = delete;
|
UniformBuffer(const UniformBuffer&) = delete;
|
||||||
|
|||||||
@@ -55,10 +55,10 @@ namespace Engine
|
|||||||
STATS.RemoveMesh(m_VertexBytes, m_IndexBytes);
|
STATS.RemoveMesh(m_VertexBytes, m_IndexBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mesh::Draw(vk::CommandBuffer cmd) const
|
void Mesh::Draw(vk::CommandBuffer cmd, u32 instanceCount, u32 firstInstance) const
|
||||||
{
|
{
|
||||||
cmd.bindVertexBuffers(0, m_VertexBuffer->Get(), {0});
|
cmd.bindVertexBuffers(0, m_VertexBuffer->Get(), {0});
|
||||||
cmd.bindIndexBuffer(m_IndexBuffer->Get(), 0, vk::IndexType::eUint32);
|
cmd.bindIndexBuffer(m_IndexBuffer->Get(), 0, vk::IndexType::eUint32);
|
||||||
cmd.drawIndexed(m_IndexCount, 1, 0, 0, 0);
|
cmd.drawIndexed(m_IndexCount, instanceCount, 0, 0, firstInstance);
|
||||||
}
|
}
|
||||||
} // namespace Engine
|
} // namespace Engine
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ namespace Engine
|
|||||||
};
|
};
|
||||||
|
|
||||||
constexpr u32 kUboBinding = 0;
|
constexpr u32 kUboBinding = 0;
|
||||||
|
constexpr u32 kObjectBinding = 1;
|
||||||
constexpr u32 kUBOSetIndex = 0;
|
constexpr u32 kUBOSetIndex = 0;
|
||||||
constexpr u32 kTextureSetIndex = 1;
|
constexpr u32 kTextureSetIndex = 1;
|
||||||
constexpr u32 kShadowSetIndex = 2;
|
constexpr u32 kShadowSetIndex = 2;
|
||||||
@@ -85,10 +86,12 @@ namespace Engine
|
|||||||
// 3. DescriptorManager
|
// 3. DescriptorManager
|
||||||
m_DescriptorManager = CreateScope<DescriptorManager>(*m_Device);
|
m_DescriptorManager = CreateScope<DescriptorManager>(*m_Device);
|
||||||
|
|
||||||
// 4. Set 0: UBO
|
// 4. Set 0: UBO + GPUDriven 实例数据(SSBO,vertex 读取)
|
||||||
std::vector<DescriptorBinding> uboBindings = {
|
std::vector<DescriptorBinding> uboBindings = {
|
||||||
{kUboBinding, vk::DescriptorType::eUniformBuffer,
|
{kUboBinding, vk::DescriptorType::eUniformBuffer,
|
||||||
vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment},
|
vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment},
|
||||||
|
{kObjectBinding, vk::DescriptorType::eStorageBuffer,
|
||||||
|
vk::ShaderStageFlagBits::eVertex},
|
||||||
};
|
};
|
||||||
m_UBOSetLayout = m_DescriptorManager->CreateLayout(uboBindings);
|
m_UBOSetLayout = m_DescriptorManager->CreateLayout(uboBindings);
|
||||||
|
|
||||||
@@ -104,10 +107,9 @@ namespace Engine
|
|||||||
};
|
};
|
||||||
m_ShadowSetLayout = m_DescriptorManager->CreateLayout(shadowBindings);
|
m_ShadowSetLayout = m_DescriptorManager->CreateLayout(shadowBindings);
|
||||||
|
|
||||||
// 6. PipelineLayout:三个 set;push constant 上限 128B
|
// 6. PipelineLayout:三个 set;forward 无 push(GPUDriven 经 SSBO)
|
||||||
//(Shadow pass 的 {lightVP, model} 用满;forward shader block 只用前 64B)
|
|
||||||
m_PipelineLayout = m_DescriptorManager->CreatePipelineLayout(
|
m_PipelineLayout = m_DescriptorManager->CreatePipelineLayout(
|
||||||
{m_UBOSetLayout, m_TextureSetLayout, m_ShadowSetLayout}, kShadowPushSize);
|
{m_UBOSetLayout, m_TextureSetLayout, m_ShadowSetLayout}, 0);
|
||||||
|
|
||||||
// Shadow pass 独立 layout:无 set,128B push constant
|
// Shadow pass 独立 layout:无 set,128B push constant
|
||||||
m_ShadowPipelineLayout = m_DescriptorManager->CreatePipelineLayout(
|
m_ShadowPipelineLayout = m_DescriptorManager->CreatePipelineLayout(
|
||||||
@@ -117,14 +119,15 @@ namespace Engine
|
|||||||
m_ShaderManager = CreateScope<ShaderManager>(*m_Device);
|
m_ShaderManager = CreateScope<ShaderManager>(*m_Device);
|
||||||
|
|
||||||
std::string shaderDir = "shaders/";
|
std::string shaderDir = "shaders/";
|
||||||
|
// forward vert/frag 均无 push(range 定义一致:都没有,VUID-08878)
|
||||||
auto vert = m_ShaderManager->CreateFromFile(
|
auto vert = m_ShaderManager->CreateFromFile(
|
||||||
shaderDir + "simple_shader.vert.spv",
|
shaderDir + "simple_shader.vert.spv",
|
||||||
vk::ShaderStageFlagBits::eVertex,
|
vk::ShaderStageFlagBits::eVertex,
|
||||||
{m_UBOSetLayout, m_TextureSetLayout, m_ShadowSetLayout}, kShadowPushSize);
|
{m_UBOSetLayout, m_TextureSetLayout, m_ShadowSetLayout}, 0);
|
||||||
auto frag = m_ShaderManager->CreateFromFile(
|
auto frag = m_ShaderManager->CreateFromFile(
|
||||||
shaderDir + "simple_shader.frag.spv",
|
shaderDir + "simple_shader.frag.spv",
|
||||||
vk::ShaderStageFlagBits::eFragment,
|
vk::ShaderStageFlagBits::eFragment,
|
||||||
{m_UBOSetLayout, m_TextureSetLayout, m_ShadowSetLayout}, kShadowPushSize);
|
{m_UBOSetLayout, m_TextureSetLayout, m_ShadowSetLayout}, 0);
|
||||||
|
|
||||||
m_VertShader = vert.Handle;
|
m_VertShader = vert.Handle;
|
||||||
m_FragShader = frag.Handle;
|
m_FragShader = frag.Handle;
|
||||||
@@ -220,9 +223,15 @@ namespace Engine
|
|||||||
*m_Device, kMaxFramesInFlight, m_Swapchain->GetImageCount());
|
*m_Device, kMaxFramesInFlight, m_Swapchain->GetImageCount());
|
||||||
m_CommandManager = CreateScope<CommandManager>(*m_Device, kMaxFramesInFlight);
|
m_CommandManager = CreateScope<CommandManager>(*m_Device, kMaxFramesInFlight);
|
||||||
|
|
||||||
// 10. Per-frame UBO ring + 每槽位的 UBO descriptor set
|
// 10. Per-frame UBO ring + GPUDriven 实例 SSBO ring
|
||||||
|
// (同一 ring 类,SSBO 只是 usage 不同;正确性保证一致)
|
||||||
|
constexpr u32 kMaxInstances = 4096;
|
||||||
m_UniformBuffer = CreateScope<UniformBuffer>(
|
m_UniformBuffer = CreateScope<UniformBuffer>(
|
||||||
*m_Device, *m_Allocator, sizeof(UniformBufferObject), kMaxFramesInFlight);
|
*m_Device, *m_Allocator, sizeof(UniformBufferObject), kMaxFramesInFlight);
|
||||||
|
m_ObjectBuffer = CreateScope<UniformBuffer>(
|
||||||
|
*m_Device, *m_Allocator,
|
||||||
|
sizeof(glm::mat4) * kMaxInstances, kMaxFramesInFlight,
|
||||||
|
vk::BufferUsageFlagBits::eStorageBuffer);
|
||||||
|
|
||||||
m_UBODescriptorSets.resize(kMaxFramesInFlight);
|
m_UBODescriptorSets.resize(kMaxFramesInFlight);
|
||||||
m_ShadowDescriptorSets.resize(kMaxFramesInFlight);
|
m_ShadowDescriptorSets.resize(kMaxFramesInFlight);
|
||||||
@@ -236,6 +245,9 @@ namespace Engine
|
|||||||
m_DescriptorManager->UpdateUniformBuffer(
|
m_DescriptorManager->UpdateUniformBuffer(
|
||||||
m_UBODescriptorSets[slot], kUboBinding,
|
m_UBODescriptorSets[slot], kUboBinding,
|
||||||
m_UniformBuffer->Get(slot), m_UniformBuffer->GetSize());
|
m_UniformBuffer->Get(slot), m_UniformBuffer->GetSize());
|
||||||
|
m_DescriptorManager->UpdateStorageBuffer(
|
||||||
|
m_UBODescriptorSets[slot], kObjectBinding,
|
||||||
|
m_ObjectBuffer->Get(slot), m_ObjectBuffer->GetSize());
|
||||||
|
|
||||||
m_ShadowDescriptorSets[slot] =
|
m_ShadowDescriptorSets[slot] =
|
||||||
m_DescriptorManager->AllocateDescriptorSet(m_ShadowSetLayout);
|
m_DescriptorManager->AllocateDescriptorSet(m_ShadowSetLayout);
|
||||||
@@ -564,29 +576,16 @@ namespace Engine
|
|||||||
vk::ColorComponentFlagBits::eA;
|
vk::ColorComponentFlagBits::eA;
|
||||||
cmd.setColorWriteMaskEXT(0, colorWriteMask);
|
cmd.setColorWriteMaskEXT(0, colorWriteMask);
|
||||||
|
|
||||||
// ---- 绘制:遍历 ECS 渲染体 ----
|
// ---- 绘制:GPUDriven 按 mesh 分 batch ----
|
||||||
// Each 以 Transform/MeshRenderer 中较小的池为主表——
|
// 实例矩阵已在 Render() 里写入 ObjectBuffer(per-slot SSBO);
|
||||||
// 大场景下遍历开销与最小池规模成正比
|
// 同 mesh 的 N 个实体合并为一次 drawIndexed(instanceCount=N),
|
||||||
m_BoundScene->Each<TransformComponent, MeshRendererComponent>(
|
// draw 数 = 唯一 mesh 数,与实体数量解耦
|
||||||
[&](Entity, TransformComponent& transform,
|
for (const auto& batch : m_InstanceBatches) {
|
||||||
MeshRendererComponent& meshRenderer) {
|
|
||||||
// 句柄 → 资产(悬空句柄会被 AssetCache FATAL 拦截)
|
|
||||||
Model* model = m_BoundAssets->GetModel(meshRenderer.model);
|
|
||||||
if (!model) return;
|
|
||||||
|
|
||||||
// stage 必须覆盖 layout range 声明的全部 stage(VUID-01796)
|
|
||||||
cmd.pushConstants(m_PipelineLayout,
|
|
||||||
vk::ShaderStageFlagBits::eVertex |
|
|
||||||
vk::ShaderStageFlagBits::eFragment,
|
|
||||||
0, sizeof(glm::mat4), &transform.world);
|
|
||||||
|
|
||||||
for (auto& mesh : model->GetMeshes()) {
|
|
||||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
|
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
|
||||||
m_PipelineLayout, kTextureSetIndex,
|
m_PipelineLayout, kTextureSetIndex,
|
||||||
mesh->GetMaterial()->GetDescriptorSet(), {});
|
batch.mesh->GetMaterial()->GetDescriptorSet(), {});
|
||||||
mesh->Draw(cmd);
|
batch.mesh->Draw(cmd, batch.count, batch.first);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
cmd.endRendering();
|
cmd.endRendering();
|
||||||
})
|
})
|
||||||
@@ -931,6 +930,57 @@ namespace Engine
|
|||||||
m_UniformBuffer->Update(frameSlot, &ubo, sizeof(ubo));
|
m_UniformBuffer->Update(frameSlot, &ubo, sizeof(ubo));
|
||||||
m_SyncManager->ResetFence(frameSlot);
|
m_SyncManager->ResetFence(frameSlot);
|
||||||
|
|
||||||
|
// ---- GPUDriven:收集实例数据(按 mesh 聚合 batch)----
|
||||||
|
// 两趟遍历:先收集唯一 mesh(保持首现序),再逐 batch 追加实例矩阵,
|
||||||
|
// 保证每个 batch 的矩阵区间连续(draw 用 firstInstance 指向起点)。
|
||||||
|
// TODO: 实体量大时改哈希聚合 + 单趟填充
|
||||||
|
m_InstanceBatches.clear();
|
||||||
|
m_InstanceModels.clear();
|
||||||
|
bool instanceTruncated = false;
|
||||||
|
|
||||||
|
std::vector<Mesh*> uniqueMeshes;
|
||||||
|
scene.Each<TransformComponent, MeshRendererComponent>(
|
||||||
|
[&](Entity, TransformComponent&, MeshRendererComponent& mr) {
|
||||||
|
Model* model = assets.GetModel(mr.model);
|
||||||
|
if (!model) return;
|
||||||
|
for (auto& mesh : model->GetMeshes()) {
|
||||||
|
if (std::find(uniqueMeshes.begin(), uniqueMeshes.end(),
|
||||||
|
mesh.get()) == uniqueMeshes.end()) {
|
||||||
|
uniqueMeshes.push_back(mesh.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (Mesh* meshPtr : uniqueMeshes) {
|
||||||
|
InstanceBatch batch{meshPtr,
|
||||||
|
static_cast<u32>(m_InstanceModels.size()), 0};
|
||||||
|
scene.Each<TransformComponent, MeshRendererComponent>(
|
||||||
|
[&](Entity, TransformComponent& t, MeshRendererComponent& mr) {
|
||||||
|
Model* model = assets.GetModel(mr.model);
|
||||||
|
if (!model) return;
|
||||||
|
for (auto& m : model->GetMeshes()) {
|
||||||
|
if (m.get() != meshPtr) continue;
|
||||||
|
if (m_InstanceModels.size() >= kMaxInstances) {
|
||||||
|
instanceTruncated = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_InstanceModels.push_back(t.world);
|
||||||
|
++batch.count;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (batch.count > 0) {
|
||||||
|
m_InstanceBatches.push_back(batch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (instanceTruncated) {
|
||||||
|
ENGINE_WARN("GPUDriven: instance buffer full ({}), entities truncated",
|
||||||
|
kMaxInstances);
|
||||||
|
}
|
||||||
|
if (!m_InstanceModels.empty()) {
|
||||||
|
m_ObjectBuffer->Update(frameSlot, m_InstanceModels.data(),
|
||||||
|
m_InstanceModels.size() * sizeof(glm::mat4));
|
||||||
|
}
|
||||||
|
|
||||||
// 2. acquire swapchain image
|
// 2. acquire swapchain image
|
||||||
u32 imageIndex = 0;
|
u32 imageIndex = 0;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ namespace Engine
|
|||||||
DescriptorManager::DescriptorManager(Device& device)
|
DescriptorManager::DescriptorManager(Device& device)
|
||||||
: m_Device(device)
|
: m_Device(device)
|
||||||
{
|
{
|
||||||
std::array<vk::DescriptorPoolSize, 2> poolSizes = {
|
std::array<vk::DescriptorPoolSize, 3> poolSizes = {
|
||||||
vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, kMaxSets),
|
vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, kMaxSets),
|
||||||
vk::DescriptorPoolSize(vk::DescriptorType::eCombinedImageSampler, kMaxSets),
|
vk::DescriptorPoolSize(vk::DescriptorType::eCombinedImageSampler, kMaxSets),
|
||||||
|
vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, kMaxSets),
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::DescriptorPoolCreateInfo poolInfo;
|
vk::DescriptorPoolCreateInfo poolInfo;
|
||||||
@@ -76,6 +77,23 @@ namespace Engine
|
|||||||
m_Device.GetDevice().updateDescriptorSets(write, {});
|
m_Device.GetDevice().updateDescriptorSets(write, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DescriptorManager::UpdateStorageBuffer(vk::DescriptorSet set, u32 binding,
|
||||||
|
vk::Buffer buffer, u64 size)
|
||||||
|
{
|
||||||
|
vk::DescriptorBufferInfo bufferInfo;
|
||||||
|
bufferInfo.setBuffer(buffer).setOffset(0).setRange(size);
|
||||||
|
|
||||||
|
vk::WriteDescriptorSet write;
|
||||||
|
write.setDstSet(set)
|
||||||
|
.setDstBinding(binding)
|
||||||
|
.setDstArrayElement(0)
|
||||||
|
.setDescriptorType(vk::DescriptorType::eStorageBuffer)
|
||||||
|
.setDescriptorCount(1)
|
||||||
|
.setBufferInfo(bufferInfo);
|
||||||
|
|
||||||
|
m_Device.GetDevice().updateDescriptorSets(write, {});
|
||||||
|
}
|
||||||
|
|
||||||
void DescriptorManager::UpdateTexture(vk::DescriptorSet set, u32 binding,
|
void DescriptorManager::UpdateTexture(vk::DescriptorSet set, u32 binding,
|
||||||
vk::Sampler sampler, vk::ImageView view)
|
vk::Sampler sampler, vk::ImageView view)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,15 +10,15 @@
|
|||||||
namespace Engine {
|
namespace Engine {
|
||||||
|
|
||||||
UniformBuffer::UniformBuffer(Device& device, MemoryAllocator& allocator,
|
UniformBuffer::UniformBuffer(Device& device, MemoryAllocator& allocator,
|
||||||
u64 size, u32 frameCount)
|
u64 size, u32 frameCount,
|
||||||
|
vk::BufferUsageFlags usage)
|
||||||
: m_Size(size)
|
: m_Size(size)
|
||||||
{
|
{
|
||||||
m_Buffers.reserve(frameCount);
|
m_Buffers.reserve(frameCount);
|
||||||
for (u32 i = 0; i < frameCount; ++i) {
|
for (u32 i = 0; i < frameCount; ++i) {
|
||||||
// Uniform Buffer 需要 CPU 每帧更新,所以用 HOST_VISIBLE | HOST_COHERENT
|
// CPU 每帧更新,所以用 HOST_VISIBLE | HOST_COHERENT
|
||||||
m_Buffers.push_back(CreateScope<Buffer>(
|
m_Buffers.push_back(CreateScope<Buffer>(
|
||||||
device, allocator, size,
|
device, allocator, size, usage,
|
||||||
vk::BufferUsageFlagBits::eUniformBuffer,
|
|
||||||
vk::MemoryPropertyFlagBits::eHostVisible |
|
vk::MemoryPropertyFlagBits::eHostVisible |
|
||||||
vk::MemoryPropertyFlagBits::eHostCoherent));
|
vk::MemoryPropertyFlagBits::eHostCoherent));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by atdunbg on 2026/9/20.
|
|
||||||
//
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#include <stb/stb_image.h>
|
|
||||||
@@ -16,9 +16,12 @@ layout(location = 1) out vec3 fragNormal;
|
|||||||
layout(location = 2) out vec3 fragWorldPos;
|
layout(location = 2) out vec3 fragWorldPos;
|
||||||
layout(location = 3) out vec3 fragLightSpacePos;
|
layout(location = 3) out vec3 fragLightSpacePos;
|
||||||
|
|
||||||
layout(push_constant) uniform PushConstants {
|
// GPUDriven:模型矩阵从实例缓冲按实例索引取。
|
||||||
mat4 model;
|
// 同一 mesh 的 N 个实体 = 1 次 drawIndexed(instanceCount=N),
|
||||||
} pc;
|
// draw 侧用 firstInstance 指向该 batch 在实例数组中的起始下标。
|
||||||
|
layout(std430, set = 0, binding = 1) readonly buffer ObjectBuffer {
|
||||||
|
mat4 models[]; // 连续 mat4 数组(16B 对齐,std430/std140 布局一致)
|
||||||
|
} objects;
|
||||||
|
|
||||||
layout(set = 0, binding = 0) uniform UniformBufferObject {
|
layout(set = 0, binding = 0) uniform UniformBufferObject {
|
||||||
mat4 view;
|
mat4 view;
|
||||||
@@ -29,14 +32,16 @@ layout(set = 0, binding = 0) uniform UniformBufferObject {
|
|||||||
} ubo;
|
} ubo;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 worldPos = pc.model * vec4(inPosition, 1.0);
|
mat4 model = objects.models[gl_InstanceIndex];
|
||||||
|
|
||||||
|
vec4 worldPos = model * vec4(inPosition, 1.0);
|
||||||
gl_Position = ubo.proj * ubo.view * worldPos;
|
gl_Position = ubo.proj * ubo.view * worldPos;
|
||||||
|
|
||||||
fragWorldPos = worldPos.xyz;
|
fragWorldPos = worldPos.xyz;
|
||||||
// 光空间坐标(含 Vulkan [0,1] 深度重映射,与 shadow pass 写入端共用同一矩阵)
|
// 光空间坐标(含 Vulkan [0,1] 深度重映射,与 shadow pass 写入端共用同一矩阵)
|
||||||
fragLightSpacePos = (ubo.lightSpace * worldPos).xyz;
|
fragLightSpacePos = (ubo.lightSpace * worldPos).xyz;
|
||||||
|
|
||||||
mat3 normalMatrix = mat3(transpose(inverse(pc.model)));
|
mat3 normalMatrix = mat3(transpose(inverse(model)));
|
||||||
fragNormal = normalize(normalMatrix * inNormal);
|
fragNormal = normalize(normalMatrix * inNormal);
|
||||||
|
|
||||||
fragUV = inUV;
|
fragUV = inUV;
|
||||||
|
|||||||
Reference in New Issue
Block a user