mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 13:36:14 +03:00
775 lines
25 KiB
C++
775 lines
25 KiB
C++
#include "Pch.h"
|
|
#include "MeshManager.h"
|
|
#include "TextureManager.h"
|
|
#include "MaterialManager.h"
|
|
#include "AssetSystem.h"
|
|
#include "AssetRegistry.h"
|
|
#include "AssetArchive.h"
|
|
#include <nlohmann/json.hpp>
|
|
#include <stb/stb_image_write.h>
|
|
#include <stb/stb_image.h>
|
|
|
|
#pragma warning(disable: 4006)
|
|
|
|
#include <assimp/Importer.hpp>
|
|
#include <assimp/scene.h>
|
|
#include <assimp/postprocess.h>
|
|
#include <assimp/GltfMaterial.h>
|
|
|
|
namespace Flower
|
|
{
|
|
const UUID EngineMeshes::GBoxUUID = "12a68c4e-8352-4d97-a914-a0f4f4d1fd28";
|
|
const UUID EngineMeshes::GSphereUUID = "45f0d878-6d3f-11ed-a1eb-0242ac120002";
|
|
|
|
std::weak_ptr<GPUMeshAsset> EngineMeshes::GBoxPtrRef = {};
|
|
std::weak_ptr<GPUMeshAsset> EngineMeshes::GSpherePtrRef = {};
|
|
|
|
struct AssimpModelProcess
|
|
{
|
|
public:
|
|
std::filesystem::path folderPath;
|
|
|
|
std::vector<StaticMeshSubMesh> m_subMeshInfos{};
|
|
|
|
std::vector<StaticMeshVertex> m_vertices{};
|
|
std::vector<VertexIndexType> m_indices{};
|
|
|
|
// .................tex path...tex uuid........
|
|
std::unordered_map<std::string, UUID> m_texPathUUIDMap{ };
|
|
|
|
explicit AssimpModelProcess(const std::filesystem::path& in)
|
|
: folderPath(in)
|
|
{
|
|
|
|
}
|
|
|
|
StaticMeshSubMesh processMesh(aiMesh* mesh, const aiScene* scene, std::shared_ptr<RegistryEntry> materialFolderEntry, std::shared_ptr<RegistryEntry> texFolderEntry)
|
|
{
|
|
auto* assetSystem = GEngine->getRuntimeModule<AssetSystem>();
|
|
|
|
StaticMeshSubMesh subMeshInfo{};
|
|
subMeshInfo.indexStartPosition = (uint32_t)m_indices.size();
|
|
uint32_t indexOffset = (uint32_t)m_vertices.size();
|
|
|
|
std::vector<StaticMeshVertex> vertices{};
|
|
std::vector<VertexIndexType> indices{};
|
|
|
|
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
|
|
{
|
|
StaticMeshVertex vertex;
|
|
|
|
glm::vec3 vector{};
|
|
vector.x = mesh->mVertices[i].x;
|
|
vector.y = mesh->mVertices[i].y;
|
|
vector.z = mesh->mVertices[i].z;
|
|
vertex.position = vector;
|
|
|
|
vector.x = mesh->mNormals[i].x;
|
|
vector.y = mesh->mNormals[i].y;
|
|
vector.z = mesh->mNormals[i].z;
|
|
vertex.normal = vector;
|
|
|
|
if (mesh->mTextureCoords[0])
|
|
{
|
|
glm::vec2 vec{};
|
|
vec.x = mesh->mTextureCoords[0][i].x;
|
|
vec.y = mesh->mTextureCoords[0][i].y;
|
|
vertex.uv0 = vec;
|
|
}
|
|
else
|
|
{
|
|
vertex.uv0 = glm::vec2(0.0f, 0.0f);
|
|
}
|
|
|
|
glm::vec4 tangentVec{};
|
|
tangentVec.x = mesh->mTangents[i].x;
|
|
tangentVec.y = mesh->mTangents[i].y;
|
|
tangentVec.z = mesh->mTangents[i].z;
|
|
|
|
// Tangent vector.
|
|
vector.x = mesh->mTangents[i].x;
|
|
vector.y = mesh->mTangents[i].y;
|
|
vector.z = mesh->mTangents[i].z;
|
|
|
|
glm::vec3 bitangent{};
|
|
bitangent.x = mesh->mBitangents[i].x;
|
|
bitangent.y = mesh->mBitangents[i].y;
|
|
bitangent.z = mesh->mBitangents[i].z;
|
|
|
|
// Tangent sign process.
|
|
tangentVec.w = glm::sign(glm::dot(glm::normalize(bitangent), glm::normalize(glm::cross(vertex.normal, vector))));
|
|
vertex.tangent = tangentVec;
|
|
vertices.push_back(vertex);
|
|
}
|
|
|
|
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
|
|
{
|
|
aiFace face = mesh->mFaces[i];
|
|
for (unsigned int j = 0; j < face.mNumIndices; j++)
|
|
{
|
|
indices.push_back(indexOffset + face.mIndices[j]);
|
|
}
|
|
}
|
|
|
|
m_vertices.insert(m_vertices.end(), vertices.begin(), vertices.end());
|
|
m_indices.insert(m_indices.end(), indices.begin(), indices.end());
|
|
|
|
subMeshInfo.indexCount = (uint32_t)indices.size();
|
|
|
|
// aabb bounds process.
|
|
auto aabbMax = mesh->mAABB.mMax;
|
|
auto aabbMin = mesh->mAABB.mMin;
|
|
auto aabbExt = (aabbMax - aabbMin) * 0.5f;
|
|
auto aabbCenter = aabbExt + aabbMin;
|
|
subMeshInfo.renderBounds.extents[0] = aabbExt.x;
|
|
subMeshInfo.renderBounds.extents[1] = aabbExt.y;
|
|
subMeshInfo.renderBounds.extents[2] = aabbExt.z;
|
|
subMeshInfo.renderBounds.origin[0] = aabbCenter.x;
|
|
subMeshInfo.renderBounds.origin[1] = aabbCenter.y;
|
|
subMeshInfo.renderBounds.origin[2] = aabbCenter.z;
|
|
subMeshInfo.renderBounds.radius = glm::distance(
|
|
glm::vec3(aabbMax.x, aabbMax.y, aabbMax.z),
|
|
glm::vec3(aabbCenter.x, aabbCenter.y, aabbCenter.z)
|
|
);
|
|
|
|
// standard pbr texture prepare.
|
|
aiString baseColorTextures{};
|
|
aiString normalTextures{};
|
|
aiString specularTextures{};
|
|
aiString aoTextures{};
|
|
aiString emissiveTextures{};
|
|
|
|
auto tryFetechTexture = [&](const char* pathIn, std::string& OutId, bool bSrgb, float cutoff)
|
|
{
|
|
const auto path = (folderPath / pathIn).string();
|
|
if (m_texPathUUIDMap.contains(path))
|
|
{
|
|
OutId = m_texPathUUIDMap[path];
|
|
}
|
|
else
|
|
{
|
|
OutId = assetSystem->importAsset(path, EAssetType::Texture, texFolderEntry, ImportOptions
|
|
{
|
|
.texOptions = ImportTextureOptions
|
|
{
|
|
.bSrgb = bSrgb,
|
|
.bBuildMipmap = true,
|
|
.cutoff = cutoff,
|
|
}
|
|
});
|
|
m_texPathUUIDMap[path] = OutId;
|
|
}
|
|
};
|
|
|
|
if (mesh->mMaterialIndex >= 0 && materialFolderEntry)
|
|
{
|
|
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
|
|
static const std::string materialName = "_mat";
|
|
|
|
// Create new material.
|
|
auto newMaterial = std::make_shared<StandardPBRMaterialHeader>((material->GetName().C_Str() + materialName).c_str());
|
|
|
|
{
|
|
// register in map.
|
|
AssetRegistryManager::get()->registerAssetMap(newMaterial, EAssetType::Material);
|
|
|
|
// add new entry file for materials folder entry.
|
|
std::shared_ptr<RegistryEntry> newRegistry = std::make_shared<RegistryEntry>(newMaterial->getHeaderUUID(), newMaterial->getName());
|
|
AssetRegistryManager::get()->addChild(materialFolderEntry, newRegistry, true);
|
|
}
|
|
|
|
if (material->GetTextureCount(aiTextureType_DIFFUSE) > 0)
|
|
{
|
|
material->GetTexture(aiTextureType_DIFFUSE, 0, &baseColorTextures);
|
|
tryFetechTexture(baseColorTextures.C_Str(), newMaterial->baseColorTexture, true, 0.5f); // SRGB
|
|
}
|
|
|
|
if (material->GetTextureCount(aiTextureType_HEIGHT) > 0)
|
|
{
|
|
material->GetTexture(aiTextureType_HEIGHT, 0, &normalTextures);
|
|
tryFetechTexture(normalTextures.C_Str(), newMaterial->normalTexture, false, 1.0f); // LINEAR
|
|
}
|
|
|
|
if (material->GetTextureCount(aiTextureType_SPECULAR) > 0)
|
|
{
|
|
material->GetTexture(aiTextureType_SPECULAR, 0, &specularTextures);
|
|
tryFetechTexture(specularTextures.C_Str(), newMaterial->specularTexture, false, 1.0f); // Linear
|
|
}
|
|
|
|
// AO
|
|
if (material->GetTextureCount(aiTextureType_AMBIENT) > 0)
|
|
{
|
|
material->GetTexture(aiTextureType_AMBIENT, 0, &aoTextures);
|
|
tryFetechTexture(aoTextures.C_Str(), newMaterial->aoTexture, false, 1.0f); // Linear
|
|
}
|
|
|
|
if (material->GetTextureCount(aiTextureType_EMISSIVE) > 0)
|
|
{
|
|
material->GetTexture(aiTextureType_EMISSIVE, 0, &emissiveTextures);
|
|
tryFetechTexture(emissiveTextures.C_Str(), newMaterial->emissiveTexture, true, 1.0f); // SRGB
|
|
}
|
|
|
|
subMeshInfo.material = newMaterial->getHeaderUUID();
|
|
|
|
AssetRegistryManager::get()->markDirty();
|
|
}
|
|
else // no material found, keep empty.
|
|
{
|
|
subMeshInfo.material = {};
|
|
}
|
|
|
|
return subMeshInfo;
|
|
}
|
|
|
|
void processNode(aiNode* node, const aiScene* scene, std::shared_ptr<RegistryEntry> materialFolderEntry, std::shared_ptr<RegistryEntry> texFolderEntry)
|
|
{
|
|
for (unsigned int i = 0; i < node->mNumMeshes; i++)
|
|
{
|
|
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
|
|
m_subMeshInfos.push_back(processMesh(mesh, scene, materialFolderEntry, texFolderEntry));
|
|
}
|
|
|
|
for (unsigned int i = 0; i < node->mNumChildren; i++)
|
|
{
|
|
processNode(node->mChildren[i], scene, materialFolderEntry, texFolderEntry);
|
|
}
|
|
}
|
|
};
|
|
|
|
std::shared_ptr<StaticMeshRawDataLoadTask> StaticMeshRawDataLoadTask::buildFromPath(
|
|
const std::string& name,
|
|
const std::filesystem::path& path,
|
|
const UUID& uuid,
|
|
bool bPersistent)
|
|
{
|
|
Assimp::Importer importer;
|
|
const aiScene* scene = importer.ReadFile(path.string(),
|
|
aiProcessPreset_TargetRealtime_Fast | aiProcess_FlipUVs | aiProcess_GenBoundingBoxes);
|
|
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
|
|
{
|
|
LOG_ERROR("ERROR::ASSIMP::{0}", importer.GetErrorString());
|
|
return nullptr;
|
|
}
|
|
|
|
AssimpModelProcess processor(path.parent_path());
|
|
processor.processNode(scene->mRootNode, scene, nullptr, nullptr);
|
|
|
|
if (bPersistent)
|
|
{
|
|
CHECK(!MeshManager::get()->isAssetExist(uuid) && "Persistent asset has exist, don't register repeatly.");
|
|
}
|
|
|
|
auto newTask = std::make_shared<StaticMeshRawDataLoadTask>();
|
|
newTask->cacheVertexData.resize(processor.m_vertices.size() * sizeof(processor.m_vertices[0]));
|
|
newTask->cacheIndexData.resize(processor.m_indices.size() * sizeof(processor.m_indices[0]));
|
|
|
|
memcpy((void*)(newTask->cacheVertexData.data()), (void*)processor.m_vertices.data(), newTask->cacheVertexData.size());
|
|
memcpy((void*)(newTask->cacheIndexData.data()), (void*)processor.m_indices.data(), newTask->cacheIndexData.size());
|
|
|
|
GPUMeshAsset* fallback = nullptr;
|
|
if (!bPersistent)
|
|
{
|
|
fallback = MeshManager::get()->getMesh(EngineMeshes::GBoxUUID).get();
|
|
CHECK(fallback && "Non persistent asset must exist one fallback mesh.");
|
|
}
|
|
|
|
CHECK(sizeof(VertexIndexType) == 4); // uint32
|
|
auto newAsset = std::shared_ptr<GPUMeshAsset>(new GPUMeshAsset(
|
|
bPersistent,
|
|
fallback,
|
|
name,
|
|
processor.m_vertices.size() * sizeof(processor.m_vertices[0]),
|
|
sizeof(processor.m_vertices[0]),
|
|
processor.m_indices.size() * sizeof(processor.m_indices[0]),
|
|
VK_INDEX_TYPE_UINT32));
|
|
|
|
MeshManager::get()->insertGPUAsset(uuid, newAsset);
|
|
|
|
newTask->meshAssetGPU = newAsset;
|
|
|
|
return newTask;
|
|
}
|
|
|
|
bool StaticMeshAssetHeader::initFromRawStaticMesh(const std::filesystem::path& rawPath, std::shared_ptr<RegistryEntry> parentEntry)
|
|
{
|
|
Assimp::Importer importer;
|
|
const aiScene* scene = importer.ReadFile(rawPath.string(),
|
|
aiProcessPreset_TargetRealtime_Fast | aiProcess_FlipUVs | aiProcess_GenBoundingBoxes);
|
|
|
|
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
|
|
{
|
|
LOG_ERROR("ERROR::ASSIMP::{0}", importer.GetErrorString());
|
|
return false;
|
|
}
|
|
|
|
setCacheBinData(std::make_shared<StaticMeshAssetBin>(rawPath.filename().string()));
|
|
auto processingMeshBin = getBinData<StaticMeshAssetBin>();
|
|
|
|
if (parentEntry == nullptr)
|
|
{
|
|
parentEntry = AssetRegistryManager::get()->getRoot();
|
|
}
|
|
|
|
std::shared_ptr<RegistryEntry> meshFolderRegistry = std::make_shared<RegistryEntry>("", rawPath.stem().string() + "_Misc");
|
|
AssetRegistryManager::get()->addChild(parentEntry, meshFolderRegistry, true);
|
|
|
|
std::shared_ptr<RegistryEntry> texFolderRegistry = std::make_shared<RegistryEntry>("", "Texture");
|
|
AssetRegistryManager::get()->addChild(meshFolderRegistry, texFolderRegistry, true);
|
|
|
|
std::shared_ptr<RegistryEntry> materialFolderRegistry = std::make_shared<RegistryEntry>("", "Material");
|
|
AssetRegistryManager::get()->addChild(meshFolderRegistry, materialFolderRegistry, true);
|
|
|
|
AssimpModelProcess processor(rawPath.parent_path());
|
|
processor.processNode(scene->mRootNode, scene, materialFolderRegistry, texFolderRegistry);
|
|
|
|
m_subMeshes = processor.m_subMeshInfos;
|
|
processingMeshBin->m_vertices = processor.m_vertices;
|
|
processingMeshBin->m_indices = processor.m_indices;
|
|
|
|
m_indicesCount = processor.m_indices.size();
|
|
m_verticesCount = processor.m_vertices.size();
|
|
|
|
return true;
|
|
}
|
|
|
|
static std::string getRuntimeUniqueMeshAssetName(const std::string& in)
|
|
{
|
|
static size_t GRuntimeId = 0;
|
|
GRuntimeId++;
|
|
return "Flower_MeshAssetId:" + std::to_string(GRuntimeId) + in;
|
|
}
|
|
|
|
uint32_t indexTypeToSize(VkIndexType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case VK_INDEX_TYPE_UINT16: return sizeof(uint16_t);
|
|
case VK_INDEX_TYPE_UINT32: return sizeof(uint32_t);
|
|
case VK_INDEX_TYPE_UINT8_EXT: return sizeof(uint8_t);
|
|
default: CHECK_ENTRY();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
GPUMeshAsset::GPUMeshAsset(
|
|
bool bPersistent,
|
|
GPUMeshAsset* fallback,
|
|
const std::string& name,
|
|
VkDeviceSize vertexSize,
|
|
size_t singleVertexSize,
|
|
VkDeviceSize indexSize,
|
|
VkIndexType indexType)
|
|
: LRUAssetInterface(fallback, bPersistent)
|
|
, m_name(name)
|
|
{
|
|
CHECK(m_vertexBuffer == nullptr && "You must ensure mesh asset only init once.");
|
|
CHECK(m_indexBuffer == nullptr && "You must ensure mesh asset only init once.");
|
|
|
|
// Mesh info also support Ray trace info.
|
|
auto bufferFlagBasic = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
|
VmaAllocationCreateFlags bufferFlagVMA = {};
|
|
if (RHI::bSupportRayTrace)
|
|
{
|
|
bufferFlagBasic |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
|
bufferFlagVMA = {};
|
|
}
|
|
|
|
m_vertexBuffer = VulkanBuffer::create2(
|
|
getRuntimeUniqueMeshAssetName(name).c_str(),
|
|
bufferFlagBasic | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
bufferFlagVMA,
|
|
vertexSize
|
|
);
|
|
|
|
m_indexBuffer = VulkanBuffer::create2(
|
|
getRuntimeUniqueMeshAssetName(name).c_str(),
|
|
bufferFlagBasic | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
bufferFlagVMA,
|
|
indexSize
|
|
);
|
|
|
|
m_indexType = indexType;
|
|
m_singleIndexSize = sizeof(uint32_t);
|
|
m_indexCount = uint32_t(indexSize) / indexTypeToSize(indexType);
|
|
m_indexCountUint32Count = uint32_t(indexSize) / sizeof(uint32_t);
|
|
|
|
m_singleVertexSize = uint32_t(singleVertexSize);
|
|
m_vertexCount = uint32_t(vertexSize) / m_singleVertexSize;
|
|
m_vertexFloat32Count = uint32_t(vertexSize) / sizeof(float);
|
|
}
|
|
|
|
GPUMeshAsset::GPUMeshAsset(bool bPersistent, GPUMeshAsset* fallback, const std::string& name)
|
|
: LRUAssetInterface(fallback, bPersistent)
|
|
, m_name(name)
|
|
{
|
|
|
|
}
|
|
|
|
GPUMeshAsset::~GPUMeshAsset()
|
|
{
|
|
if (!m_bPersistent)
|
|
{
|
|
if (m_vertexBufferBindlessIndex != ~0)
|
|
{
|
|
MeshManager::get()->getBindlessVertexBuffers()->freeBindlessImpl(
|
|
m_vertexBufferBindlessIndex,
|
|
EngineMeshes::GBoxPtrRef.lock() ? EngineMeshes::GBoxPtrRef.lock()->m_vertexBuffer : nullptr);
|
|
}
|
|
if (m_indexBufferBindlessIndex != ~0)
|
|
{
|
|
MeshManager::get()->getBindlessIndexBuffers()->freeBindlessImpl(
|
|
m_indexBufferBindlessIndex,
|
|
EngineMeshes::GBoxPtrRef.lock() ? EngineMeshes::GBoxPtrRef.lock()->m_indexBuffer : nullptr);
|
|
}
|
|
}
|
|
|
|
m_indexBuffer.reset();
|
|
m_vertexBuffer.reset();
|
|
}
|
|
|
|
void GPUMeshAsset::prepareToUpload()
|
|
{
|
|
CHECK(m_vertexBufferBindlessIndex == ~0);
|
|
CHECK(m_indexBufferBindlessIndex == ~0);
|
|
}
|
|
|
|
void GPUMeshAsset::finishUpload()
|
|
{
|
|
m_vertexBufferBindlessIndex =
|
|
MeshManager::get()->getBindlessVertexBuffers()->updateBufferToBindlessDescriptorSet(
|
|
m_vertexBuffer->getVkBuffer(), 0, m_vertexBuffer->getSize());
|
|
|
|
m_indexBufferBindlessIndex =
|
|
MeshManager::get()->getBindlessIndexBuffers()->updateBufferToBindlessDescriptorSet(
|
|
m_indexBuffer->getVkBuffer(), 0, m_indexBuffer->getSize());
|
|
|
|
CHECK(m_vertexBufferBindlessIndex != ~0);
|
|
CHECK(m_indexBufferBindlessIndex != ~0);
|
|
}
|
|
|
|
AccelerateStructure* GPUMeshAsset::getOrBuilddBLAS()
|
|
{
|
|
if (m_blas == nullptr)
|
|
{
|
|
m_blas = std::make_unique<AccelerateStructure>();
|
|
|
|
VkDeviceOrHostAddressConstKHR vertexBufferDeviceAddress{};
|
|
VkDeviceOrHostAddressConstKHR indexBufferDeviceAddress{};
|
|
|
|
vertexBufferDeviceAddress.deviceAddress = m_vertexBuffer->getDeviceAddress();
|
|
indexBufferDeviceAddress.deviceAddress = m_indexBuffer->getDeviceAddress();
|
|
|
|
uint32_t numTriangles = static_cast<uint32_t>(m_indexCount) / 3;
|
|
uint32_t maxVertex = m_vertexCount;
|
|
uint32_t vertexStride = m_singleVertexSize;
|
|
|
|
// Build geometry.
|
|
VkAccelerationStructureGeometryKHR asGeometry{ };
|
|
asGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
|
|
asGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
|
asGeometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
|
asGeometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR;
|
|
asGeometry.geometry.triangles.vertexData = vertexBufferDeviceAddress;
|
|
asGeometry.geometry.triangles.indexData = indexBufferDeviceAddress;
|
|
asGeometry.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
|
|
asGeometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
|
|
asGeometry.geometry.triangles.maxVertex = maxVertex;
|
|
asGeometry.geometry.triangles.vertexStride = vertexStride;
|
|
|
|
// Get size info.
|
|
VkAccelerationStructureBuildGeometryInfoKHR asBuildGeometryInfo{};
|
|
asBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
|
|
asBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
|
asBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
|
asBuildGeometryInfo.geometryCount = 1;
|
|
asBuildGeometryInfo.pGeometries = &asGeometry;
|
|
|
|
VkAccelerationStructureBuildSizesInfoKHR asBuildSizesInfo{};
|
|
asBuildSizesInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
|
|
RHI::GetAccelerationStructureBuildSizes(
|
|
RHI::Device,
|
|
VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR,
|
|
&asBuildGeometryInfo,
|
|
&numTriangles,
|
|
&asBuildSizesInfo);
|
|
|
|
m_blas->create(getRuntimeUniqueMeshAssetName(m_name).c_str(), VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, asBuildSizesInfo);
|
|
|
|
VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{};
|
|
accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
|
|
accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
|
accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
|
accelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
|
|
accelerationBuildGeometryInfo.dstAccelerationStructure = m_blas->getHandle();
|
|
accelerationBuildGeometryInfo.geometryCount = 1;
|
|
accelerationBuildGeometryInfo.pGeometries = &asGeometry;
|
|
accelerationBuildGeometryInfo.scratchData.deviceAddress = m_blas->getScratchBuffer().getDeviceAddress();
|
|
|
|
VkAccelerationStructureBuildRangeInfoKHR asBuildRangeInfo{};
|
|
asBuildRangeInfo.primitiveCount = numTriangles;
|
|
asBuildRangeInfo.primitiveOffset = 0;
|
|
asBuildRangeInfo.firstVertex = 0;
|
|
asBuildRangeInfo.transformOffset = 0;
|
|
std::vector<VkAccelerationStructureBuildRangeInfoKHR*> accelerationBuildStructureRangeInfos = { &asBuildRangeInfo };
|
|
|
|
|
|
// Build the acceleration structure on the device via a one-time command buffer submission
|
|
// Some implementations may support acceleration structure building on the host (VkPhysicalDeviceAccelerationStructureFeaturesKHR->accelerationStructureHostCommands), but we prefer device builds
|
|
RHI::executeImmediatelyMajorGraphics([&](VkCommandBuffer cmd)
|
|
{
|
|
RHI::CmdBuildAccelerationStructures(
|
|
cmd,
|
|
1,
|
|
&accelerationBuildGeometryInfo,
|
|
accelerationBuildStructureRangeInfos.data());
|
|
});
|
|
|
|
m_blas->cleanScratchBuffer();
|
|
}
|
|
|
|
return m_blas.get();
|
|
}
|
|
|
|
void MeshContext::init()
|
|
{
|
|
m_lruCache = std::make_unique<LRUAssetCache<GPUMeshAsset>>(512, 256);
|
|
|
|
m_vertexBindlessBuffer = std::make_unique<BindlessStorageBuffer>();
|
|
m_indexBindlessBuffer = std::make_unique<BindlessStorageBuffer>();
|
|
|
|
m_vertexBindlessBuffer->init();
|
|
m_indexBindlessBuffer->init();
|
|
}
|
|
|
|
void MeshContext::release()
|
|
{
|
|
m_lruCache.reset();
|
|
|
|
m_vertexBindlessBuffer->release();
|
|
m_indexBindlessBuffer->release();
|
|
}
|
|
|
|
void StaticMeshRawDataLoadTask::finishCallback()
|
|
{
|
|
meshAssetGPU->setAsyncLoadState(false);
|
|
}
|
|
|
|
void StaticMeshRawDataLoadTask::uploadFunction(
|
|
uint32_t stageBufferOffset,
|
|
void* mapped,
|
|
RHICommandBufferBase& commandBuffer,
|
|
VulkanBuffer& stageBuffer)
|
|
{
|
|
CHECK(uploadSize() == uint32_t(cacheIndexData.size() + cacheVertexData.size()));
|
|
uint32_t indexOffsetInSrcBuffer = 0;
|
|
uint32_t vertexOffsetInSrcBuffer = indexOffsetInSrcBuffer + uint32_t(cacheIndexData.size());
|
|
|
|
memcpy((void*)((char*)mapped + indexOffsetInSrcBuffer), cacheIndexData.data(), cacheIndexData.size());
|
|
memcpy((void*)((char*)mapped + vertexOffsetInSrcBuffer), cacheVertexData.data(), cacheVertexData.size());
|
|
|
|
meshAssetGPU->prepareToUpload();
|
|
|
|
{
|
|
VkBufferCopy regionIndex{};
|
|
regionIndex.size = VkDeviceSize(cacheIndexData.size());
|
|
regionIndex.srcOffset = indexOffsetInSrcBuffer;
|
|
regionIndex.dstOffset = 0;
|
|
vkCmdCopyBuffer(
|
|
commandBuffer.cmd,
|
|
stageBuffer,
|
|
meshAssetGPU->getIndexBuffer().getVkBuffer(),
|
|
1,
|
|
®ionIndex);
|
|
}
|
|
|
|
{
|
|
VkBufferCopy regionVertex{};
|
|
regionVertex.size = VkDeviceSize(cacheVertexData.size());
|
|
regionVertex.srcOffset = vertexOffsetInSrcBuffer;
|
|
regionVertex.dstOffset = 0;
|
|
vkCmdCopyBuffer(
|
|
commandBuffer.cmd,
|
|
stageBuffer,
|
|
meshAssetGPU->getVertexBuffer().getVkBuffer(),
|
|
1,
|
|
®ionVertex);
|
|
}
|
|
|
|
meshAssetGPU->finishUpload();
|
|
}
|
|
|
|
std::shared_ptr<StaticMeshRawDataLoadTask> StaticMeshRawDataLoadTask::buildFromData(
|
|
const std::string& name,
|
|
const UUID& uuid,
|
|
bool bPersistent,
|
|
uint8_t* indices,
|
|
size_t indexSize,
|
|
VkIndexType indexType,
|
|
uint8_t* vertices,
|
|
size_t vertexSize,
|
|
size_t singleVertexSize)
|
|
{
|
|
if (bPersistent)
|
|
{
|
|
CHECK(!MeshManager::get()->isAssetExist(uuid) && "Persistent asset has exist, don't register repeatly.");
|
|
}
|
|
|
|
auto newTask = std::make_shared<StaticMeshRawDataLoadTask>();
|
|
newTask->cacheVertexData.resize(vertexSize);
|
|
newTask->cacheIndexData.resize(indexSize);
|
|
|
|
memcpy((void*)(newTask->cacheVertexData.data()), (void*)vertices, vertexSize);
|
|
memcpy((void*)(newTask->cacheIndexData.data()), (void*)indices, indexSize);
|
|
|
|
GPUMeshAsset* fallback = nullptr;
|
|
if (!bPersistent)
|
|
{
|
|
fallback = MeshManager::get()->getMesh(EngineMeshes::GBoxUUID).get();
|
|
CHECK(fallback && "Non persistent asset must exist one fallback mesh.");
|
|
}
|
|
|
|
auto newAsset = std::shared_ptr<GPUMeshAsset>(new GPUMeshAsset(
|
|
bPersistent,
|
|
fallback,
|
|
name,
|
|
vertexSize,
|
|
singleVertexSize,
|
|
indexSize,
|
|
indexType));
|
|
MeshManager::get()->insertGPUAsset(uuid, newAsset);
|
|
|
|
newTask->meshAssetGPU = newAsset;
|
|
|
|
return newTask;
|
|
}
|
|
|
|
|
|
void StaticMeshLoadTask::finishCallback()
|
|
{
|
|
meshAssetGPU->setAsyncLoadState(false);
|
|
}
|
|
|
|
void StaticMeshLoadTask::uploadFunction(
|
|
uint32_t stageBufferOffset,
|
|
void* mapped,
|
|
RHICommandBufferBase& commandBuffer,
|
|
VulkanBuffer& stageBuffer)
|
|
{
|
|
// Load bin data.
|
|
auto meshBin = std::dynamic_pointer_cast<StaticMeshAssetBin>(cacheHeader->loadBinData());
|
|
CHECK(meshBin != nullptr);
|
|
|
|
const auto verticesSize = meshBin->getVertices().size() * sizeof(meshBin->getVertices()[0]);
|
|
const auto indicesSize = meshBin->getIndices().size() * sizeof(meshBin->getIndices()[0]);
|
|
|
|
CHECK(uploadSize() == uint32_t(indicesSize + verticesSize));
|
|
uint32_t indexOffsetInSrcBuffer = 0;
|
|
uint32_t vertexOffsetInSrcBuffer = indexOffsetInSrcBuffer + uint32_t(indicesSize);
|
|
|
|
memcpy((void*)((char*)stageBuffer.mapped + indexOffsetInSrcBuffer), meshBin->getIndices().data(), indicesSize);
|
|
memcpy((void*)((char*)stageBuffer.mapped + vertexOffsetInSrcBuffer), meshBin->getVertices().data(), verticesSize);
|
|
|
|
meshAssetGPU->prepareToUpload();
|
|
|
|
{
|
|
VkBufferCopy regionIndex{};
|
|
regionIndex.size = VkDeviceSize(indicesSize);
|
|
regionIndex.srcOffset = indexOffsetInSrcBuffer;
|
|
regionIndex.dstOffset = 0;
|
|
vkCmdCopyBuffer(
|
|
commandBuffer.cmd,
|
|
stageBuffer,
|
|
meshAssetGPU->getIndexBuffer().getVkBuffer(),
|
|
1,
|
|
®ionIndex);
|
|
}
|
|
|
|
{
|
|
VkBufferCopy regionVertex{};
|
|
regionVertex.size = VkDeviceSize(verticesSize);
|
|
regionVertex.srcOffset = vertexOffsetInSrcBuffer;
|
|
regionVertex.dstOffset = 0;
|
|
vkCmdCopyBuffer(
|
|
commandBuffer.cmd,
|
|
stageBuffer,
|
|
meshAssetGPU->getVertexBuffer().getVkBuffer(),
|
|
1,
|
|
®ionVertex);
|
|
}
|
|
|
|
meshAssetGPU->finishUpload();
|
|
}
|
|
|
|
std::shared_ptr<StaticMeshLoadTask> StaticMeshLoadTask::build(
|
|
std::shared_ptr<RegistryEntry> registry,
|
|
bool bPersistent)
|
|
{
|
|
CHECK(registry->isLeaf() && registry->isValid());
|
|
|
|
auto meshHeader = std::dynamic_pointer_cast<StaticMeshAssetHeader>(registry->getHeader());
|
|
CHECK(meshHeader != nullptr);
|
|
GPUMeshAsset* fallback = nullptr;
|
|
if (bPersistent)
|
|
{
|
|
CHECK(!MeshManager::get()->isAssetExist(meshHeader->getHeaderUUID()) && "Persistent asset has exist, don't register repeatly.");
|
|
}
|
|
else
|
|
{
|
|
fallback = MeshManager::get()->getMesh(EngineMeshes::GBoxUUID).get();
|
|
CHECK(fallback && "Non persistent asset must exist one fallback mesh.");
|
|
}
|
|
|
|
auto newTask = std::make_shared<StaticMeshLoadTask>();
|
|
|
|
const auto verticesSize = meshHeader->getVerticesCount() * sizeof(StaticMeshVertex);
|
|
const auto indicesSize = meshHeader->getIndicesCount() * sizeof(uint32_t);
|
|
|
|
auto newAsset = std::shared_ptr<GPUMeshAsset>(new GPUMeshAsset(
|
|
bPersistent,
|
|
fallback,
|
|
registry->getName(),
|
|
verticesSize,
|
|
sizeof(StaticMeshVertex),
|
|
indicesSize,
|
|
VK_INDEX_TYPE_UINT32));
|
|
|
|
MeshManager::get()->insertGPUAsset(meshHeader->getHeaderUUID(), newAsset);
|
|
newTask->meshAssetGPU = newAsset;
|
|
newTask->cacheHeader = meshHeader;
|
|
|
|
return newTask;
|
|
}
|
|
|
|
std::shared_ptr<GPUMeshAsset> MeshContext::getOrCreateLRUMesh(const AssetHeaderUUID& id)
|
|
{
|
|
// No exist in lru cache, need load from disk.
|
|
if (!m_lruCache->contain(id))
|
|
{
|
|
const auto& entryHeaderMap = AssetRegistryManager::get()->getEntryHeaderMap();
|
|
const auto& entryMap = AssetRegistryManager::get()->getEntryMap();
|
|
auto newTask = StaticMeshLoadTask::build(entryMap.at(entryHeaderMap.at(id)).lock(), false);
|
|
GEngine->getRuntimeModule<AssetSystem>()->addUploadTask(newTask);
|
|
}
|
|
|
|
return getMesh(id);
|
|
}
|
|
|
|
std::shared_ptr<GPUMeshAsset> MeshContext::getOrCreateLRUMesh(std::shared_ptr<StaticMeshAssetHeader> header)
|
|
{
|
|
return getOrCreateLRUMesh(header->getHeaderUUID());
|
|
}
|
|
|
|
void MeshContext::shrinkLRU()
|
|
{
|
|
// Find unused asset and push to lazy destory component.
|
|
size_t sizeReduce = m_lruCache->prune([&](std::shared_ptr<GPUMeshAsset> removedAsset)
|
|
{
|
|
GEngine->getRuntimeModule<AssetSystem>()->addUnusedAsset(removedAsset);
|
|
});
|
|
|
|
LOG_INFO("Mesh manager reduce {0} mesh size.", sizeReduce);
|
|
}
|
|
} |