MetaCore/Source/MetaCoreRendering/Private/MetaCoreRendering.cpp
2026-07-22 14:14:54 +08:00

131 lines
15 KiB
C++

#include "MetaCoreRendering/MetaCoreRendering.h"
#include "MetaCoreFoundation/MetaCoreArchive.h"
#include <algorithm>
#include <cmath>
#include <fstream>
#include <unordered_set>
namespace MetaCore {
namespace {
template <typename T>
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<const char*>(bytes->data()), static_cast<std::streamsize>(bytes->size()));
return output.good();
}
template <typename T>
std::optional<T> 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<std::byte> bytes(static_cast<std::size_t>(end));
input.seekg(0);
if (!bytes.empty() && !input.read(reinterpret_cast<char*>(bytes.data()), static_cast<std::streamsize>(bytes.size()))) return std::nullopt;
T value{};
if (!MetaCoreDeserializeFromBytes(std::span<const std::byte>(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<std::string>* 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<document.DirectionalCascadeCount;++i) document.DirectionalCascadeSplits[i]=static_cast<float>(i+1U)/static_cast<float>(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<float>(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<std::string>* 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<std::string>* 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<MetaCoreRenderSettingsDocument> MetaCoreReadRenderSettings(const std::filesystem::path& path, const MetaCoreTypeRegistry& registry) { auto value=ReadDocument<MetaCoreRenderSettingsDocument>(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<MetaCoreEnvironmentProfileDocument> MetaCoreReadEnvironmentProfile(const std::filesystem::path& path,const MetaCoreTypeRegistry& registry){auto value=ReadDocument<MetaCoreEnvironmentProfileDocument>(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<MetaCorePostProcessProfileDocument> MetaCoreReadPostProcessProfile(const std::filesystem::path& path,const MetaCoreTypeRegistry& registry){auto value=ReadDocument<MetaCorePostProcessProfileDocument>(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<std::int32_t>(group.Levels.size()-1U);
for(std::size_t i=0;i<group.Levels.size();++i)if(screenHeight>=group.Levels[i].ScreenHeight){selected=static_cast<std::int32_t>(i);break;}
if(previousLevel>=0&&static_cast<std::size_t>(previousLevel)<group.Levels.size()&&selected!=previousLevel){const std::int32_t boundaryLevel=selected<0?previousLevel:std::min(selected,previousLevel);const float boundary=group.Levels[static_cast<std::size_t>(boundaryLevel)].ScreenHeight;if(std::abs(screenHeight-boundary)<=std::max(0.0F,group.Hysteresis))selected=previousLevel;}
return selected;
}
std::vector<MetaCoreId> MetaCoreAllocateShadowBudget(const std::vector<MetaCoreShadowCandidate>& candidates, const MetaCoreRenderSettingsDocument& settings) {
std::vector<MetaCoreShadowCandidate> 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<b.DistanceToCamera;return a.ObjectId<b.ObjectId;});
std::vector<MetaCoreId> 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<std::string>* 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<MetaCoreMaterialParameterDocument> migrated;std::unordered_set<std::string> 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&&parameter.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