ADD: object adding system ((RT shadow error)
This commit is contained in:
@@ -122,6 +122,19 @@ void TextureCache::watchBinding(TextureHandle handle, VkDescriptorSet set, uint3
|
|||||||
|
|
||||||
// Back-reference for fast per-set markUsed
|
// Back-reference for fast per-set markUsed
|
||||||
_setToHandles[set].push_back(handle);
|
_setToHandles[set].push_back(handle);
|
||||||
|
|
||||||
|
// If the texture is already resident, immediately patch the new descriptor
|
||||||
|
// so re-spawned models using cached textures get the correct bindings.
|
||||||
|
if (e.state == EntryState::Resident && e.image.imageView != VK_NULL_HANDLE && set != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
if (!_context || !_context->getDevice()) return;
|
||||||
|
DescriptorWriter writer;
|
||||||
|
writer.write_image(static_cast<int>(binding), e.image.imageView,
|
||||||
|
p.sampler ? p.sampler : e.sampler,
|
||||||
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
||||||
|
writer.update_set(_context->getDevice()->device(), set);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureCache::unwatchSet(VkDescriptorSet set)
|
void TextureCache::unwatchSet(VkDescriptorSet set)
|
||||||
|
|||||||
@@ -254,13 +254,6 @@ void VulkanEngine::init()
|
|||||||
auto imguiPass = std::make_unique<ImGuiPass>();
|
auto imguiPass = std::make_unique<ImGuiPass>();
|
||||||
_renderPassManager->setImGuiPass(std::move(imguiPass));
|
_renderPassManager->setImGuiPass(std::move(imguiPass));
|
||||||
|
|
||||||
const std::string structurePath = _assetManager->modelPath("mirage2000/scene.gltf");
|
|
||||||
const auto structureFile = _assetManager->loadGLTF(structurePath);
|
|
||||||
|
|
||||||
assert(structureFile.has_value());
|
|
||||||
|
|
||||||
_sceneManager->loadScene("structure", *structureFile);
|
|
||||||
|
|
||||||
_resourceManager->set_deferred_uploads(true);
|
_resourceManager->set_deferred_uploads(true);
|
||||||
|
|
||||||
//everything went fine
|
//everything went fine
|
||||||
@@ -330,6 +323,8 @@ void VulkanEngine::init_default_data()
|
|||||||
BoundsType::Sphere);
|
BoundsType::Sphere);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addGLTFInstance("mirage", "mirage2000/scene.gltf", glm::mat4(1.0f));
|
||||||
|
|
||||||
_mainDeletionQueue.push_function([&]() {
|
_mainDeletionQueue.push_function([&]() {
|
||||||
_resourceManager->destroy_image(_whiteImage);
|
_resourceManager->destroy_image(_whiteImage);
|
||||||
_resourceManager->destroy_image(_greyImage);
|
_resourceManager->destroy_image(_greyImage);
|
||||||
@@ -340,6 +335,32 @@ void VulkanEngine::init_default_data()
|
|||||||
//< default_img
|
//< default_img
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VulkanEngine::addGLTFInstance(const std::string &instanceName,
|
||||||
|
const std::string &modelRelativePath,
|
||||||
|
const glm::mat4 &transform)
|
||||||
|
{
|
||||||
|
if (!_assetManager || !_sceneManager)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string fullPath = _assetManager->modelPath(modelRelativePath);
|
||||||
|
auto gltf = _assetManager->loadGLTF(fullPath);
|
||||||
|
if (!gltf.has_value() || !gltf.value())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide a readable debug name for UI/picking when missing.
|
||||||
|
if ((*gltf)->debugName.empty())
|
||||||
|
{
|
||||||
|
(*gltf)->debugName = modelRelativePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
_sceneManager->addGLTFInstance(instanceName, *gltf, transform);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void VulkanEngine::cleanup()
|
void VulkanEngine::cleanup()
|
||||||
{
|
{
|
||||||
vkDeviceWaitIdle(_deviceManager->device());
|
vkDeviceWaitIdle(_deviceManager->device());
|
||||||
@@ -449,6 +470,9 @@ void VulkanEngine::draw()
|
|||||||
{
|
{
|
||||||
_hoverPick.mesh = hoverObj.sourceMesh;
|
_hoverPick.mesh = hoverObj.sourceMesh;
|
||||||
_hoverPick.scene = hoverObj.sourceScene;
|
_hoverPick.scene = hoverObj.sourceScene;
|
||||||
|
_hoverPick.node = hoverObj.sourceNode;
|
||||||
|
_hoverPick.ownerType = hoverObj.ownerType;
|
||||||
|
_hoverPick.ownerName = hoverObj.ownerName;
|
||||||
_hoverPick.worldPos = hoverPos;
|
_hoverPick.worldPos = hoverPos;
|
||||||
_hoverPick.worldTransform = hoverObj.transform;
|
_hoverPick.worldTransform = hoverObj.transform;
|
||||||
_hoverPick.firstIndex = hoverObj.firstIndex;
|
_hoverPick.firstIndex = hoverObj.firstIndex;
|
||||||
@@ -459,6 +483,8 @@ void VulkanEngine::draw()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_hoverPick.valid = false;
|
_hoverPick.valid = false;
|
||||||
|
_hoverPick.ownerName.clear();
|
||||||
|
_hoverPick.ownerType = RenderObject::OwnerType::None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,6 +805,9 @@ void VulkanEngine::run()
|
|||||||
{
|
{
|
||||||
_lastPick.mesh = hitObject.sourceMesh;
|
_lastPick.mesh = hitObject.sourceMesh;
|
||||||
_lastPick.scene = hitObject.sourceScene;
|
_lastPick.scene = hitObject.sourceScene;
|
||||||
|
_lastPick.node = hitObject.sourceNode;
|
||||||
|
_lastPick.ownerType = hitObject.ownerType;
|
||||||
|
_lastPick.ownerName = hitObject.ownerName;
|
||||||
_lastPick.worldPos = hitPos;
|
_lastPick.worldPos = hitPos;
|
||||||
_lastPick.worldTransform = hitObject.transform;
|
_lastPick.worldTransform = hitObject.transform;
|
||||||
_lastPick.firstIndex = hitObject.firstIndex;
|
_lastPick.firstIndex = hitObject.firstIndex;
|
||||||
@@ -790,6 +819,8 @@ void VulkanEngine::run()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_lastPick.valid = false;
|
_lastPick.valid = false;
|
||||||
|
_lastPick.ownerName.clear();
|
||||||
|
_lastPick.ownerType = RenderObject::OwnerType::None;
|
||||||
_lastPickObjectID = 0;
|
_lastPickObjectID = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -809,10 +840,13 @@ void VulkanEngine::run()
|
|||||||
PickInfo info{};
|
PickInfo info{};
|
||||||
info.mesh = obj.sourceMesh;
|
info.mesh = obj.sourceMesh;
|
||||||
info.scene = obj.sourceScene;
|
info.scene = obj.sourceScene;
|
||||||
|
info.node = obj.sourceNode;
|
||||||
|
info.ownerType = obj.ownerType;
|
||||||
|
info.ownerName = obj.ownerName;
|
||||||
// Use bounds origin transformed to world as a representative point.
|
// Use bounds origin transformed to world as a representative point.
|
||||||
glm::vec3 centerWorld = glm::vec3(obj.transform * glm::vec4(obj.bounds.origin, 1.0f));
|
glm::vec3 centerWorld = glm::vec3(obj.transform * glm::vec4(obj.bounds.origin, 1.0f));
|
||||||
info.worldPos = centerWorld;
|
info.worldPos = centerWorld;
|
||||||
info.worldTransform = obj.transform;
|
info.worldTransform = obj.transform;
|
||||||
info.firstIndex = obj.firstIndex;
|
info.firstIndex = obj.firstIndex;
|
||||||
info.indexCount = obj.indexCount;
|
info.indexCount = obj.indexCount;
|
||||||
info.surfaceIndex = obj.surfaceIndex;
|
info.surfaceIndex = obj.surfaceIndex;
|
||||||
@@ -856,6 +890,8 @@ void VulkanEngine::run()
|
|||||||
{
|
{
|
||||||
// No object under cursor in ID buffer: clear last pick.
|
// No object under cursor in ID buffer: clear last pick.
|
||||||
_lastPick.valid = false;
|
_lastPick.valid = false;
|
||||||
|
_lastPick.ownerName.clear();
|
||||||
|
_lastPick.ownerType = RenderObject::OwnerType::None;
|
||||||
_lastPickObjectID = 0;
|
_lastPickObjectID = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -868,6 +904,9 @@ void VulkanEngine::run()
|
|||||||
glm::vec3 fallbackPos = glm::vec3(picked.transform[3]);
|
glm::vec3 fallbackPos = glm::vec3(picked.transform[3]);
|
||||||
_lastPick.mesh = picked.sourceMesh;
|
_lastPick.mesh = picked.sourceMesh;
|
||||||
_lastPick.scene = picked.sourceScene;
|
_lastPick.scene = picked.sourceScene;
|
||||||
|
_lastPick.node = picked.sourceNode;
|
||||||
|
_lastPick.ownerType = picked.ownerType;
|
||||||
|
_lastPick.ownerName = picked.ownerName;
|
||||||
_lastPick.worldPos = fallbackPos;
|
_lastPick.worldPos = fallbackPos;
|
||||||
_lastPick.worldTransform = picked.transform;
|
_lastPick.worldTransform = picked.transform;
|
||||||
_lastPick.firstIndex = picked.firstIndex;
|
_lastPick.firstIndex = picked.firstIndex;
|
||||||
@@ -878,6 +917,8 @@ void VulkanEngine::run()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_lastPick.valid = false;
|
_lastPick.valid = false;
|
||||||
|
_lastPick.ownerName.clear();
|
||||||
|
_lastPick.ownerType = RenderObject::OwnerType::None;
|
||||||
_lastPickObjectID = 0;
|
_lastPickObjectID = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -968,6 +1009,7 @@ void MeshNode::Draw(const glm::mat4 &topMatrix, DrawContext &ctx)
|
|||||||
def.surfaceIndex = i;
|
def.surfaceIndex = i;
|
||||||
def.objectID = ctx.nextID++;
|
def.objectID = ctx.nextID++;
|
||||||
def.sourceScene = scene;
|
def.sourceScene = scene;
|
||||||
|
def.sourceNode = this;
|
||||||
|
|
||||||
if (s.material->data.passType == MaterialPass::Transparent)
|
if (s.material->data.passType == MaterialPass::Transparent)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -120,6 +120,9 @@ public:
|
|||||||
{
|
{
|
||||||
MeshAsset *mesh = nullptr;
|
MeshAsset *mesh = nullptr;
|
||||||
LoadedGLTF *scene = nullptr;
|
LoadedGLTF *scene = nullptr;
|
||||||
|
Node *node = nullptr;
|
||||||
|
RenderObject::OwnerType ownerType = RenderObject::OwnerType::None;
|
||||||
|
std::string ownerName;
|
||||||
glm::vec3 worldPos{0.0f};
|
glm::vec3 worldPos{0.0f};
|
||||||
glm::mat4 worldTransform{1.0f};
|
glm::mat4 worldTransform{1.0f};
|
||||||
uint32_t indexCount = 0;
|
uint32_t indexCount = 0;
|
||||||
@@ -174,6 +177,12 @@ public:
|
|||||||
// Query a conservative streaming texture budget for the texture cache.
|
// Query a conservative streaming texture budget for the texture cache.
|
||||||
size_t query_texture_budget_bytes() const;
|
size_t query_texture_budget_bytes() const;
|
||||||
|
|
||||||
|
// Convenience helper: load a glTF from assets/models and add it as a runtime instance.
|
||||||
|
// modelRelativePath is relative to the AssetManager model root.
|
||||||
|
bool addGLTFInstance(const std::string &instanceName,
|
||||||
|
const std::string &modelRelativePath,
|
||||||
|
const glm::mat4 &transform = glm::mat4(1.f));
|
||||||
|
|
||||||
bool resize_requested{false};
|
bool resize_requested{false};
|
||||||
bool freeze_rendering{false};
|
bool freeze_rendering{false};
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -34,6 +34,9 @@ void SceneManager::update_scene()
|
|||||||
{
|
{
|
||||||
auto start = std::chrono::system_clock::now();
|
auto start = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
// Release any GLTF assets that were scheduled for safe destruction after GPU idle.
|
||||||
|
pendingGLTFRelease.clear();
|
||||||
|
|
||||||
mainDrawContext.OpaqueSurfaces.clear();
|
mainDrawContext.OpaqueSurfaces.clear();
|
||||||
mainDrawContext.TransparentSurfaces.clear();
|
mainDrawContext.TransparentSurfaces.clear();
|
||||||
mainDrawContext.nextID = 1;
|
mainDrawContext.nextID = 1;
|
||||||
@@ -78,12 +81,30 @@ void SceneManager::update_scene()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto tagOwner = [&](RenderObject::OwnerType type, const std::string &name,
|
||||||
|
size_t opaqueBegin, size_t transpBegin)
|
||||||
|
{
|
||||||
|
for (size_t i = opaqueBegin; i < mainDrawContext.OpaqueSurfaces.size(); ++i)
|
||||||
|
{
|
||||||
|
mainDrawContext.OpaqueSurfaces[i].ownerType = type;
|
||||||
|
mainDrawContext.OpaqueSurfaces[i].ownerName = name;
|
||||||
|
}
|
||||||
|
for (size_t i = transpBegin; i < mainDrawContext.TransparentSurfaces.size(); ++i)
|
||||||
|
{
|
||||||
|
mainDrawContext.TransparentSurfaces[i].ownerType = type;
|
||||||
|
mainDrawContext.TransparentSurfaces[i].ownerName = name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Draw all loaded GLTF scenes (static world)
|
// Draw all loaded GLTF scenes (static world)
|
||||||
for (auto &[name, scene] : loadedScenes)
|
for (auto &[name, scene] : loadedScenes)
|
||||||
{
|
{
|
||||||
if (scene)
|
if (scene)
|
||||||
{
|
{
|
||||||
|
const size_t opaqueStart = mainDrawContext.OpaqueSurfaces.size();
|
||||||
|
const size_t transpStart = mainDrawContext.TransparentSurfaces.size();
|
||||||
scene->Draw(glm::mat4{1.f}, mainDrawContext);
|
scene->Draw(glm::mat4{1.f}, mainDrawContext);
|
||||||
|
tagOwner(RenderObject::OwnerType::StaticGLTF, name, opaqueStart, transpStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +114,10 @@ void SceneManager::update_scene()
|
|||||||
const GLTFInstance &inst = kv.second;
|
const GLTFInstance &inst = kv.second;
|
||||||
if (inst.scene)
|
if (inst.scene)
|
||||||
{
|
{
|
||||||
|
const size_t opaqueStart = mainDrawContext.OpaqueSurfaces.size();
|
||||||
|
const size_t transpStart = mainDrawContext.TransparentSurfaces.size();
|
||||||
inst.scene->Draw(inst.transform, mainDrawContext);
|
inst.scene->Draw(inst.transform, mainDrawContext);
|
||||||
|
tagOwner(RenderObject::OwnerType::GLTFInstance, kv.first, opaqueStart, transpStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +147,8 @@ void SceneManager::update_scene()
|
|||||||
obj.sourceMesh = inst.mesh.get();
|
obj.sourceMesh = inst.mesh.get();
|
||||||
obj.surfaceIndex = surfaceIndex++;
|
obj.surfaceIndex = surfaceIndex++;
|
||||||
obj.objectID = mainDrawContext.nextID++;
|
obj.objectID = mainDrawContext.nextID++;
|
||||||
|
obj.ownerType = RenderObject::OwnerType::MeshInstance;
|
||||||
|
obj.ownerName = kv.first;
|
||||||
if (obj.material->passType == MaterialPass::Transparent)
|
if (obj.material->passType == MaterialPass::Transparent)
|
||||||
{
|
{
|
||||||
mainDrawContext.TransparentSurfaces.push_back(obj);
|
mainDrawContext.TransparentSurfaces.push_back(obj);
|
||||||
@@ -299,7 +325,17 @@ void SceneManager::addGLTFInstance(const std::string &name, std::shared_ptr<Load
|
|||||||
|
|
||||||
bool SceneManager::removeGLTFInstance(const std::string &name)
|
bool SceneManager::removeGLTFInstance(const std::string &name)
|
||||||
{
|
{
|
||||||
return dynamicGLTFInstances.erase(name) > 0;
|
auto it = dynamicGLTFInstances.find(name);
|
||||||
|
if (it == dynamicGLTFInstances.end()) return false;
|
||||||
|
|
||||||
|
// Defer destruction until after the next frame fence (update_scene).
|
||||||
|
if (it->second.scene)
|
||||||
|
{
|
||||||
|
pendingGLTFRelease.push_back(it->second.scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamicGLTFInstances.erase(it);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SceneManager::setGLTFInstanceTransform(const std::string &name, const glm::mat4 &transform)
|
bool SceneManager::setGLTFInstanceTransform(const std::string &name, const glm::mat4 &transform)
|
||||||
@@ -312,6 +348,13 @@ bool SceneManager::setGLTFInstanceTransform(const std::string &name, const glm::
|
|||||||
|
|
||||||
void SceneManager::clearGLTFInstances()
|
void SceneManager::clearGLTFInstances()
|
||||||
{
|
{
|
||||||
|
for (auto &kv : dynamicGLTFInstances)
|
||||||
|
{
|
||||||
|
if (kv.second.scene)
|
||||||
|
{
|
||||||
|
pendingGLTFRelease.push_back(kv.second.scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
dynamicGLTFInstances.clear();
|
dynamicGLTFInstances.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <glm/vec2.hpp>
|
#include <glm/vec2.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "scene/vk_loader.h"
|
#include "scene/vk_loader.h"
|
||||||
class EngineContext;
|
class EngineContext;
|
||||||
@@ -28,8 +29,19 @@ struct RenderObject
|
|||||||
uint32_t surfaceIndex = 0;
|
uint32_t surfaceIndex = 0;
|
||||||
// Unique per-draw identifier for ID-buffer picking (0 = none).
|
// Unique per-draw identifier for ID-buffer picking (0 = none).
|
||||||
uint32_t objectID = 0;
|
uint32_t objectID = 0;
|
||||||
// Optional owning glTF scene for this draw (null for procedural/dynamic meshes).
|
// Optional logical owner for editor/picking (instance name etc.).
|
||||||
|
enum class OwnerType : uint8_t
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
StaticGLTF, // loaded scene
|
||||||
|
GLTFInstance, // runtime glTF instance with transform
|
||||||
|
MeshInstance // dynamic primitive/mesh instance
|
||||||
|
};
|
||||||
|
OwnerType ownerType = OwnerType::None;
|
||||||
|
std::string ownerName;
|
||||||
|
// Optional owning glTF scene and node for this draw (null for procedural/dynamic meshes).
|
||||||
LoadedGLTF *sourceScene = nullptr;
|
LoadedGLTF *sourceScene = nullptr;
|
||||||
|
Node *sourceNode = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DrawContext
|
struct DrawContext
|
||||||
@@ -137,6 +149,9 @@ private:
|
|||||||
std::unordered_map<std::string, std::shared_ptr<Node> > loadedNodes;
|
std::unordered_map<std::string, std::shared_ptr<Node> > loadedNodes;
|
||||||
std::unordered_map<std::string, MeshInstance> dynamicMeshInstances;
|
std::unordered_map<std::string, MeshInstance> dynamicMeshInstances;
|
||||||
std::unordered_map<std::string, GLTFInstance> dynamicGLTFInstances;
|
std::unordered_map<std::string, GLTFInstance> dynamicGLTFInstances;
|
||||||
|
// Keep GLTF assets alive until after the next frame fence to avoid destroying
|
||||||
|
// GPU resources that might still be in-flight.
|
||||||
|
std::vector<std::shared_ptr<LoadedGLTF>> pendingGLTFRelease;
|
||||||
|
|
||||||
PickingDebug pickingDebug{};
|
PickingDebug pickingDebug{};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user