Add VolumeField NanoVDB asset pipeline

This commit is contained in:
2026-04-08 19:45:53 +08:00
parent 6bf9203eec
commit c6815fa809
16 changed files with 608 additions and 1 deletions

View File

@@ -7,6 +7,8 @@
#include <XCEngine/Resources/Shader/ShaderLoader.h>
#include <XCEngine/Resources/Texture/TextureLoader.h>
#include <XCEngine/Resources/UI/UIDocumentCompiler.h>
#include <XCEngine/Resources/Volume/VolumeField.h>
#include <XCEngine/Resources/Volume/VolumeFieldLoader.h>
#include <algorithm>
#include <cctype>
@@ -366,6 +368,27 @@ bool WriteTextureArtifactFile(const fs::path& artifactPath, const Texture& textu
return static_cast<bool>(output);
}
bool WriteVolumeFieldArtifactFile(const fs::path& artifactPath, const VolumeField& volumeField) {
std::ofstream output(artifactPath, std::ios::binary | std::ios::trunc);
if (!output.is_open()) {
return false;
}
VolumeFieldArtifactHeader header;
header.storageKind = static_cast<Core::uint32>(volumeField.GetStorageKind());
header.boundsMin = volumeField.GetBounds().GetMin();
header.boundsMax = volumeField.GetBounds().GetMax();
header.voxelSize = volumeField.GetVoxelSize();
header.payloadSize = static_cast<Core::uint64>(volumeField.GetPayloadSize());
output.write(reinterpret_cast<const char*>(&header), sizeof(header));
if (volumeField.GetPayloadSize() > 0) {
output.write(static_cast<const char*>(volumeField.GetPayloadData()), volumeField.GetPayloadSize());
}
return static_cast<bool>(output);
}
std::vector<MaterialProperty> GatherMaterialProperties(const Material& material) {
return material.GetProperties();
}
@@ -1258,6 +1281,7 @@ bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath,
const fs::path metaPath(sourcePath.string() + ".meta");
outRecord.metaPath = NormalizeRelativePath(metaPath);
const Containers::String expectedImporterName = GetImporterNameForPath(relativePath, isFolder);
bool shouldRewriteMeta = false;
if (!fs::exists(metaPath) || !ReadMetaFile(metaPath, outRecord) || !outRecord.guid.IsValid()) {
@@ -1266,6 +1290,10 @@ bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath,
}
shouldRewriteMeta = true;
}
if (outRecord.importerName != expectedImporterName) {
outRecord.importerName = expectedImporterName;
shouldRewriteMeta = true;
}
if (outRecord.importerVersion != kCurrentImporterVersion) {
outRecord.importerVersion = kCurrentImporterVersion;
shouldRewriteMeta = true;
@@ -1409,6 +1437,9 @@ Containers::String AssetDatabase::GetImporterNameForPath(const Containers::Strin
if (ext == ".shader") {
return Containers::String("ShaderImporter");
}
if (ext == ".nvdb") {
return Containers::String("VolumeFieldImporter");
}
if (ext == ".mat" || ext == ".material" || ext == ".json") {
return Containers::String("MaterialImporter");
}
@@ -1437,6 +1468,9 @@ ResourceType AssetDatabase::GetPrimaryResourceTypeForImporter(const Containers::
if (importerName == "ShaderImporter") {
return ResourceType::Shader;
}
if (importerName == "VolumeFieldImporter") {
return ResourceType::VolumeField;
}
return ResourceType::Unknown;
}
@@ -1487,6 +1521,8 @@ bool AssetDatabase::ImportAsset(const SourceAssetRecord& sourceRecord,
return ImportModelAsset(sourceRecord, outRecord);
case ResourceType::Shader:
return ImportShaderAsset(sourceRecord, outRecord);
case ResourceType::VolumeField:
return ImportVolumeFieldAsset(sourceRecord, outRecord);
default:
SetLastErrorMessage(Containers::String("No importer available for asset: ") + sourceRecord.relativePath);
return false;
@@ -1875,6 +1911,54 @@ bool AssetDatabase::ImportShaderAsset(const SourceAssetRecord& sourceRecord,
return true;
}
bool AssetDatabase::ImportVolumeFieldAsset(const SourceAssetRecord& sourceRecord,
ArtifactRecord& outRecord) {
VolumeFieldLoader loader;
const Containers::String absolutePath =
NormalizePathString(fs::path(m_projectRoot.CStr()) / sourceRecord.relativePath.CStr());
LoadResult result = loader.Load(absolutePath);
if (!result || result.resource == nullptr) {
return false;
}
VolumeField* volumeField = static_cast<VolumeField*>(result.resource);
const Containers::String artifactKey = BuildArtifactKey(sourceRecord);
const Containers::String artifactDir = BuildArtifactDirectory(artifactKey);
const Containers::String mainArtifactPath =
NormalizePathString(fs::path(artifactDir.CStr()) / "main.xcvol");
std::error_code ec;
fs::remove_all(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
ec.clear();
fs::create_directories(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
if (ec) {
delete volumeField;
return false;
}
const bool writeOk =
WriteVolumeFieldArtifactFile(fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr(), *volumeField);
delete volumeField;
if (!writeOk) {
return false;
}
outRecord.artifactKey = artifactKey;
outRecord.assetGuid = sourceRecord.guid;
outRecord.importerName = sourceRecord.importerName;
outRecord.importerVersion = sourceRecord.importerVersion;
outRecord.resourceType = ResourceType::VolumeField;
outRecord.artifactDirectory = artifactDir;
outRecord.mainArtifactPath = mainArtifactPath;
outRecord.sourceHash = sourceRecord.sourceHash;
outRecord.metaHash = sourceRecord.metaHash;
outRecord.sourceFileSize = sourceRecord.sourceFileSize;
outRecord.sourceWriteTime = sourceRecord.sourceWriteTime;
outRecord.mainLocalID = kMainAssetLocalID;
outRecord.dependencies.clear();
return true;
}
bool AssetDatabase::ImportUIDocumentAsset(const SourceAssetRecord& sourceRecord,
UIDocumentKind kind,
const char* artifactFileName,

View File

@@ -7,6 +7,7 @@
#include <XCEngine/Resources/Shader/ShaderLoader.h>
#include <XCEngine/Resources/Texture/TextureLoader.h>
#include <XCEngine/Resources/UI/UIDocumentLoaders.h>
#include <XCEngine/Resources/Volume/VolumeFieldLoader.h>
#include <exception>
namespace XCEngine {
@@ -49,6 +50,7 @@ TextureLoader g_textureLoader;
UIViewLoader g_uiViewLoader;
UIThemeLoader g_uiThemeLoader;
UISchemaLoader g_uiSchemaLoader;
VolumeFieldLoader g_volumeFieldLoader;
} // namespace
@@ -92,6 +94,7 @@ void ResourceManager::EnsureInitialized() {
RegisterBuiltinLoader(*this, g_uiViewLoader);
RegisterBuiltinLoader(*this, g_uiThemeLoader);
RegisterBuiltinLoader(*this, g_uiSchemaLoader);
RegisterBuiltinLoader(*this, g_volumeFieldLoader);
m_assetImportService.Initialize();
m_asyncLoader = std::move(asyncLoader);