导入更新
This commit is contained in:
parent
a31f700d75
commit
a8739a9423
@ -11,16 +11,16 @@
|
||||
"BaseColorTexture": "",
|
||||
"DoubleSided": false,
|
||||
"EmissiveColor": [
|
||||
0.29019609093666077,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"EmissiveTexture": "",
|
||||
"Metallic": 0.0,
|
||||
"Metallic": 1.0,
|
||||
"MetallicRoughnessTexture": "",
|
||||
"Name": "Material 1",
|
||||
"NormalTexture": "",
|
||||
"Roughness": 0.5690000057220459,
|
||||
"Roughness": 0.0,
|
||||
"ShaderModel": 0,
|
||||
"StableImportKey": ""
|
||||
}
|
||||
@ -3,6 +3,6 @@
|
||||
"guid": "fc3fd465-4f39-44af-907a-4fc0494c2502",
|
||||
"importer_id": "MaterialImporter",
|
||||
"package_path": "Assets/Materials/Material 1.mcmaterial.json",
|
||||
"source_hash": 491201104691168908,
|
||||
"source_hash": 12648564269874715657,
|
||||
"source_path": "Assets/Materials/Material 1.mcmaterial.json"
|
||||
}
|
||||
BIN
SandboxProject/Assets/Models/111.glb.mcasset
Normal file
BIN
SandboxProject/Assets/Models/111.glb.mcasset
Normal file
Binary file not shown.
@ -44,7 +44,7 @@
|
||||
"c1bdb8de-36f0-fa5d-4ed3-aa7311a5c60a",
|
||||
"474bab4f-e853-88a4-3738-590a98c9b0a8"
|
||||
],
|
||||
"guid": "b72a0c12-d6fd-4999-86c5-958e3bac1c78",
|
||||
"guid": "e9fd854e-2d0a-43b6-a73e-2caa1fe61f4e",
|
||||
"importer_id": "GltfModelImporter",
|
||||
"package_path": "Assets/Models/超精密磨床.glb.mcasset",
|
||||
"source_hash": 4002013065180687563,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -971,48 +971,84 @@ template <typename TGeneratedAsset, typename TLabelBuilder>
|
||||
);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<MetaCoreModelAssetDocument> MetaCoreLoadModelAssetDocumentForRecord(
|
||||
const MetaCoreIAssetDatabaseService& assetDatabaseService,
|
||||
const MetaCoreIPackageService& packageService,
|
||||
const MetaCoreIReflectionRegistry& reflectionRegistry,
|
||||
const MetaCoreAssetRecord& assetRecord,
|
||||
std::unordered_map<MetaCoreAssetGuid, MetaCoreModelAssetDocument, MetaCoreAssetGuidHasher>* modelCache = nullptr
|
||||
);
|
||||
|
||||
[[nodiscard]] std::optional<MetaCoreResolvedGeneratedAssetDocument> MetaCoreResolveGeneratedAssetDocument(
|
||||
const MetaCoreIAssetDatabaseService& assetDatabaseService,
|
||||
const MetaCoreIPackageService& packageService,
|
||||
const MetaCoreIReflectionRegistry& reflectionRegistry,
|
||||
const MetaCoreAssetGuid& generatedAssetGuid
|
||||
const MetaCoreAssetGuid& generatedAssetGuid,
|
||||
std::unordered_map<MetaCoreAssetGuid, MetaCoreModelAssetDocument, MetaCoreAssetGuidHasher>* modelCache = nullptr
|
||||
) {
|
||||
if (!assetDatabaseService.HasProject() || !generatedAssetGuid.IsValid()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto findGeneratedAsset = [&](
|
||||
const MetaCoreAssetRecord& record,
|
||||
const MetaCoreModelAssetDocument& modelDocument
|
||||
) -> std::optional<MetaCoreResolvedGeneratedAssetDocument> {
|
||||
for (std::size_t index = 0; index < modelDocument.GeneratedMeshAssets.size(); ++index) {
|
||||
if (modelDocument.GeneratedMeshAssets[index].AssetGuid == generatedAssetGuid) {
|
||||
return MetaCoreResolvedGeneratedAssetDocument{record, modelDocument, "mesh", index};
|
||||
}
|
||||
}
|
||||
for (std::size_t index = 0; index < modelDocument.GeneratedMaterialAssets.size(); ++index) {
|
||||
if (modelDocument.GeneratedMaterialAssets[index].AssetGuid == generatedAssetGuid) {
|
||||
return MetaCoreResolvedGeneratedAssetDocument{record, modelDocument, "material", index};
|
||||
}
|
||||
}
|
||||
for (std::size_t index = 0; index < modelDocument.GeneratedTextureAssets.size(); ++index) {
|
||||
if (modelDocument.GeneratedTextureAssets[index].AssetGuid == generatedAssetGuid) {
|
||||
return MetaCoreResolvedGeneratedAssetDocument{record, modelDocument, "texture", index};
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
};
|
||||
|
||||
const std::filesystem::path sourcePath = MetaCoreAssetRegistry::Get().ResolveGuidToPath(generatedAssetGuid);
|
||||
if (!sourcePath.empty()) {
|
||||
const auto sourceRecord = assetDatabaseService.FindAssetByRelativePath(sourcePath);
|
||||
if (sourceRecord.has_value() && sourceRecord->Type == "model") {
|
||||
const auto modelDocument = MetaCoreLoadModelAssetDocumentForRecord(
|
||||
assetDatabaseService,
|
||||
packageService,
|
||||
reflectionRegistry,
|
||||
*sourceRecord,
|
||||
modelCache
|
||||
);
|
||||
if (modelDocument.has_value()) {
|
||||
if (auto resolved = findGeneratedAsset(*sourceRecord, *modelDocument)) {
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const MetaCoreAssetRecord& record : assetDatabaseService.GetAssetRegistry()) {
|
||||
if (record.Type != "model") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::filesystem::path relativePackagePath =
|
||||
!record.PackagePath.empty() ? record.PackagePath : record.RelativePath;
|
||||
const auto package =
|
||||
packageService.ReadPackage(assetDatabaseService.GetProjectDescriptor().RootPath / relativePackagePath);
|
||||
if (!package.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto modelDocument = MetaCoreReadModelAssetDocument(*package, reflectionRegistry.GetTypeRegistry());
|
||||
const auto modelDocument = MetaCoreLoadModelAssetDocumentForRecord(
|
||||
assetDatabaseService,
|
||||
packageService,
|
||||
reflectionRegistry,
|
||||
record,
|
||||
modelCache
|
||||
);
|
||||
if (!modelDocument.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < modelDocument->GeneratedMeshAssets.size(); ++index) {
|
||||
if (modelDocument->GeneratedMeshAssets[index].AssetGuid == generatedAssetGuid) {
|
||||
return MetaCoreResolvedGeneratedAssetDocument{record, *modelDocument, "mesh", index};
|
||||
}
|
||||
}
|
||||
for (std::size_t index = 0; index < modelDocument->GeneratedMaterialAssets.size(); ++index) {
|
||||
if (modelDocument->GeneratedMaterialAssets[index].AssetGuid == generatedAssetGuid) {
|
||||
return MetaCoreResolvedGeneratedAssetDocument{record, *modelDocument, "material", index};
|
||||
}
|
||||
}
|
||||
for (std::size_t index = 0; index < modelDocument->GeneratedTextureAssets.size(); ++index) {
|
||||
if (modelDocument->GeneratedTextureAssets[index].AssetGuid == generatedAssetGuid) {
|
||||
return MetaCoreResolvedGeneratedAssetDocument{record, *modelDocument, "texture", index};
|
||||
}
|
||||
if (auto resolved = findGeneratedAsset(record, *modelDocument)) {
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4498,7 +4534,7 @@ void MetaCorePublishAssetRecordChanges(
|
||||
materialAsset.Name = absoluteSourcePath.stem().string() + "_Material";
|
||||
materialAsset.StableImportKey = MetaCoreBuildStableImportKey("material", materialAsset.Name, 0);
|
||||
materialAsset.Metallic = 0.0F;
|
||||
materialAsset.Roughness = 0.0F;
|
||||
materialAsset.Roughness = 1.0F;
|
||||
document.GeneratedMaterialAssets.push_back(std::move(materialAsset));
|
||||
|
||||
document.ImportReport.UsedFallback = true;
|
||||
@ -4514,6 +4550,102 @@ void MetaCorePublishAssetRecordChanges(
|
||||
return document;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<MetaCoreModelAssetDocument> MetaCoreLoadModelAssetDocumentForRecord(
|
||||
const MetaCoreIAssetDatabaseService& assetDatabaseService,
|
||||
const MetaCoreIPackageService& packageService,
|
||||
const MetaCoreIReflectionRegistry& reflectionRegistry,
|
||||
const MetaCoreAssetRecord& assetRecord,
|
||||
std::unordered_map<MetaCoreAssetGuid, MetaCoreModelAssetDocument, MetaCoreAssetGuidHasher>* modelCache
|
||||
) {
|
||||
if (!assetDatabaseService.HasProject() || assetRecord.Type != "model") {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (modelCache != nullptr && assetRecord.Guid.IsValid()) {
|
||||
const auto cacheIterator = modelCache->find(assetRecord.Guid);
|
||||
if (cacheIterator != modelCache->end() &&
|
||||
(assetRecord.SourceHash == 0 || cacheIterator->second.SourceHash == assetRecord.SourceHash)) {
|
||||
return cacheIterator->second;
|
||||
}
|
||||
}
|
||||
|
||||
const auto cacheDocument = [&](const MetaCoreModelAssetDocument& document) {
|
||||
if (modelCache != nullptr && assetRecord.Guid.IsValid()) {
|
||||
(*modelCache)[assetRecord.Guid] = document;
|
||||
}
|
||||
return document;
|
||||
};
|
||||
|
||||
const std::filesystem::path projectRoot = assetDatabaseService.GetProjectDescriptor().RootPath;
|
||||
const std::filesystem::path relativePackagePath =
|
||||
!assetRecord.PackagePath.empty()
|
||||
? assetRecord.PackagePath
|
||||
: MetaCoreBuildPackagePathFromSource(!assetRecord.SourcePath.empty() ? assetRecord.SourcePath : assetRecord.RelativePath);
|
||||
if (!relativePackagePath.empty()) {
|
||||
const auto package = packageService.ReadPackage(projectRoot / relativePackagePath);
|
||||
if (package.has_value()) {
|
||||
if (auto document = MetaCoreReadModelAssetDocument(*package, reflectionRegistry.GetTypeRegistry())) {
|
||||
return cacheDocument(*document);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path relativeSourcePath =
|
||||
!assetRecord.SourcePath.empty() ? assetRecord.SourcePath : assetRecord.RelativePath;
|
||||
if (relativeSourcePath.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const std::filesystem::path absoluteSourcePath = projectRoot / relativeSourcePath;
|
||||
if (!std::filesystem::exists(absoluteSourcePath) || std::filesystem::is_directory(absoluteSourcePath)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
relativeSourcePath = absoluteSourcePath.lexically_relative(projectRoot);
|
||||
const std::string importerId =
|
||||
!assetRecord.ImporterId.empty() ? assetRecord.ImporterId : MetaCoreDetectImporterId(absoluteSourcePath);
|
||||
if (importerId != "GltfModelImporter" && importerId != "ModelImporter") {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const std::uint64_t sourceHash = MetaCoreHashFile(absoluteSourcePath).value_or(assetRecord.SourceHash);
|
||||
MetaCoreModelImportSettingsDocument importSettings = MetaCoreBuildDefaultModelImportSettings();
|
||||
|
||||
MetaCoreAssetMetadataDocument metadata;
|
||||
std::vector<MetaCoreSubAssetMetadata> previousSubAssets;
|
||||
if (MetaCoreReadMetaJson(MetaCoreBuildMetaPath(absoluteSourcePath), metadata)) {
|
||||
previousSubAssets = metadata.SubAssets;
|
||||
if (!metadata.SourcePath.empty()) {
|
||||
relativeSourcePath = metadata.SourcePath;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<MetaCoreModelAssetDocument> document;
|
||||
if (importerId == "GltfModelImporter") {
|
||||
std::vector<std::vector<std::byte>> meshPayloads;
|
||||
document = MetaCoreBuildImportedGltfAssetDocument(
|
||||
absoluteSourcePath,
|
||||
relativeSourcePath,
|
||||
sourceHash,
|
||||
meshPayloads,
|
||||
importSettings
|
||||
);
|
||||
} else {
|
||||
document = MetaCoreBuildImportedGenericModelAssetDocument(
|
||||
absoluteSourcePath,
|
||||
relativeSourcePath,
|
||||
sourceHash,
|
||||
importSettings
|
||||
);
|
||||
}
|
||||
|
||||
if (document.has_value()) {
|
||||
MetaCoreApplyStableSubAssetGuids(previousSubAssets, *document);
|
||||
return cacheDocument(*document);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
[[nodiscard]] MetaCorePackageDocument MetaCoreBuildTypedPackage(
|
||||
MetaCorePackageType packageType,
|
||||
const MetaCoreAssetGuid& assetGuid,
|
||||
@ -5576,6 +5708,7 @@ public:
|
||||
AssetDatabaseService_.reset();
|
||||
PackageService_.reset();
|
||||
ReflectionRegistry_.reset();
|
||||
ModelCache_.clear();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<MetaCoreModelAssetDocument> LoadModelAsset(
|
||||
@ -5771,15 +5904,13 @@ std::optional<MetaCoreModelAssetDocument> MetaCoreBuiltinAssetEditingService::Lo
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const std::filesystem::path relativePackagePath =
|
||||
!assetRecord->PackagePath.empty() ? assetRecord->PackagePath : assetRecord->RelativePath;
|
||||
const auto package =
|
||||
PackageService_->ReadPackage(AssetDatabaseService_->GetProjectDescriptor().RootPath / relativePackagePath);
|
||||
if (!package.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto doc = MetaCoreReadModelAssetDocument(*package, ReflectionRegistry_->GetTypeRegistry());
|
||||
auto doc = MetaCoreLoadModelAssetDocumentForRecord(
|
||||
*AssetDatabaseService_,
|
||||
*PackageService_,
|
||||
*ReflectionRegistry_,
|
||||
*assetRecord,
|
||||
&ModelCache_
|
||||
);
|
||||
if (doc.has_value()) {
|
||||
ModelCache_[assetGuid] = *doc;
|
||||
}
|
||||
@ -5797,7 +5928,8 @@ std::optional<MetaCoreMeshAssetDocument> MetaCoreBuiltinAssetEditingService::Loa
|
||||
*AssetDatabaseService_,
|
||||
*PackageService_,
|
||||
*ReflectionRegistry_,
|
||||
meshGuid
|
||||
meshGuid,
|
||||
&ModelCache_
|
||||
);
|
||||
if (!resolved.has_value() || resolved->GeneratedKind != "mesh") {
|
||||
return std::nullopt;
|
||||
@ -5829,7 +5961,8 @@ std::optional<MetaCoreMaterialAssetDocument> MetaCoreBuiltinAssetEditingService:
|
||||
*AssetDatabaseService_,
|
||||
*PackageService_,
|
||||
*ReflectionRegistry_,
|
||||
materialGuid
|
||||
materialGuid,
|
||||
&ModelCache_
|
||||
);
|
||||
if (resolved.has_value() && resolved->GeneratedKind == "material") {
|
||||
if (resolved->GeneratedIndex < resolved->Document.GeneratedMaterialAssets.size()) {
|
||||
@ -5881,7 +6014,8 @@ std::optional<MetaCoreTextureAssetDocument> MetaCoreBuiltinAssetEditingService::
|
||||
*AssetDatabaseService_,
|
||||
*PackageService_,
|
||||
*ReflectionRegistry_,
|
||||
textureGuid
|
||||
textureGuid,
|
||||
&ModelCache_
|
||||
);
|
||||
if (!resolved.has_value() || resolved->GeneratedKind != "texture") {
|
||||
return std::nullopt;
|
||||
@ -5952,7 +6086,8 @@ bool MetaCoreBuiltinAssetEditingService::SaveMaterialAsset(
|
||||
*AssetDatabaseService_,
|
||||
*PackageService_,
|
||||
*ReflectionRegistry_,
|
||||
materialGuid
|
||||
materialGuid,
|
||||
&ModelCache_
|
||||
);
|
||||
if (resolved.has_value() && resolved->GeneratedKind == "material") {
|
||||
if (resolved->GeneratedIndex < resolved->Document.GeneratedMaterialAssets.size()) {
|
||||
@ -5988,7 +6123,8 @@ std::optional<MetaCoreResolvedGeneratedAssetRecord> MetaCoreBuiltinAssetEditingS
|
||||
*AssetDatabaseService_,
|
||||
*PackageService_,
|
||||
*ReflectionRegistry_,
|
||||
assetGuid
|
||||
assetGuid,
|
||||
&ModelCache_
|
||||
);
|
||||
if (!resolved.has_value()) {
|
||||
return std::nullopt;
|
||||
@ -6604,6 +6740,7 @@ public:
|
||||
AssetDatabaseService_.reset();
|
||||
PackageService_.reset();
|
||||
ReflectionRegistry_.reset();
|
||||
ModelCache_.clear();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<MetaCoreId> CreateGameObject(
|
||||
@ -6632,6 +6769,7 @@ private:
|
||||
std::shared_ptr<MetaCoreIAssetDatabaseService> AssetDatabaseService_{};
|
||||
std::shared_ptr<MetaCoreIPackageService> PackageService_{};
|
||||
std::shared_ptr<MetaCoreIReflectionRegistry> ReflectionRegistry_{};
|
||||
std::unordered_map<MetaCoreAssetGuid, MetaCoreModelAssetDocument, MetaCoreAssetGuidHasher> ModelCache_{};
|
||||
};
|
||||
|
||||
class MetaCoreBuiltinPrefabService final : public MetaCoreIPrefabService {
|
||||
@ -8381,42 +8519,13 @@ std::optional<MetaCoreId> MetaCoreBuiltinSceneEditingService::InstantiateModelAs
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const std::filesystem::path relativePackagePath =
|
||||
!assetRecord->PackagePath.empty() ? assetRecord->PackagePath : assetRecord->RelativePath;
|
||||
const auto package = PackageService_->ReadPackage(AssetDatabaseService_->GetProjectDescriptor().RootPath / relativePackagePath);
|
||||
|
||||
std::optional<MetaCoreModelAssetDocument> importedDocument;
|
||||
|
||||
if (package.has_value()) {
|
||||
importedDocument = MetaCoreReadModelAssetDocument(*package, ReflectionRegistry_->GetTypeRegistry());
|
||||
}
|
||||
|
||||
if (!importedDocument.has_value() || importedDocument->Nodes.empty()) {
|
||||
// 【敏捷开发决策】:如果磁盘上不存在物理的 .mcasset 包文件,直接动态解析原始 model 原始文件,构建文档结构以供实例化
|
||||
const std::filesystem::path absoluteSourcePath =
|
||||
AssetDatabaseService_->GetProjectDescriptor().RootPath / assetRecord->RelativePath;
|
||||
if (std::filesystem::exists(absoluteSourcePath)) {
|
||||
const std::string extension = absoluteSourcePath.extension().generic_string();
|
||||
MetaCoreModelImportSettingsDocument defaultSettings{};
|
||||
if (extension == ".glb" || extension == ".gltf") {
|
||||
std::vector<std::vector<std::byte>> meshPayloads;
|
||||
importedDocument = MetaCoreBuildImportedGltfAssetDocument(
|
||||
absoluteSourcePath,
|
||||
assetRecord->RelativePath,
|
||||
assetRecord->SourceHash,
|
||||
meshPayloads,
|
||||
defaultSettings
|
||||
);
|
||||
} else if (extension == ".obj" || extension == ".fbx") {
|
||||
importedDocument = MetaCoreBuildImportedGenericModelAssetDocument(
|
||||
absoluteSourcePath,
|
||||
assetRecord->RelativePath,
|
||||
assetRecord->SourceHash,
|
||||
defaultSettings
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::optional<MetaCoreModelAssetDocument> importedDocument = MetaCoreLoadModelAssetDocumentForRecord(
|
||||
*AssetDatabaseService_,
|
||||
*PackageService_,
|
||||
*ReflectionRegistry_,
|
||||
*assetRecord,
|
||||
&ModelCache_
|
||||
);
|
||||
|
||||
if (!importedDocument.has_value() || importedDocument->Nodes.empty()) {
|
||||
return std::nullopt;
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
@ -18,6 +20,11 @@
|
||||
namespace MetaCore {
|
||||
|
||||
void MetaCoreGltfTrace(const char* message) {
|
||||
const char* traceEnv = std::getenv("METACORE_GLTF_IMPORT_TRACE");
|
||||
if (traceEnv == nullptr || traceEnv[0] == '\0' || std::strcmp(traceEnv, "0") == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
FILE* file = nullptr;
|
||||
#if defined(_MSC_VER)
|
||||
if (fopen_s(&file, "editor.crash.log", "a") == 0 && file != nullptr) {
|
||||
@ -439,7 +446,7 @@ struct MetaCoreGltfMaterialScalarPresence {
|
||||
genMat.Name = "PumpMaterial";
|
||||
genMat.StableImportKey = MetaCoreBuildStableImportKey("material", "PumpMaterial", 0);
|
||||
genMat.Metallic = 0.0F;
|
||||
genMat.Roughness = 0.0F;
|
||||
genMat.Roughness = 1.0F;
|
||||
genMat.BaseColorTexture = genTex.AssetGuid;
|
||||
genMat.BaseColor = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
document.GeneratedMaterialAssets.push_back(genMat);
|
||||
@ -517,7 +524,7 @@ struct MetaCoreGltfMaterialScalarPresence {
|
||||
genMat.Name = "ValveMaterial";
|
||||
genMat.StableImportKey = MetaCoreBuildStableImportKey("material", "ValveMaterial", 0);
|
||||
genMat.Metallic = 0.0F;
|
||||
genMat.Roughness = 0.0F;
|
||||
genMat.Roughness = 1.0F;
|
||||
genMat.BaseColorTexture = genTex.AssetGuid;
|
||||
document.GeneratedMaterialAssets.push_back(genMat);
|
||||
|
||||
@ -594,7 +601,7 @@ struct MetaCoreGltfMaterialScalarPresence {
|
||||
genMat.Name = "EmbeddedTextureMaterial";
|
||||
genMat.StableImportKey = MetaCoreBuildStableImportKey("material", "EmbeddedTextureMaterial", 0);
|
||||
genMat.Metallic = 0.0F;
|
||||
genMat.Roughness = 0.0F;
|
||||
genMat.Roughness = 1.0F;
|
||||
genMat.BaseColorTexture = genTex.AssetGuid;
|
||||
document.GeneratedMaterialAssets.push_back(genMat);
|
||||
|
||||
@ -679,7 +686,7 @@ struct MetaCoreGltfMaterialScalarPresence {
|
||||
genMat.Name = "Tank_Material";
|
||||
genMat.StableImportKey = MetaCoreBuildStableImportKey("material", "Tank_Material", 0);
|
||||
genMat.Metallic = 0.0F;
|
||||
genMat.Roughness = 0.0F;
|
||||
genMat.Roughness = 1.0F;
|
||||
document.GeneratedMaterialAssets.push_back(genMat);
|
||||
|
||||
// 3. Node
|
||||
@ -751,7 +758,7 @@ struct MetaCoreGltfMaterialScalarPresence {
|
||||
materialAsset.Name = absoluteSourcePath.stem().string() + "_Material";
|
||||
materialAsset.StableImportKey = MetaCoreBuildStableImportKey("material", materialAsset.Name, 0);
|
||||
materialAsset.Metallic = 0.0F;
|
||||
materialAsset.Roughness = 0.0F;
|
||||
materialAsset.Roughness = 1.0F;
|
||||
document.GeneratedMaterialAssets.push_back(std::move(materialAsset));
|
||||
};
|
||||
|
||||
@ -818,7 +825,7 @@ struct MetaCoreGltfMaterialScalarPresence {
|
||||
genMat.AlphaCutoff = mat.alpha_cutoff;
|
||||
genMat.AlphaMode = mat.alpha_mode == cgltf_alpha_mode_blend ? MetaCoreMaterialAlphaMode::Blend : (mat.alpha_mode == cgltf_alpha_mode_mask ? MetaCoreMaterialAlphaMode::Mask : MetaCoreMaterialAlphaMode::Opaque);
|
||||
genMat.Metallic = 0.0F;
|
||||
genMat.Roughness = 0.0F;
|
||||
genMat.Roughness = 1.0F;
|
||||
|
||||
if (mat.has_pbr_metallic_roughness) {
|
||||
genMat.BaseColor = glm::vec3(mat.pbr_metallic_roughness.base_color_factor[0], mat.pbr_metallic_roughness.base_color_factor[1], mat.pbr_metallic_roughness.base_color_factor[2]);
|
||||
|
||||
@ -25,11 +25,16 @@
|
||||
#include <filament/Material.h>
|
||||
#include <filament/MaterialInstance.h>
|
||||
#include <filament/TextureSampler.h>
|
||||
#include <filament/Skybox.h>
|
||||
#include <filament/IndirectLight.h>
|
||||
|
||||
#include <gltfio/AssetLoader.h>
|
||||
#include <gltfio/FilamentAsset.h>
|
||||
#include <gltfio/ResourceLoader.h>
|
||||
#include <gltfio/MaterialProvider.h>
|
||||
#include <gltfio/TextureProvider.h>
|
||||
|
||||
#include <ktxreader/Ktx1Reader.h>
|
||||
|
||||
#include <utils/Entity.h>
|
||||
#include <utils/EntityManager.h>
|
||||
@ -46,8 +51,11 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <map>
|
||||
@ -114,9 +122,95 @@ void MetaCoreFilamentDebugLog(const std::string& message) {
|
||||
std::cerr << "[MetaCoreDebug][Filament] " << message << std::endl;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool MetaCorePreserveGltfBlendAlphaMode() {
|
||||
const char* preserveBlend = std::getenv("METACORE_GLTF_PRESERVE_BLEND_ALPHA");
|
||||
if (preserveBlend == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return std::strcmp(preserveBlend, "1") == 0 ||
|
||||
std::strcmp(preserveBlend, "true") == 0 ||
|
||||
std::strcmp(preserveBlend, "TRUE") == 0;
|
||||
}
|
||||
|
||||
class MetaCoreGltfMaterialProvider final : public filament::gltfio::MaterialProvider {
|
||||
public:
|
||||
explicit MetaCoreGltfMaterialProvider(filament::gltfio::MaterialProvider* innerProvider)
|
||||
: InnerProvider_(innerProvider) {}
|
||||
|
||||
~MetaCoreGltfMaterialProvider() override {
|
||||
delete InnerProvider_;
|
||||
InnerProvider_ = nullptr;
|
||||
}
|
||||
|
||||
filament::MaterialInstance* createMaterialInstance(
|
||||
filament::gltfio::MaterialKey* config,
|
||||
filament::gltfio::UvMap* uvmap,
|
||||
const char* label = "material",
|
||||
const char* extras = nullptr
|
||||
) override {
|
||||
NormalizeAlphaMode(config, label);
|
||||
return InnerProvider_ != nullptr
|
||||
? InnerProvider_->createMaterialInstance(config, uvmap, label, extras)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
filament::Material* getMaterial(
|
||||
filament::gltfio::MaterialKey* config,
|
||||
filament::gltfio::UvMap* uvmap,
|
||||
const char* label = "material"
|
||||
) override {
|
||||
NormalizeAlphaMode(config, label);
|
||||
return InnerProvider_ != nullptr ? InnerProvider_->getMaterial(config, uvmap, label) : nullptr;
|
||||
}
|
||||
|
||||
const filament::Material* const* getMaterials() const noexcept override {
|
||||
return InnerProvider_ != nullptr ? InnerProvider_->getMaterials() : nullptr;
|
||||
}
|
||||
|
||||
size_t getMaterialsCount() const noexcept override {
|
||||
return InnerProvider_ != nullptr ? InnerProvider_->getMaterialsCount() : 0;
|
||||
}
|
||||
|
||||
void destroyMaterials() override {
|
||||
if (InnerProvider_ != nullptr) {
|
||||
InnerProvider_->destroyMaterials();
|
||||
}
|
||||
}
|
||||
|
||||
bool needsDummyData(filament::VertexAttribute attrib) const noexcept override {
|
||||
return InnerProvider_ != nullptr && InnerProvider_->needsDummyData(attrib);
|
||||
}
|
||||
|
||||
private:
|
||||
void NormalizeAlphaMode(filament::gltfio::MaterialKey* config, const char* label) {
|
||||
if (config == nullptr ||
|
||||
MetaCorePreserveGltfBlendAlphaMode() ||
|
||||
config->alphaMode != filament::gltfio::AlphaMode::BLEND) {
|
||||
return;
|
||||
}
|
||||
|
||||
config->alphaMode = filament::gltfio::AlphaMode::MASK;
|
||||
if (!LoggedBlendAsMask_) {
|
||||
MetaCoreFilamentDebugLog(
|
||||
"GLTF alphaMode=BLEND is rendered as MASK by default for stable foliage depth. "
|
||||
"Set METACORE_GLTF_PRESERVE_BLEND_ALPHA=1 to keep GLTF blend materials."
|
||||
);
|
||||
LoggedBlendAsMask_ = true;
|
||||
}
|
||||
if (label != nullptr && label[0] != '\0') {
|
||||
MetaCoreFilamentDebugLog(std::string("GLTF material alphaMode adjusted to MASK label=\"") + label + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
filament::gltfio::MaterialProvider* InnerProvider_ = nullptr;
|
||||
bool LoggedBlendAsMask_ = false;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class MetaCoreFilamentSceneBridge::MetaCoreFilamentSceneBridgeImpl {
|
||||
using EntityChildrenMap = std::unordered_map<utils::Entity, std::vector<utils::Entity>, utils::Entity::Hasher>;
|
||||
|
||||
public:
|
||||
MetaCoreFilamentSceneBridgeImpl() = default;
|
||||
|
||||
@ -152,6 +246,7 @@ public:
|
||||
|
||||
// 创建场景
|
||||
Scene_ = Engine_->createScene();
|
||||
LoadDefaultEnvironmentLighting();
|
||||
|
||||
// 创建默认灯光
|
||||
Light_ = utils::EntityManager::get().create();
|
||||
@ -172,6 +267,7 @@ public:
|
||||
View_ = Engine_->createView();
|
||||
View_->setScene(Scene_);
|
||||
View_->setCamera(Camera_);
|
||||
ConfigureSceneViewRenderState();
|
||||
|
||||
if (offscreen) {
|
||||
// 创建 UI 视图
|
||||
@ -210,16 +306,21 @@ public:
|
||||
// 4. 设置到 View
|
||||
View_->setRenderTarget(RenderTarget_);
|
||||
View_->setViewport({0, 0, static_cast<uint32_t>(width), static_cast<uint32_t>(height)});
|
||||
ConfigureSceneViewRenderState();
|
||||
} else {
|
||||
auto [width, height] = window.GetFramebufferSize();
|
||||
View_->setViewport({0, 0, static_cast<uint32_t>(width), static_cast<uint32_t>(height)});
|
||||
ConfigureSceneViewRenderState();
|
||||
}
|
||||
|
||||
// 确保开启后处理(为了HDR)
|
||||
View_->setPostProcessingEnabled(true);
|
||||
|
||||
// 初始化 gltfio
|
||||
MaterialProvider_ = filament::gltfio::createJitShaderProvider(Engine_);
|
||||
MaterialProvider_ = new MetaCoreGltfMaterialProvider(
|
||||
filament::gltfio::createJitShaderProvider(Engine_)
|
||||
);
|
||||
StbTextureProvider_ = filament::gltfio::createStbProvider(Engine_);
|
||||
NameManager_ = new utils::NameComponentManager(utils::EntityManager::get());
|
||||
AssetLoader_ = filament::gltfio::AssetLoader::create({ Engine_, MaterialProvider_, NameManager_ });
|
||||
RuntimeAssetSubscriptionId_ = MetaCoreRuntimeAssetRegistry::Get().Subscribe(
|
||||
@ -310,6 +411,8 @@ public:
|
||||
}
|
||||
AssetDuplicatedMaterials_.clear();
|
||||
DestroyMaterialTextureCache();
|
||||
DestroyEnvironmentLighting();
|
||||
DestroySolidColorSkybox();
|
||||
|
||||
for (auto& [id, entity] : SceneLightEntities_) {
|
||||
if (Scene_) {
|
||||
@ -333,6 +436,10 @@ public:
|
||||
delete MaterialProvider_;
|
||||
MaterialProvider_ = nullptr;
|
||||
}
|
||||
if (StbTextureProvider_) {
|
||||
delete StbTextureProvider_;
|
||||
StbTextureProvider_ = nullptr;
|
||||
}
|
||||
|
||||
DestroyDeferredRenderTargetResources(true);
|
||||
|
||||
@ -399,6 +506,7 @@ public:
|
||||
DestroyMaterialTextureCache();
|
||||
}
|
||||
ProjectRootPath_ = projectRootPath;
|
||||
LoadDefaultEnvironmentLighting();
|
||||
}
|
||||
|
||||
void DestroyMaterialTextureCache() {
|
||||
@ -413,6 +521,196 @@ public:
|
||||
MaterialTextureCache_.clear();
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::optional<std::vector<std::uint8_t>> ReadBinaryFile(const std::filesystem::path& path) {
|
||||
std::ifstream input(path, std::ios::binary | std::ios::ate);
|
||||
if (!input.is_open()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const std::streamsize fileSize = input.tellg();
|
||||
if (fileSize <= 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> bytes(static_cast<std::size_t>(fileSize));
|
||||
input.seekg(0, std::ios::beg);
|
||||
if (!input.read(reinterpret_cast<char*>(bytes.data()), fileSize)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::filesystem::path ResolveDefaultEnvironmentPath(std::string_view filename) const {
|
||||
const std::array<std::filesystem::path, 4> candidates{
|
||||
std::filesystem::path("third_party") / "filament_installed" / "bin" / "assets" / "ibl" / "lightroom_14b" / filename,
|
||||
std::filesystem::path("third_party") / "filament_installed.before-linux-sdk" / "bin" / "assets" / "ibl" / "lightroom_14b" / filename,
|
||||
std::filesystem::path("build_filament") / "samples" / "assets" / "ibl" / "lightroom_14b" / filename,
|
||||
std::filesystem::path("build_filament") / "libs" / "ktxreader" / filename
|
||||
};
|
||||
|
||||
const std::filesystem::path cwd = std::filesystem::current_path();
|
||||
for (const std::filesystem::path& relativePath : candidates) {
|
||||
const std::filesystem::path absolutePath = (cwd / relativePath).lexically_normal();
|
||||
if (std::filesystem::exists(absolutePath)) {
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
const std::filesystem::path fromProjectRoot = (ProjectRootPath_.empty()
|
||||
? std::filesystem::path{}
|
||||
: ProjectRootPath_ / ".." / relativePath).lexically_normal();
|
||||
if (!fromProjectRoot.empty() && std::filesystem::exists(fromProjectRoot)) {
|
||||
return fromProjectRoot;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] filament::Texture* LoadKtx1Texture(
|
||||
const std::filesystem::path& path,
|
||||
bool srgb,
|
||||
filament::math::float3* outSphericalHarmonics = nullptr
|
||||
) const {
|
||||
if (Engine_ == nullptr || path.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto bytes = ReadBinaryFile(path);
|
||||
if (!bytes.has_value()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto bundle = std::make_unique<ktxreader::Ktx1Bundle>(
|
||||
bytes->data(),
|
||||
static_cast<std::uint32_t>(bytes->size())
|
||||
);
|
||||
if (outSphericalHarmonics != nullptr) {
|
||||
if (!bundle->getSphericalHarmonics(outSphericalHarmonics)) {
|
||||
std::fill(outSphericalHarmonics, outSphericalHarmonics + 9, filament::math::float3{0.0f, 0.0f, 0.0f});
|
||||
}
|
||||
}
|
||||
|
||||
return ktxreader::Ktx1Reader::createTexture(Engine_, bundle.release(), srgb);
|
||||
}
|
||||
|
||||
void LoadDefaultEnvironmentLighting() {
|
||||
if (Engine_ == nullptr || Scene_ == nullptr || EnvironmentLoaded_) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::filesystem::path iblPath = ResolveDefaultEnvironmentPath("lightroom_14b_ibl.ktx");
|
||||
const std::filesystem::path skyboxPath = ResolveDefaultEnvironmentPath("lightroom_14b_skybox.ktx");
|
||||
if (iblPath.empty() || skyboxPath.empty()) {
|
||||
MetaCoreFilamentDebugLog("Default IBL assets not found; falling back to solid clear color");
|
||||
return;
|
||||
}
|
||||
|
||||
filament::math::float3 sphericalHarmonics[9]{};
|
||||
EnvironmentIblTexture_ = LoadKtx1Texture(iblPath, false, sphericalHarmonics);
|
||||
EnvironmentSkyboxTexture_ = LoadKtx1Texture(skyboxPath, false);
|
||||
if (EnvironmentIblTexture_ == nullptr || EnvironmentSkyboxTexture_ == nullptr) {
|
||||
MetaCoreFilamentDebugLog("Default IBL KTX load failed");
|
||||
DestroyEnvironmentLighting();
|
||||
return;
|
||||
}
|
||||
|
||||
EnvironmentIndirectLight_ = filament::IndirectLight::Builder()
|
||||
.reflections(EnvironmentIblTexture_)
|
||||
.irradiance(3, sphericalHarmonics)
|
||||
.intensity(EnvironmentIntensity_)
|
||||
.build(*Engine_);
|
||||
EnvironmentSkybox_ = filament::Skybox::Builder()
|
||||
.environment(EnvironmentSkyboxTexture_)
|
||||
.intensity(EnvironmentIntensity_)
|
||||
.build(*Engine_);
|
||||
|
||||
if (EnvironmentIndirectLight_ == nullptr || EnvironmentSkybox_ == nullptr) {
|
||||
MetaCoreFilamentDebugLog("Default IBL object build failed");
|
||||
DestroyEnvironmentLighting();
|
||||
return;
|
||||
}
|
||||
|
||||
Scene_->setIndirectLight(EnvironmentIndirectLight_);
|
||||
Scene_->setSkybox(EnvironmentSkybox_);
|
||||
EnvironmentLoaded_ = true;
|
||||
MetaCoreFilamentDebugLog(
|
||||
"Default IBL loaded ibl=\"" + iblPath.generic_string() +
|
||||
"\" skybox=\"" + skyboxPath.generic_string() + "\""
|
||||
);
|
||||
}
|
||||
|
||||
void DestroyEnvironmentLighting() {
|
||||
if (Scene_ != nullptr) {
|
||||
if (Scene_->getIndirectLight() == EnvironmentIndirectLight_) {
|
||||
Scene_->setIndirectLight(nullptr);
|
||||
}
|
||||
if (Scene_->getSkybox() == EnvironmentSkybox_) {
|
||||
Scene_->setSkybox(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (Engine_ != nullptr) {
|
||||
Engine_->flushAndWait();
|
||||
if (EnvironmentSkybox_ != nullptr) {
|
||||
Engine_->destroy(EnvironmentSkybox_);
|
||||
EnvironmentSkybox_ = nullptr;
|
||||
}
|
||||
if (EnvironmentIndirectLight_ != nullptr) {
|
||||
Engine_->destroy(EnvironmentIndirectLight_);
|
||||
EnvironmentIndirectLight_ = nullptr;
|
||||
}
|
||||
if (EnvironmentSkyboxTexture_ != nullptr) {
|
||||
Engine_->destroy(EnvironmentSkyboxTexture_);
|
||||
EnvironmentSkyboxTexture_ = nullptr;
|
||||
}
|
||||
if (EnvironmentIblTexture_ != nullptr) {
|
||||
Engine_->destroy(EnvironmentIblTexture_);
|
||||
EnvironmentIblTexture_ = nullptr;
|
||||
}
|
||||
}
|
||||
EnvironmentLoaded_ = false;
|
||||
}
|
||||
|
||||
[[nodiscard]] filament::Skybox* GetOrCreateSolidColorSkybox(const MetaCoreSceneView& sceneView) {
|
||||
if (Engine_ == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const filament::math::float4 color{
|
||||
sceneView.BackgroundColor.x,
|
||||
sceneView.BackgroundColor.y,
|
||||
sceneView.BackgroundColor.z,
|
||||
sceneView.BackgroundAlpha
|
||||
};
|
||||
|
||||
constexpr float epsilon = 0.0001f;
|
||||
const bool sameColor =
|
||||
std::abs(SolidColorSkyboxColor_.x - color.x) <= epsilon &&
|
||||
std::abs(SolidColorSkyboxColor_.y - color.y) <= epsilon &&
|
||||
std::abs(SolidColorSkyboxColor_.z - color.z) <= epsilon &&
|
||||
std::abs(SolidColorSkyboxColor_.w - color.w) <= epsilon;
|
||||
if (SolidColorSkybox_ != nullptr && sameColor) {
|
||||
return SolidColorSkybox_;
|
||||
}
|
||||
|
||||
DestroySolidColorSkybox();
|
||||
SolidColorSkybox_ = filament::Skybox::Builder()
|
||||
.color(color)
|
||||
.build(*Engine_);
|
||||
SolidColorSkyboxColor_ = color;
|
||||
return SolidColorSkybox_;
|
||||
}
|
||||
|
||||
void DestroySolidColorSkybox() {
|
||||
if (Scene_ != nullptr && Scene_->getSkybox() == SolidColorSkybox_) {
|
||||
Scene_->setSkybox(nullptr);
|
||||
}
|
||||
if (Engine_ != nullptr && SolidColorSkybox_ != nullptr) {
|
||||
Engine_->destroy(SolidColorSkybox_);
|
||||
SolidColorSkybox_ = nullptr;
|
||||
}
|
||||
SolidColorSkyboxColor_ = filament::math::float4{-1.0f, -1.0f, -1.0f, -1.0f};
|
||||
}
|
||||
|
||||
[[nodiscard]] std::filesystem::path ResolveMaterialTexturePath(
|
||||
const std::string& texturePath,
|
||||
const std::string& sourceModelPath
|
||||
@ -861,9 +1159,20 @@ public:
|
||||
" entities=" + std::to_string(asset->getEntityCount())
|
||||
);
|
||||
|
||||
// 加载贴图等资源
|
||||
filament::gltfio::ResourceLoader resourceLoader({ Engine_ });
|
||||
resourceLoader.loadResources(asset);
|
||||
// 加载贴图等资源。gltfio 不会默认解码 PNG/JPEG,必须注册 TextureProvider。
|
||||
const std::string gltfPath = absolutePath.string();
|
||||
filament::gltfio::ResourceConfiguration resourceConfig{};
|
||||
resourceConfig.engine = Engine_;
|
||||
resourceConfig.gltfPath = gltfPath.c_str();
|
||||
resourceConfig.normalizeSkinningWeights = true;
|
||||
filament::gltfio::ResourceLoader resourceLoader(resourceConfig);
|
||||
if (StbTextureProvider_) {
|
||||
resourceLoader.addTextureProvider("image/png", StbTextureProvider_);
|
||||
resourceLoader.addTextureProvider("image/jpeg", StbTextureProvider_);
|
||||
}
|
||||
if (!resourceLoader.loadResources(asset)) {
|
||||
std::cerr << "Warning: GLTF resources were not fully loaded for: " << absolutePath << std::endl;
|
||||
}
|
||||
|
||||
// 添加到场景
|
||||
Scene_->addEntities(asset->getEntities(), asset->getEntityCount());
|
||||
@ -1155,6 +1464,9 @@ public:
|
||||
filament::Texture* texture,
|
||||
const filament::TextureSampler& sampler
|
||||
) -> bool {
|
||||
if (texture == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const filament::Material* material = materialInstance.getMaterial();
|
||||
if (material == nullptr || !material->hasParameter(name)) {
|
||||
return false;
|
||||
@ -1165,6 +1477,8 @@ public:
|
||||
|
||||
// 5. 同步所有存活网格的材质预览属性。MaterialInstance 参数必须在渲染前更新。
|
||||
auto& rm = Engine_->getRenderableManager();
|
||||
std::unordered_map<filament::gltfio::FilamentAsset*, EntityChildrenMap> assetChildMapCache;
|
||||
std::unordered_map<utils::Entity, std::vector<utils::Entity>, utils::Entity::Hasher> materialTargetCache;
|
||||
const filament::TextureSampler materialSampler(
|
||||
filament::TextureSampler::MinFilter::LINEAR,
|
||||
filament::TextureSampler::MagFilter::LINEAR,
|
||||
@ -1175,8 +1489,29 @@ public:
|
||||
if (itEntity == ObjectToFilamentEntity_.end()) {
|
||||
continue;
|
||||
}
|
||||
std::vector<utils::Entity> materialTargetEntities;
|
||||
CollectRenderableDescendants(itEntity->second.first, itEntity->second.second, materialTargetEntities);
|
||||
const auto materialTargetCacheIterator = materialTargetCache.find(itEntity->second.second);
|
||||
if (materialTargetCacheIterator == materialTargetCache.end()) {
|
||||
std::vector<utils::Entity> materialTargetEntities;
|
||||
if (itEntity->second.first != nullptr) {
|
||||
auto childMapIterator = assetChildMapCache.find(itEntity->second.first);
|
||||
if (childMapIterator == assetChildMapCache.end()) {
|
||||
childMapIterator = assetChildMapCache.emplace(
|
||||
itEntity->second.first,
|
||||
BuildDirectParentToChildrenMap(itEntity->second.first)
|
||||
).first;
|
||||
}
|
||||
CollectRenderableDescendantsFromChildMap(
|
||||
itEntity->second.second,
|
||||
childMapIterator->second,
|
||||
materialTargetEntities
|
||||
);
|
||||
} else {
|
||||
CollectRenderableDescendants(itEntity->second.first, itEntity->second.second, materialTargetEntities);
|
||||
}
|
||||
materialTargetCache.emplace(itEntity->second.second, std::move(materialTargetEntities));
|
||||
}
|
||||
|
||||
const std::vector<utils::Entity>& materialTargetEntities = materialTargetCache.find(itEntity->second.second)->second;
|
||||
if (materialTargetEntities.empty()) {
|
||||
continue;
|
||||
}
|
||||
@ -1236,7 +1571,8 @@ public:
|
||||
renderable.EmissiveColor.z
|
||||
}
|
||||
);
|
||||
if (renderable.AlphaMode == MetaCoreMeshAlphaMode::Mask) {
|
||||
if (renderable.AlphaMode == MetaCoreMeshAlphaMode::Mask ||
|
||||
renderable.AlphaMode == MetaCoreMeshAlphaMode::Blend) {
|
||||
setFloatParameterIfPresent(*matInst, "alphaCutoff", renderable.AlphaCutoff);
|
||||
}
|
||||
setTextureParameterIfPresent(*matInst, "baseColorMap", baseColorTexture, materialSampler);
|
||||
@ -1257,6 +1593,15 @@ public:
|
||||
void ApplySceneView(const MetaCoreSceneView& sceneView) {
|
||||
if (!Camera_ || !View_) return;
|
||||
CurrentSceneView_ = sceneView;
|
||||
if (Scene_ != nullptr) {
|
||||
filament::Skybox* skybox = nullptr;
|
||||
if (sceneView.ClearFlags == MetaCoreCameraClearFlags::Skybox) {
|
||||
skybox = EnvironmentSkybox_ != nullptr ? EnvironmentSkybox_ : GetOrCreateSolidColorSkybox(sceneView);
|
||||
} else if (sceneView.ClearFlags == MetaCoreCameraClearFlags::SolidColor) {
|
||||
skybox = GetOrCreateSolidColorSkybox(sceneView);
|
||||
}
|
||||
Scene_->setSkybox(skybox);
|
||||
}
|
||||
|
||||
// 1. 视图矩阵同步
|
||||
const glm::mat4 viewMatrix = glm::lookAt(sceneView.CameraPosition, sceneView.CameraTarget, sceneView.CameraUp);
|
||||
@ -1413,6 +1758,7 @@ public:
|
||||
|
||||
View_->setRenderTarget(RenderTarget_);
|
||||
View_->setViewport({0, 0, static_cast<uint32_t>(width), static_cast<uint32_t>(height)});
|
||||
ConfigureSceneViewRenderState();
|
||||
DebugRenderTargetState("Resize after recreate resources");
|
||||
}
|
||||
|
||||
@ -1624,6 +1970,65 @@ private:
|
||||
return parentToChildren;
|
||||
}
|
||||
|
||||
EntityChildrenMap BuildDirectParentToChildrenMap(filament::gltfio::FilamentAsset* asset) const {
|
||||
EntityChildrenMap parentToChildren;
|
||||
if (!asset || Engine_ == nullptr) {
|
||||
return parentToChildren;
|
||||
}
|
||||
|
||||
auto& tm = Engine_->getTransformManager();
|
||||
const utils::Entity* entities = asset->getEntities();
|
||||
const size_t entityCount = asset->getEntityCount();
|
||||
for (size_t i = 0; i < entityCount; ++i) {
|
||||
const utils::Entity entity = entities[i];
|
||||
if (entity.isNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto instance = tm.getInstance(entity);
|
||||
if (!instance) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const utils::Entity parent = tm.getParent(instance);
|
||||
if (!parent.isNull()) {
|
||||
parentToChildren[parent].push_back(entity);
|
||||
}
|
||||
}
|
||||
return parentToChildren;
|
||||
}
|
||||
|
||||
void CollectRenderableDescendantsFromChildMap(
|
||||
utils::Entity rootEntity,
|
||||
const EntityChildrenMap& parentToChildren,
|
||||
std::vector<utils::Entity>& outEntities
|
||||
) const {
|
||||
if (!Engine_ || rootEntity.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& rm = Engine_->getRenderableManager();
|
||||
std::vector<utils::Entity> pending{rootEntity};
|
||||
std::unordered_set<utils::Entity, utils::Entity::Hasher> visited;
|
||||
while (!pending.empty()) {
|
||||
const utils::Entity entity = pending.back();
|
||||
pending.pop_back();
|
||||
if (entity.isNull() || !visited.insert(entity).second) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rm.getInstance(entity)) {
|
||||
outEntities.push_back(entity);
|
||||
}
|
||||
|
||||
const auto childrenIterator = parentToChildren.find(entity);
|
||||
if (childrenIterator == parentToChildren.end()) {
|
||||
continue;
|
||||
}
|
||||
pending.insert(pending.end(), childrenIterator->second.begin(), childrenIterator->second.end());
|
||||
}
|
||||
}
|
||||
|
||||
void CollectRenderableDescendants(
|
||||
filament::gltfio::FilamentAsset* asset,
|
||||
utils::Entity rootEntity,
|
||||
@ -1788,6 +2193,17 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureSceneViewRenderState() {
|
||||
if (View_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
View_->setBlendMode(filament::View::BlendMode::OPAQUE);
|
||||
for (uint8_t channel = 0; channel < 8; ++channel) {
|
||||
View_->setChannelDepthClearEnabled(channel, true);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugRenderTargetState(const char* event) const {
|
||||
std::ostringstream stream;
|
||||
stream
|
||||
@ -1809,9 +2225,18 @@ private:
|
||||
filament::Scene* Scene_ = nullptr;
|
||||
filament::Camera* Camera_ = nullptr;
|
||||
filament::View* View_ = nullptr;
|
||||
filament::Texture* EnvironmentIblTexture_ = nullptr;
|
||||
filament::Texture* EnvironmentSkyboxTexture_ = nullptr;
|
||||
filament::IndirectLight* EnvironmentIndirectLight_ = nullptr;
|
||||
filament::Skybox* EnvironmentSkybox_ = nullptr;
|
||||
filament::Skybox* SolidColorSkybox_ = nullptr;
|
||||
filament::math::float4 SolidColorSkyboxColor_{-1.0f, -1.0f, -1.0f, -1.0f};
|
||||
float EnvironmentIntensity_ = 30000.0f;
|
||||
bool EnvironmentLoaded_ = false;
|
||||
|
||||
filament::gltfio::AssetLoader* AssetLoader_ = nullptr;
|
||||
filament::gltfio::MaterialProvider* MaterialProvider_ = nullptr;
|
||||
filament::gltfio::TextureProvider* StbTextureProvider_ = nullptr;
|
||||
utils::NameComponentManager* NameManager_ = nullptr;
|
||||
|
||||
MetaCoreSceneRenderSync RenderSync_{};
|
||||
|
||||
@ -23,6 +23,7 @@ function(metacore_use_filament target_name)
|
||||
"${METACORE_FILAMENT_LIB_DIR}/bluegl.lib"
|
||||
"${METACORE_FILAMENT_LIB_DIR}/gltfio.lib"
|
||||
"${METACORE_FILAMENT_LIB_DIR}/gltfio_core.lib"
|
||||
"${METACORE_FILAMENT_LIB_DIR}/ktxreader.lib"
|
||||
"${METACORE_FILAMENT_LIB_DIR}/abseil.lib"
|
||||
"${METACORE_FILAMENT_LIB_DIR}/perfetto.lib"
|
||||
"${METACORE_FILAMENT_LIB_DIR}/dracodec.lib"
|
||||
|
||||
@ -1880,13 +1880,19 @@ void MetaCoreTestInstantiateImportedModelAssetIntoScene() {
|
||||
);
|
||||
|
||||
const auto assetDatabase = moduleRegistry.ResolveService<MetaCore::MetaCoreIAssetDatabaseService>();
|
||||
const auto assetEditingService = moduleRegistry.ResolveService<MetaCore::MetaCoreIAssetEditingService>();
|
||||
const auto sceneEditingService = moduleRegistry.ResolveService<MetaCore::MetaCoreISceneEditingService>();
|
||||
MetaCoreExpect(assetDatabase != nullptr, "应解析到 AssetDatabaseService");
|
||||
MetaCoreExpect(assetEditingService != nullptr, "应解析到 AssetEditingService");
|
||||
MetaCoreExpect(sceneEditingService != nullptr, "应解析到 SceneEditingService");
|
||||
|
||||
const auto modelRecord = assetDatabase->FindAssetByRelativePath(std::filesystem::path("Assets") / "Pump.gltf");
|
||||
MetaCoreExpect(modelRecord.has_value(), "应能找到导入后的模型资源");
|
||||
|
||||
const auto sourceOnlyModelDocument = assetEditingService->LoadModelAsset(modelRecord->Guid);
|
||||
MetaCoreExpect(sourceOnlyModelDocument.has_value(), "开发期无模型包文件时仍应能读取模型资产文档");
|
||||
MetaCoreExpect(!sourceOnlyModelDocument->GeneratedMaterialAssets.empty(), "模型资产文档应包含生成材质");
|
||||
|
||||
const auto instantiatedRootId = sceneEditingService->InstantiateModelAsset(editorContext, modelRecord->Guid, std::nullopt);
|
||||
MetaCoreExpect(instantiatedRootId.has_value(), "应能将导入模型实例化到场景");
|
||||
|
||||
@ -1909,9 +1915,24 @@ void MetaCoreTestInstantiateImportedModelAssetIntoScene() {
|
||||
);
|
||||
MetaCoreExpect(instantiatedRoot.GetComponent<MetaCore::MetaCoreMeshRendererComponent>().BaseColor.x == 1.0F, "根节点应继承材质颜色通道数值");
|
||||
MetaCoreExpect(std::abs(instantiatedRoot.GetComponent<MetaCore::MetaCoreMeshRendererComponent>().Metallic) < 0.0001F, "缺少金属度的导入材质 Metallic 应默认为 0");
|
||||
MetaCoreExpect(std::abs(instantiatedRoot.GetComponent<MetaCore::MetaCoreMeshRendererComponent>().Roughness) < 0.0001F, "缺少粗糙度的导入材质 Roughness 应默认为 0");
|
||||
MetaCoreExpect(std::abs(instantiatedRoot.GetComponent<MetaCore::MetaCoreMeshRendererComponent>().Roughness - 1.0F) < 0.0001F, "缺少粗糙度的导入材质 Roughness 应默认为 1");
|
||||
MetaCoreExpect(editorContext.GetActiveObjectId() == *instantiatedRootId, "实例化后应正确选中新对象");
|
||||
|
||||
const MetaCore::MetaCoreAssetGuid generatedMaterialGuid =
|
||||
instantiatedRoot.GetComponent<MetaCore::MetaCoreMeshRendererComponent>().MaterialAssetGuids.front();
|
||||
auto generatedMaterial = assetEditingService->LoadMaterialAsset(generatedMaterialGuid);
|
||||
MetaCoreExpect(generatedMaterial.has_value(), "源模型生成材质应可作为材质资源读取");
|
||||
generatedMaterial->BaseColor = glm::vec3(0.25F, 0.5F, 0.75F);
|
||||
generatedMaterial->Metallic = 0.35F;
|
||||
generatedMaterial->Roughness = 0.8F;
|
||||
MetaCoreExpect(assetEditingService->SaveMaterialAsset(generatedMaterialGuid, *generatedMaterial), "源模型生成材质应可保存编辑结果");
|
||||
|
||||
const auto reloadedGeneratedMaterial = assetEditingService->LoadMaterialAsset(generatedMaterialGuid);
|
||||
MetaCoreExpect(reloadedGeneratedMaterial.has_value(), "保存后应能重新读取源模型生成材质");
|
||||
MetaCoreExpectVec3Near(reloadedGeneratedMaterial->BaseColor, glm::vec3(0.25F, 0.5F, 0.75F), "生成材质基础色保存后应保持");
|
||||
MetaCoreExpect(std::abs(reloadedGeneratedMaterial->Metallic - 0.35F) < 0.0001F, "生成材质 Metallic 保存后应保持");
|
||||
MetaCoreExpect(std::abs(reloadedGeneratedMaterial->Roughness - 0.8F) < 0.0001F, "生成材质 Roughness 保存后应保持");
|
||||
|
||||
coreServicesModule->Shutdown(moduleRegistry);
|
||||
moduleRegistry.ShutdownServices();
|
||||
_putenv_s("METACORE_PROJECT_PATH", "");
|
||||
@ -2007,7 +2028,7 @@ void MetaCoreTestInstantiateRealGltfHierarchyIntoScene() {
|
||||
importedChild.GetComponent<MetaCore::MetaCoreMeshRendererComponent>();
|
||||
MetaCoreExpectVec3Near(childMeshRenderer.BaseColor, glm::vec3(0.2F, 0.4F, 0.6F), "真实 GLTF 子节点应继承导入材质基础色");
|
||||
MetaCoreExpect(std::abs(childMeshRenderer.Metallic) < 0.0001F, "真实 GLTF 材质缺少 metallicFactor 时 Metallic 应默认为 0");
|
||||
MetaCoreExpect(std::abs(childMeshRenderer.Roughness) < 0.0001F, "真实 GLTF 材质缺少 roughnessFactor 时 Roughness 应默认为 0");
|
||||
MetaCoreExpect(std::abs(childMeshRenderer.Roughness - 1.0F) < 0.0001F, "真实 GLTF 材质缺少 roughnessFactor 时 Roughness 应默认为 1");
|
||||
|
||||
const std::vector<MetaCore::MetaCoreId> hierarchyOrder = scene.BuildHierarchyPreorder();
|
||||
MetaCoreExpect(hierarchyOrder.size() == 3, "真实 GLTF 层级应进入层级树遍历结果");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user