MetaCore/tests/MetaCoreRenderTests.cpp
2026-07-22 14:14:54 +08:00

123 lines
8.1 KiB
C++

#include "MetaCoreFoundation/MetaCoreGeneratedReflection.h"
#include "MetaCoreRendering/MetaCoreRendering.h"
#include "MetaCoreScene/MetaCoreScene.h"
#include "MetaCoreScene/MetaCoreSceneSerializer.h"
#include <cmath>
#include <algorithm>
#include <filesystem>
#include <iostream>
namespace {
int Failures = 0;
void Expect(bool condition, const char* message) { if (!condition) { ++Failures; std::cerr << "FAIL: " << message << '\n'; } }
MetaCore::MetaCoreTypeRegistry BuildRegistry() {
MetaCore::MetaCoreTypeRegistry registry;
MetaCore::MetaCoreRegisterFoundationGeneratedTypes(registry);
MetaCore::MetaCoreRegisterRenderingGeneratedTypes(registry);
MetaCore::MetaCoreRegisterSceneGeneratedTypes(registry);
return registry;
}
void TestSettingsAndProfiles() {
const MetaCore::MetaCorePostProcessProfileDocument safeDefaults;
Expect(std::abs(safeDefaults.ManualEv100 - 15.0F) < 0.0001F, "default exposure preserves Filament PBR brightness");
Expect(!safeDefaults.BloomEnabled, "default bloom does not make ordinary PBR materials appear emissive");
auto settings = MetaCore::MetaCoreBuildDefaultRenderSettings();
settings.DirectionalCascadeCount = 3U; settings.MsaaSamples = 3U; settings.GlobalParticleBudget = 0U;
std::vector<std::string> issues;
Expect(!MetaCore::MetaCoreValidateRenderSettings(settings, &issues), "invalid settings rejected");
Expect(settings.DirectionalCascadeCount == 4U && settings.MsaaSamples == 1U && settings.GlobalParticleBudget == 100000U, "settings repaired deterministically");
const auto registry = BuildRegistry();
const auto path = std::filesystem::temp_directory_path() / "MetaCoreRenderTests" / "Rendering.mcruntime";
Expect(MetaCore::MetaCoreWriteRenderSettings(path, settings, registry), "render settings write");
const auto loaded = MetaCore::MetaCoreReadRenderSettings(path, registry);
Expect(loaded.has_value() && loaded->DirectionalCascadeCount == 4U, "render settings round trip");
MetaCore::MetaCoreEnvironmentProfileDocument environment;
environment.AssetGuid = MetaCore::MetaCoreAssetGuid::Generate();
environment.Name = "Factory IBL";
const auto environmentPath = path.parent_path() / "factory.mcenvironment";
Expect(MetaCore::MetaCoreWriteEnvironmentProfile(environmentPath, environment, registry), "environment profile write");
const auto loadedEnvironment = MetaCore::MetaCoreReadEnvironmentProfile(environmentPath, registry);
Expect(loadedEnvironment.has_value() && loadedEnvironment->AssetGuid == environment.AssetGuid, "environment profile round trip");
MetaCore::MetaCorePostProcessProfileDocument postProcess;
postProcess.AssetGuid = MetaCore::MetaCoreAssetGuid::Generate();
postProcess.Name = "Factory Camera";
const auto postProcessPath = path.parent_path() / "factory.mcpostprocess";
Expect(MetaCore::MetaCoreWritePostProcessProfile(postProcessPath, postProcess, registry), "post process profile write");
const auto loadedPostProcess = MetaCore::MetaCoreReadPostProcessProfile(postProcessPath, registry);
Expect(loadedPostProcess.has_value() && loadedPostProcess->AssetGuid == postProcess.AssetGuid, "post process profile round trip");
MetaCore::MetaCorePostProcessProfileDocument engineDefault, scene, camera;
scene.Name = "Scene"; camera.Name = "Camera";
Expect(&MetaCore::MetaCoreResolvePostProcessProfile(engineDefault, &scene, &camera) == &camera, "camera profile precedence");
Expect(&MetaCore::MetaCoreResolvePostProcessProfile(engineDefault, &scene, nullptr) == &scene, "scene profile precedence");
}
void TestMaterialTemplates() {
MetaCore::MetaCoreMaterialTemplateRegistry registry;
Expect(registry.GetTemplates().size() == 7U, "all production material templates registered");
MetaCore::MetaCoreMaterialAssetDocument material;
material.TemplateId = "metacore.pbr";
material.Parameters.push_back({"metallic", MetaCore::MetaCoreMaterialParameterType::Float, 2.0F, false, {}, {}});
std::vector<std::string> issues;
Expect(registry.ValidateAndMigrate(material, &issues), "compatible material parameters migrate");
const auto metallic = std::find_if(material.Parameters.begin(), material.Parameters.end(), [](const auto& value){return value.Name=="metallic";});
Expect(metallic != material.Parameters.end() && std::abs(metallic->FloatValue-1.0F)<0.0001F, "material range clamps");
material.TemplateId = "project.raw.mat";
Expect(!registry.ValidateAndMigrate(material, nullptr), "project raw material source rejected");
}
void TestBudgetsAndLod() {
MetaCore::MetaCoreLodGroupComponent lod;
lod.Levels = {{0.5F, {}, {}}, {0.2F, {}, {}}, {0.05F, {}, {}}};
Expect(MetaCore::MetaCoreSelectLod(lod, 0.7F) == 0, "lod0 selected");
Expect(MetaCore::MetaCoreSelectLod(lod, 0.3F) == 1, "lod1 selected");
Expect(MetaCore::MetaCoreSelectLod(lod, 0.19F, 1) == 1, "lod hysteresis retains previous level");
Expect(MetaCore::MetaCoreSelectLod(lod, 0.01F) == -1, "lod culls below final threshold");
auto settings = MetaCore::MetaCoreBuildDefaultRenderSettings(); settings.MaxShadowCastingPointSpotLights = 2U;
std::vector<MetaCore::MetaCoreShadowCandidate> candidates{
{4, MetaCore::MetaCoreLightType::Point, 1, 1.0F, true, true},
{2, MetaCore::MetaCoreLightType::Spot, 5, 50.0F, true, true},
{1, MetaCore::MetaCoreLightType::Directional, 0, 100.0F, true, true},
{3, MetaCore::MetaCoreLightType::Point, 1, 2.0F, true, true}};
const auto selected = MetaCore::MetaCoreAllocateShadowBudget(candidates, settings);
Expect(selected.size()==3U && selected[0]==1U && selected[1]==2U && selected[2]==4U, "shadow allocation is priority and id stable");
Expect(MetaCore::MetaCoreAllocateParticleBudget(500U, 300U, 200U)==200U, "particle budget clamps globally");
}
void TestSceneProductionComponents() {
MetaCore::MetaCoreScene scene;
auto object = scene.CreateGameObject("Rendering Components");
object.AddComponent<MetaCore::MetaCoreReflectionProbeComponent>().Priority = 7;
object.AddComponent<MetaCore::MetaCoreLodGroupComponent>().Levels.push_back({0.5F, {}, {}});
object.AddComponent<MetaCore::MetaCoreParticleEmitterComponent>().MaxParticles = 321U;
object.AddComponent<MetaCore::MetaCoreLineRendererComponent>().Points = {{0,0,0},{1,0,0}};
object.AddComponent<MetaCore::MetaCoreTrailRendererComponent>().MaxPoints = 42U;
object.AddComponent<MetaCore::MetaCoreDecalProjectorComponent>().Opacity = 0.4F;
object.AddComponent<MetaCore::MetaCoreTerrainComponent>().ChunkResolution = 32U;
const auto snapshot = scene.CaptureSnapshot();
MetaCore::MetaCoreScene restored; restored.RestoreSnapshot(snapshot);
const auto restoredObject = restored.FindGameObject(object.GetId());
Expect(restoredObject && restoredObject.HasComponent<MetaCore::MetaCoreReflectionProbeComponent>(), "reflection probe snapshot");
Expect(restoredObject.HasComponent<MetaCore::MetaCoreLodGroupComponent>() && restoredObject.HasComponent<MetaCore::MetaCoreParticleEmitterComponent>(), "lod and particles snapshot");
Expect(restoredObject.HasComponent<MetaCore::MetaCoreLineRendererComponent>() && restoredObject.HasComponent<MetaCore::MetaCoreTrailRendererComponent>(), "line and trail snapshot");
Expect(restoredObject.HasComponent<MetaCore::MetaCoreDecalProjectorComponent>() && restoredObject.HasComponent<MetaCore::MetaCoreTerrainComponent>(), "decal and terrain snapshot");
MetaCore::MetaCoreSceneDocument document; document.Name="Rendering"; document.GameObjects=snapshot.GameObjects;
const auto registry=BuildRegistry(); const auto path=std::filesystem::temp_directory_path()/"MetaCoreRenderTests"/"Rendering.mcscene.json";
Expect(MetaCore::MetaCoreSceneSerializer::SaveSceneToJson(path,document,registry),"render component scene json save");
const auto loaded=MetaCore::MetaCoreSceneSerializer::LoadSceneFromJson(path,registry);
Expect(loaded&&loaded->GameObjects.size()==1U&&loaded->GameObjects[0].Terrain.has_value(),"render component scene json load");
}
}
int main() {
TestSettingsAndProfiles(); TestMaterialTemplates(); TestBudgetsAndLod(); TestSceneProductionComponents();
if(Failures==0)std::cout<<"MetaCoreRenderTests passed\n";return Failures==0?0:1;
}