#include "MetaCoreRendering/MetaCoreRendering.h" #include "MetaCoreFoundation/MetaCoreArchive.h" #include #include #include #include namespace MetaCore { namespace { template bool WriteDocument(const std::filesystem::path& path, const T& document, const MetaCoreTypeRegistry& registry) { const auto bytes = MetaCoreSerializeToBytes(document, registry); if (!bytes) return false; std::error_code error; std::filesystem::create_directories(path.parent_path(), error); std::ofstream output(path, std::ios::binary | std::ios::trunc); if (!output) return false; output.write(reinterpret_cast(bytes->data()), static_cast(bytes->size())); return output.good(); } template std::optional ReadDocument(const std::filesystem::path& path, const MetaCoreTypeRegistry& registry) { std::ifstream input(path, std::ios::binary | std::ios::ate); if (!input) return std::nullopt; const auto end = input.tellg(); if (end < 0) return std::nullopt; std::vector bytes(static_cast(end)); input.seekg(0); if (!bytes.empty() && !input.read(reinterpret_cast(bytes.data()), static_cast(bytes.size()))) return std::nullopt; T value{}; if (!MetaCoreDeserializeFromBytes(std::span(bytes.data(), bytes.size()), value, registry)) return std::nullopt; return value; } bool IsFinite(float value) { return std::isfinite(value); } } MetaCoreRenderSettingsDocument MetaCoreBuildDefaultRenderSettings() { return {}; } bool MetaCoreValidateRenderSettings(MetaCoreRenderSettingsDocument& document, std::vector* issues) { bool valid = true; const auto report = [&](std::string issue) { valid = false; if (issues) issues->push_back(std::move(issue)); }; if (document.Version == 0U || document.Version > MetaCoreRenderingSettingsVersion) { report("不支持的渲染设置版本"); document.Version = MetaCoreRenderingSettingsVersion; } if (document.DirectionalCascadeCount != 1U && document.DirectionalCascadeCount != 2U && document.DirectionalCascadeCount != 4U) { report("级联阴影数量必须为 1、2 或 4"); document.DirectionalCascadeCount = 4U; } if (!IsFinite(document.DirectionalShadowDistance) || document.DirectionalShadowDistance <= 0.0F) { report("方向光阴影距离必须为正有限值"); document.DirectionalShadowDistance = 150.0F; } if (document.DirectionalCascadeSplits.size() != document.DirectionalCascadeCount) { report("级联分割数量与级联数量不一致"); document.DirectionalCascadeSplits.resize(document.DirectionalCascadeCount); for (std::uint32_t i=0;i(i+1U)/static_cast(document.DirectionalCascadeCount); } float previous = 0.0F; for (float& split : document.DirectionalCascadeSplits) { if (!IsFinite(split) || split <= previous || split > 1.0F) { report("级联分割必须递增且位于 (0,1]"); split = std::min(1.0F, previous + 1.0F/static_cast(document.DirectionalCascadeCount)); } previous = split; } if (!document.DirectionalCascadeSplits.empty()) document.DirectionalCascadeSplits.back() = 1.0F; if (document.ShadowAtlasSize != 1024U && document.ShadowAtlasSize != 2048U && document.ShadowAtlasSize != 4096U && document.ShadowAtlasSize != 8192U) { report("阴影图集必须为 1024/2048/4096/8192"); document.ShadowAtlasSize = 4096U; } if (document.MaxShadowCastingPointSpotLights > 64U) { report("点光/聚光阴影预算不能超过 64"); document.MaxShadowCastingPointSpotLights = 64U; } if (document.MsaaSamples != 1U && document.MsaaSamples != 2U && document.MsaaSamples != 4U && document.MsaaSamples != 8U) { report("MSAA 必须为 1/2/4/8"); document.MsaaSamples = 1U; } if (document.OcclusionGraceFrames > 8U) { report("遮挡宽限帧不能超过 8"); document.OcclusionGraceFrames = 8U; } if (document.GlobalParticleBudget == 0U || document.GlobalParticleBudget > 1000000U) { report("全局粒子预算必须位于 [1,1000000]"); document.GlobalParticleBudget = 100000U; } if (document.DynamicLinePointBudget == 0U) { report("动态线点预算必须大于零"); document.DynamicLinePointBudget = 262144U; } return valid; } bool MetaCoreValidatePostProcessProfile(MetaCorePostProcessProfileDocument& document, std::vector* issues) { bool valid = true; const auto report=[&](std::string issue){valid=false;if(issues)issues->push_back(std::move(issue));}; if (document.Version == 0U || document.Version > MetaCorePostProcessProfileVersion) { report("不支持的后处理 Profile 版本"); document.Version=MetaCorePostProcessProfileVersion; } if (!IsFinite(document.ManualEv100)) { report("手动曝光必须为有限值"); document.ManualEv100=15.0F; } if (!IsFinite(document.AutoExposureMinEv100) || !IsFinite(document.AutoExposureMaxEv100) || document.AutoExposureMinEv100 > document.AutoExposureMaxEv100) { report("自动曝光范围无效"); document.AutoExposureMinEv100=-4.0F;document.AutoExposureMaxEv100=16.0F; } if (!IsFinite(document.BloomStrength) || document.BloomStrength < 0.0F) { report("Bloom 强度不能为负"); document.BloomStrength=0.1F; } if (document.MsaaSamples!=1U&&document.MsaaSamples!=2U&&document.MsaaSamples!=4U&&document.MsaaSamples!=8U) { report("Profile MSAA 必须为 1/2/4/8"); document.MsaaSamples=1U; } document.Saturation=std::clamp(document.Saturation,0.0F,2.0F); document.Contrast=std::clamp(document.Contrast,0.0F,2.0F); return valid; } bool MetaCoreValidateEnvironmentProfile(MetaCoreEnvironmentProfileDocument& document, std::vector* issues) { bool valid=true;const auto report=[&](std::string issue){valid=false;if(issues)issues->push_back(std::move(issue));}; if(document.Version==0U||document.Version>MetaCoreEnvironmentProfileVersion){report("不支持的环境 Profile 版本");document.Version=MetaCoreEnvironmentProfileVersion;} if(!IsFinite(document.IndirectLightIntensity)||document.IndirectLightIntensity<0.0F){report("环境光强度无效");document.IndirectLightIntensity=30000.0F;} if(!IsFinite(document.SkyboxIntensity)||document.SkyboxIntensity<0.0F){report("天空盒强度无效");document.SkyboxIntensity=30000.0F;} if(!IsFinite(document.RotationDegrees)){report("环境旋转无效");document.RotationDegrees=0.0F;} document.RotationDegrees=std::fmod(document.RotationDegrees,360.0F);if(document.RotationDegrees<0.0F)document.RotationDegrees+=360.0F; return valid; } bool MetaCoreWriteRenderSettings(const std::filesystem::path& path, const MetaCoreRenderSettingsDocument& document, const MetaCoreTypeRegistry& registry) { MetaCoreRenderSettingsDocument value=document;if(!MetaCoreValidateRenderSettings(value))return false;return WriteDocument(path,value,registry); } std::optional MetaCoreReadRenderSettings(const std::filesystem::path& path, const MetaCoreTypeRegistry& registry) { auto value=ReadDocument(path,registry);if(!value)return std::nullopt;if(value->Version>MetaCoreRenderingSettingsVersion)return std::nullopt;(void)MetaCoreValidateRenderSettings(*value);return value; } bool MetaCoreWriteEnvironmentProfile(const std::filesystem::path& path,const MetaCoreEnvironmentProfileDocument& document,const MetaCoreTypeRegistry& registry){auto value=document;if(!value.AssetGuid.IsValid()||!MetaCoreValidateEnvironmentProfile(value))return false;return WriteDocument(path,value,registry);} std::optional MetaCoreReadEnvironmentProfile(const std::filesystem::path& path,const MetaCoreTypeRegistry& registry){auto value=ReadDocument(path,registry);if(!value||value->Version>MetaCoreEnvironmentProfileVersion||!value->AssetGuid.IsValid())return std::nullopt;(void)MetaCoreValidateEnvironmentProfile(*value);return value;} bool MetaCoreWritePostProcessProfile(const std::filesystem::path& path,const MetaCorePostProcessProfileDocument& document,const MetaCoreTypeRegistry& registry){auto value=document;if(!value.AssetGuid.IsValid()||!MetaCoreValidatePostProcessProfile(value))return false;return WriteDocument(path,value,registry);} std::optional MetaCoreReadPostProcessProfile(const std::filesystem::path& path,const MetaCoreTypeRegistry& registry){auto value=ReadDocument(path,registry);if(!value||value->Version>MetaCorePostProcessProfileVersion||!value->AssetGuid.IsValid())return std::nullopt;(void)MetaCoreValidatePostProcessProfile(*value);return value;} std::int32_t MetaCoreSelectLod(const MetaCoreLodGroupComponent& group, float screenHeight, std::int32_t previousLevel) { if(!group.Enabled||group.Levels.empty())return -1; screenHeight=std::max(0.0F,screenHeight); std::int32_t selected=group.CullBelowLastLevel?-1:static_cast(group.Levels.size()-1U); for(std::size_t i=0;i=group.Levels[i].ScreenHeight){selected=static_cast(i);break;} if(previousLevel>=0&&static_cast(previousLevel)(boundaryLevel)].ScreenHeight;if(std::abs(screenHeight-boundary)<=std::max(0.0F,group.Hysteresis))selected=previousLevel;} return selected; } std::vector MetaCoreAllocateShadowBudget(const std::vector& candidates, const MetaCoreRenderSettingsDocument& settings) { std::vector eligible;for(const auto& candidate:candidates)if(candidate.Enabled&&candidate.CastShadows)eligible.push_back(candidate); std::stable_sort(eligible.begin(),eligible.end(),[](const auto& a,const auto& b){if(a.Type==MetaCoreLightType::Directional&&b.Type!=MetaCoreLightType::Directional)return true;if(a.Type!=MetaCoreLightType::Directional&&b.Type==MetaCoreLightType::Directional)return false;if(a.Priority!=b.Priority)return a.Priority>b.Priority;if(a.DistanceToCamera!=b.DistanceToCamera)return a.DistanceToCamera result;std::uint32_t localCount=0U;for(const auto& candidate:eligible){if(candidate.Type!=MetaCoreLightType::Directional&&localCount>=settings.MaxShadowCastingPointSpotLights)continue;result.push_back(candidate.ObjectId);if(candidate.Type!=MetaCoreLightType::Directional)++localCount;}return result; } std::uint32_t MetaCoreAllocateParticleBudget(std::uint32_t requested,std::uint32_t emitterMaximum,std::uint32_t globalRemaining){return std::min({requested,emitterMaximum,globalRemaining});} const MetaCorePostProcessProfileDocument& MetaCoreResolvePostProcessProfile(const MetaCorePostProcessProfileDocument& engineDefault,const MetaCorePostProcessProfileDocument* sceneProfile,const MetaCorePostProcessProfileDocument* cameraOverride){if(cameraOverride)return *cameraOverride;if(sceneProfile)return *sceneProfile;return engineDefault;} MetaCoreMaterialTemplateRegistry::MetaCoreMaterialTemplateRegistry() { const auto floatParameter=[](std::string name,float value,float minimum,float maximum){MetaCoreMaterialTemplateParameter parameter;parameter.Name=name;parameter.Type=MetaCoreMaterialParameterType::Float;parameter.Minimum=minimum;parameter.Maximum=maximum;parameter.DefaultValue.Name=parameter.Name;parameter.DefaultValue.Type=parameter.Type;parameter.DefaultValue.FloatValue=value;return parameter;}; const auto colorParameter=[](std::string name,glm::vec3 value){MetaCoreMaterialTemplateParameter parameter;parameter.Name=name;parameter.Type=MetaCoreMaterialParameterType::Color;parameter.DefaultValue.Name=parameter.Name;parameter.DefaultValue.Type=parameter.Type;parameter.DefaultValue.VectorValue=value;return parameter;}; const auto textureParameter=[](std::string name){MetaCoreMaterialTemplateParameter parameter;parameter.Name=name;parameter.Type=MetaCoreMaterialParameterType::Texture;parameter.DefaultValue.Name=parameter.Name;parameter.DefaultValue.Type=parameter.Type;return parameter;}; Templates_.push_back({"metacore.pbr",1U,"pbr.filamat",{colorParameter("baseColor",{1.0F,1.0F,1.0F}),textureParameter("baseColorTexture"),floatParameter("metallic",0.0F,0.0F,1.0F),floatParameter("roughness",1.0F,0.0F,1.0F),textureParameter("normalTexture"),textureParameter("emissiveTexture")}}); Templates_.push_back({"metacore.unlit",1U,"unlit.filamat",{colorParameter("color",{1.0F,1.0F,1.0F}),textureParameter("texture")}}); Templates_.push_back({"metacore.transparent",1U,"transparent.filamat",{colorParameter("color",{1.0F,1.0F,1.0F}),textureParameter("texture"),floatParameter("opacity",1.0F,0.0F,1.0F)}}); Templates_.push_back({"metacore.decal",1U,"decal.filamat",{colorParameter("baseColor",{1.0F,1.0F,1.0F}),textureParameter("baseColorTexture"),textureParameter("normalTexture"),floatParameter("opacity",1.0F,0.0F,1.0F)}}); Templates_.push_back({"metacore.terrain",1U,"terrain.filamat",{textureParameter("heightmap"),textureParameter("splatMap")}}); Templates_.push_back({"metacore.particle",1U,"particle.filamat",{textureParameter("texture"),colorParameter("tint",{1.0F,1.0F,1.0F})}}); Templates_.push_back({"metacore.line",1U,"line.filamat",{textureParameter("texture"),colorParameter("tint",{1.0F,1.0F,1.0F})}}); } const MetaCoreMaterialTemplateDescriptor* MetaCoreMaterialTemplateRegistry::Find(std::string_view templateId) const {const auto iterator=std::find_if(Templates_.begin(),Templates_.end(),[&](const auto& value){return value.TemplateId==templateId;});return iterator==Templates_.end()?nullptr:&*iterator;} bool MetaCoreMaterialTemplateRegistry::ValidateAndMigrate(MetaCoreMaterialAssetDocument& material,std::vector* issues) const { if(material.TemplateId.empty()){material.TemplateId=material.ShaderModel==MetaCoreMaterialShaderModel::PbrMetalRough?"metacore.pbr":"metacore.unlit";} const auto* descriptor=Find(material.TemplateId);if(!descriptor){if(issues)issues->push_back("未知材质模板: "+material.TemplateId);return false;} bool valid=true;std::vector migrated;std::unordered_set used; for(const auto& schema:descriptor->Parameters){const auto existing=std::find_if(material.Parameters.begin(),material.Parameters.end(),[&](const auto& parameter){return parameter.Name==schema.Name&¶meter.Type==schema.Type;});auto value=existing==material.Parameters.end()?schema.DefaultValue:*existing;if(existing==material.Parameters.end()&&issues)issues->push_back("补充材质参数默认值: "+schema.Name);if(schema.Type==MetaCoreMaterialParameterType::Float)value.FloatValue=std::clamp(value.FloatValue,schema.Minimum,schema.Maximum);migrated.push_back(std::move(value));used.insert(schema.Name);} for(const auto& parameter:material.Parameters)if(!used.contains(parameter.Name)){valid=false;if(issues)issues->push_back("模板不接受材质参数: "+parameter.Name);} material.Parameters=std::move(migrated);material.TemplateVersion=descriptor->Version;return valid; } } // namespace MetaCore