mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 19:36:20 +03:00
413 lines
11 KiB
C++
413 lines
11 KiB
C++
#include "staticmesh_component.h"
|
|
|
|
#include <iconFontcppHeaders/IconsFontAwesome6.h>
|
|
#include <editor/widgets/content.h>
|
|
#include <editor/editor.h>
|
|
#include <engine/asset/asset_manager.h>
|
|
#include <engine/asset/asset_staticmesh.h>
|
|
#include <asset/asset_material.h>
|
|
|
|
|
|
namespace engine
|
|
{
|
|
constexpr size_t kMinSubMeshNumStartParallel = 250;
|
|
|
|
bool StaticMeshComponent::uiDrawComponent()
|
|
{
|
|
static const auto& meta = StaticMeshComponent::uiComponentReflection();
|
|
|
|
auto drawStaticMeshSelect = [&]()
|
|
{
|
|
static const auto suffix = AssetStaticMesh::getCDO()->getSuffix();
|
|
ImGui::Spacing();
|
|
const auto& set = getAssetManager()->getAssetTypeMap(suffix);
|
|
for (const auto& meshId : set)
|
|
{
|
|
auto asset = getAssetManager()->getAsset(meshId);
|
|
if (ImGui::MenuItem((std::string(" ") + ICON_FA_CHESS_PAWN" " + asset->getSaveInfo().getName()).c_str()))
|
|
{
|
|
setAssetUUID(meshId);
|
|
}
|
|
|
|
ui::hoverTip(asset->getSaveInfo().getStorePathU8().c_str());
|
|
}
|
|
};
|
|
|
|
bool bChangedValue = false;
|
|
{
|
|
ImGui::Unindent();
|
|
ui::beginGroupPanel("Basic");
|
|
|
|
if (getAssetUUID().empty())
|
|
{
|
|
ImGui::TextDisabled("Non-mesh set on the mesh component.");
|
|
ImGui::TextDisabled("Please select one mesh asset for this component.");
|
|
}
|
|
else
|
|
{
|
|
ImGui::TextDisabled("Staticmesh asset setting ready.");
|
|
ImGui::TextDisabled("Asset uuid: %s.", getAssetUUID().c_str());
|
|
}
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImTextureID set = Editor::get()->getClampToTransparentBorderImGuiTexture(getContext()->getBuiltinTextureTranslucent()->getReadyImage());
|
|
const float kItemDim = ImGui::GetTextLineHeightWithSpacing() * 5.0f;
|
|
|
|
ImGui::Image(set, { kItemDim , kItemDim });
|
|
ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 255, 80));
|
|
|
|
if (ImGui::BeginDragDropTarget())
|
|
{
|
|
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(Editor::getDragDropAssetsName()))
|
|
{
|
|
const auto& dragAssets = Editor::get()->getDragDropAssets();
|
|
if (dragAssets.selectAssets.size() == 1)
|
|
{
|
|
const std::filesystem::path& assetPath = *dragAssets.selectAssets.begin();
|
|
if (AssetStaticMesh::isStaticMesh(assetPath.extension().string().c_str()))
|
|
{
|
|
auto meshAsset = getAssetManager()->getOrLoadAsset<AssetStaticMesh>(assetPath).lock();
|
|
|
|
this->setAssetUUID(meshAsset->getSaveInfo().getUUID());
|
|
}
|
|
}
|
|
}
|
|
ImGui::EndDragDropTarget();
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
ImGui::BeginGroup();
|
|
|
|
static const std::string selectButtonName = meta.iconCreated + " Chose ";
|
|
if (ImGui::Button(selectButtonName.c_str()))
|
|
ImGui::OpenPopup("StaticMeshSelectPopUp");
|
|
if (ImGui::BeginPopup("StaticMeshSelectPopUp"))
|
|
{
|
|
ImGui::TextDisabled("Select StaticMesh...");
|
|
ImGui::Spacing();
|
|
drawStaticMeshSelect();
|
|
ImGui::EndPopup();
|
|
}
|
|
|
|
ImGui::TextDisabled("Submesh count: %d.", getSubmeshCount());
|
|
ImGui::TextDisabled("Vertices count: %d.", getVerticesCount());
|
|
ImGui::TextDisabled("Indices count: %d.", getIndicesCount());
|
|
|
|
ImGui::EndGroup();
|
|
|
|
ui::endGroupPanel();
|
|
ImGui::Indent();
|
|
|
|
}
|
|
return bChangedValue;
|
|
}
|
|
|
|
const UIComponentReflectionDetailed& StaticMeshComponent::uiComponentReflection()
|
|
{
|
|
static const UIComponentReflectionDetailed reflection =
|
|
{
|
|
.bOptionalCreated = true,
|
|
.iconCreated = ICON_FA_BUILDING + std::string(" StaticMesh"),
|
|
};
|
|
return reflection;
|
|
}
|
|
|
|
void StaticMeshComponent::tick(const RuntimeModuleTickData& tickData)
|
|
{
|
|
if (!m_assetUUID.empty() && m_meshCache.empty())
|
|
{
|
|
buildCacheSync();
|
|
}
|
|
}
|
|
|
|
bool StaticMeshComponent::setAssetUUID(const UUID& in)
|
|
{
|
|
if (m_assetUUID != in)
|
|
{
|
|
clearCache();
|
|
m_assetUUID = in;
|
|
|
|
buildCacheSync();
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
uint32_t StaticMeshComponent::getSubmeshCount() const
|
|
{
|
|
if (auto mesh = m_meshCache.assetWeakPtr.lock())
|
|
{
|
|
return (uint32_t)mesh->getSubMeshes().size();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint32_t StaticMeshComponent::getVerticesCount() const
|
|
{
|
|
if (auto mesh = m_meshCache.assetWeakPtr.lock())
|
|
{
|
|
return mesh->getVerticesCount();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint32_t StaticMeshComponent::getIndicesCount() const
|
|
{
|
|
if (auto mesh = m_meshCache.assetWeakPtr.lock())
|
|
{
|
|
return mesh->getIndicesCount();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline void fillVkAccelerationStructureInstance(VkAccelerationStructureInstanceKHR& as, uint64_t address)
|
|
{
|
|
as.accelerationStructureReference = address;
|
|
as.mask = 0xFF;
|
|
|
|
// NOTE: VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR // Faster.
|
|
// VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR // Two side.
|
|
as.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
|
as.instanceShaderBindingTableRecordOffset = 0;
|
|
}
|
|
|
|
// TODO: Add some cache.
|
|
void StaticMeshComponent::collectRenderObject(RenderScene& renderScene)
|
|
{
|
|
if (m_meshCache.cacheMeshGPU && m_meshCache.cacheMeshGPU->isAssetReady())
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
math::mat4 modelMatrix = getNode()->getTransform()->getWorldMatrix();
|
|
math::mat4 modelMatrixPrev = getNode()->getTransform()->getPrevWorldMatrix();
|
|
|
|
|
|
|
|
const bool bSelected = getNode()->editorSelected();
|
|
const auto sceneNodeId = getNode()->getId();
|
|
if (auto asset = m_meshCache.assetWeakPtr.lock())
|
|
{
|
|
// Update aabb.
|
|
{
|
|
AABBBounds newAABB{};
|
|
newAABB.min = asset->getMinPosition();
|
|
newAABB.max = asset->getMaxPosition();
|
|
|
|
newAABB.transform(modelMatrix);
|
|
|
|
auto& aabb = renderScene.getAABBBounds();
|
|
aabb.min = math::min(aabb.min, newAABB.min);
|
|
aabb.max = math::max(aabb.max, newAABB.max);
|
|
}
|
|
|
|
auto& collector = renderScene.getObjectCollector();
|
|
const size_t objectOffsetId = collector.size();
|
|
|
|
auto& meshInfos = m_meshCache.cachePerObjectData;
|
|
auto& rtInfos = m_meshCache.cachePerObjectAs;
|
|
|
|
VkAccelerationStructureInstanceKHR instanceTamplate{};
|
|
{
|
|
math::mat4 temp = math::transpose(modelMatrix);
|
|
memcpy(&instanceTamplate.transform, &temp, sizeof(VkTransformMatrixKHR));
|
|
}
|
|
|
|
if (m_meshCache.bNewlyCreated)
|
|
{
|
|
m_meshCache.bNewlyCreated = false;
|
|
renderScene.unvalidTLAS();
|
|
}
|
|
|
|
auto updateObject = [&](size_t index)
|
|
{
|
|
auto& object = meshInfos[index];
|
|
object.modelMatrix = modelMatrix;
|
|
object.modelMatrixPrev = modelMatrixPrev;
|
|
object.sceneNodeId = sceneNodeId;
|
|
object.bSelected = bSelected ? 1U : 0U;
|
|
|
|
auto& rtObject = rtInfos[index];
|
|
rtObject.transform = instanceTamplate.transform;
|
|
|
|
// NOTE: instance custom index used to index object info.
|
|
rtObject.instanceCustomIndex = objectOffsetId + index;
|
|
};
|
|
|
|
if (meshInfos.size() > kMinSubMeshNumStartParallel)
|
|
{
|
|
const auto loop = [&, this](const size_t loopStart, const size_t loopEnd)
|
|
{
|
|
for (size_t i = loopStart; i < loopEnd; ++i)
|
|
{
|
|
updateObject(i);
|
|
}
|
|
};
|
|
Engine::get()->getThreadPool()->parallelizeLoop(0, meshInfos.size(), loop).wait();
|
|
}
|
|
else
|
|
{
|
|
for (size_t i = 0; i < meshInfos.size(); i++)
|
|
{
|
|
updateObject(i);
|
|
}
|
|
}
|
|
|
|
{
|
|
collector.insert(collector.end(),
|
|
m_meshCache.cachePerObjectData.begin(),
|
|
m_meshCache.cachePerObjectData.end());
|
|
}
|
|
|
|
|
|
if (getContext()->getGraphicsState().bSupportRaytrace)
|
|
{
|
|
auto& asInstances = renderScene.getBLASObjectCollector();
|
|
asInstances.insert(asInstances.end(), m_meshCache.cachePerObjectAs.begin(), m_meshCache.cachePerObjectAs.end());
|
|
}
|
|
}
|
|
}
|
|
|
|
void StaticMeshComponent::clearCache()
|
|
{
|
|
m_meshCache.clear();
|
|
}
|
|
|
|
void StaticMeshComponent::buildCacheSync()
|
|
{
|
|
// Pre-return if asset uuid is empty.
|
|
if (m_assetUUID.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Update cache.
|
|
if (!m_meshCache.assetWeakPtr.lock())
|
|
{
|
|
CHECK(m_meshCache.empty());
|
|
CHECK(m_meshCache.cachePerObjectMaterials.empty());
|
|
|
|
m_meshCache.assetWeakPtr = std::dynamic_pointer_cast<AssetStaticMesh>(
|
|
getAssetManager()->getAsset(m_assetUUID));
|
|
|
|
auto meshAsset = m_meshCache.assetWeakPtr.lock();
|
|
m_meshCache.cacheMeshGPU = meshAsset->getGPUAsset();
|
|
|
|
// Fill per-object cache and material.
|
|
const auto& submeshes = meshAsset->getSubMeshes();
|
|
m_meshCache.resize(submeshes.size());
|
|
for (size_t i = 0; i < submeshes.size(); i++)
|
|
{
|
|
const auto& submesh = submeshes[i];
|
|
auto& cacheObject = m_meshCache.cachePerObjectData.at(i);
|
|
|
|
// Update mesh info data.
|
|
{
|
|
cacheObject.meshInfoData.meshType = EMeshType_StaticMesh;
|
|
cacheObject.meshInfoData.indicesCount = submesh.indicesCount;
|
|
cacheObject.meshInfoData.indexStartPosition = submesh.indicesStart;
|
|
cacheObject.meshInfoData.indicesArrayId = m_meshCache.cacheMeshGPU->getIndices().bindless;
|
|
|
|
cacheObject.meshInfoData.normalsArrayId = m_meshCache.cacheMeshGPU->getNormals().bindless;
|
|
cacheObject.meshInfoData.tangentsArrayId = m_meshCache.cacheMeshGPU->getTangents().bindless;
|
|
cacheObject.meshInfoData.positionsArrayId = m_meshCache.cacheMeshGPU->getPositions().bindless;
|
|
cacheObject.meshInfoData.uv0sArrayId = m_meshCache.cacheMeshGPU->getUV0s().bindless;
|
|
|
|
cacheObject.meshInfoData.sphereBounds = math::vec4(submesh.bounds.origin, submesh.bounds.radius);
|
|
cacheObject.meshInfoData.extents = submesh.bounds.extents;
|
|
cacheObject.meshInfoData.submeshIndex = i;
|
|
}
|
|
|
|
m_meshCache.cacheMaterialId[i] = submesh.material;
|
|
if (submesh.material.empty())
|
|
{
|
|
cacheObject.materialInfoData = buildDefaultBSDFMaterialInfo();
|
|
}
|
|
else
|
|
{
|
|
// Insert material if no exist cache.
|
|
auto& cacheMaterialPair = m_meshCache.cachePerObjectMaterials[submesh.material];
|
|
|
|
auto material = std::static_pointer_cast<AssetMaterial>(
|
|
getAssetManager()->getAsset(submesh.material));
|
|
|
|
cacheMaterialPair.handle = material->buildCache();
|
|
cacheMaterialPair.asset = material;
|
|
|
|
cacheObject.materialInfoData = material->getGPUOnly();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sync until all process finish.
|
|
getContext()->waitDeviceIdle();
|
|
|
|
// Update material after sync.
|
|
updateMaterials();
|
|
|
|
if (getContext()->getGraphicsState().bSupportRaytrace)
|
|
{
|
|
auto& rtInfos = m_meshCache.cachePerObjectAs;
|
|
|
|
// Try build blas when loading ready.
|
|
auto& blas = m_meshCache.cacheMeshGPU->getOrBuilddBLAS();
|
|
for (size_t i = 0; i < rtInfos.size(); i++)
|
|
{
|
|
auto& cacheAs = rtInfos.at(i);
|
|
fillVkAccelerationStructureInstance(cacheAs, blas.getBlasDeviceAddress(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
void StaticMeshComponent::updateMaterials()
|
|
{
|
|
if (!m_meshCache.assetWeakPtr.lock())
|
|
{
|
|
return;
|
|
}
|
|
CHECK(m_meshCache.cacheMeshGPU);
|
|
|
|
for (auto& materialPair : m_meshCache.cachePerObjectMaterials)
|
|
{
|
|
auto& material = materialPair.second.asset;
|
|
material->getAndTryBuildGPU();
|
|
}
|
|
|
|
if (m_meshCache.cachePerObjectData.size() > kMinSubMeshNumStartParallel)
|
|
{
|
|
const auto loop = [this](const size_t loopStart, const size_t loopEnd)
|
|
{
|
|
for (size_t i = loopStart; i < loopEnd; ++i)
|
|
{
|
|
auto& object = m_meshCache.cachePerObjectData[i];
|
|
|
|
const auto& id = m_meshCache.cacheMaterialId[i];
|
|
const auto& material = m_meshCache.cachePerObjectMaterials.at(id).asset;
|
|
|
|
object.materialInfoData = material->getGPUOnly();
|
|
}
|
|
};
|
|
Engine::get()->getThreadPool()->parallelizeLoop(0, m_meshCache.cachePerObjectData.size(), loop).wait();
|
|
}
|
|
else
|
|
{
|
|
for (size_t i = 0; i < m_meshCache.cachePerObjectData.size(); i++)
|
|
{
|
|
auto& object = m_meshCache.cachePerObjectData[i];
|
|
const auto& id = m_meshCache.cacheMaterialId[i];
|
|
|
|
if (!id.empty())
|
|
{
|
|
const auto& material = m_meshCache.cachePerObjectMaterials.at(id).asset;
|
|
object.materialInfoData = material->getGPUOnly();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |