Init repo

This commit is contained in:
Eragon-Brisingr
2026-06-30 16:30:49 +08:00
parent a861b4680b
commit 64354806bd
4 changed files with 30 additions and 18 deletions

View File

@@ -35,7 +35,7 @@ UPackage* FShaderLabMaterialRegistry::GetPackage()
return Package;
}
FString FShaderLabMaterialRegistry::MakeObjectName(const FString& ShaderName)
FName FShaderLabMaterialRegistry::MakeObjectName(const FString& ShaderName)
{
FString Out;
Out.Reserve(ShaderName.Len());
@@ -47,12 +47,12 @@ FString FShaderLabMaterialRegistry::MakeObjectName(const FString& ShaderName)
{
Out = TEXT("Unnamed");
}
return Out;
return FName(*Out);
}
FString FShaderLabMaterialRegistry::MakeObjectPath(const FString& ShaderName)
{
return FString::Printf(TEXT("%s.%s"), GShaderLabPackageName, *MakeObjectName(ShaderName));
return FString::Printf(TEXT("%s.%s"), GShaderLabPackageName, *MakeObjectName(ShaderName).ToString());
}
UMaterial* FShaderLabMaterialRegistry::FindMaterial(const FString& ShaderName) const
@@ -61,28 +61,29 @@ UMaterial* FShaderLabMaterialRegistry::FindMaterial(const FString& ShaderName) c
{
return nullptr;
}
return FindObject<UMaterial>(Package, *MakeObjectName(ShaderName));
return FindObject<UMaterial>(Package, *MakeObjectName(ShaderName).ToString());
}
UMaterial* FShaderLabMaterialRegistry::RegisterFromModel(const FShaderLabModel& Model)
{
UPackage* Pkg = GetPackage();
const FString ObjName = MakeObjectName(Model.ShaderName);
const FName ObjName = MakeObjectName(Model.ShaderName);
// Contract: a material's identity is its file name. Two different source files that sanitize to the
// same object name are a hard error (would otherwise silently clobber each other / break MIC refs).
// The key is an FName, so the collision check is case-insensitive — matching UObject name semantics.
if (const FShaderLabModel* Existing = RegisteredModels.Find(ObjName))
{
if (!FPaths::IsSamePath(Existing->SourceFilePath, Model.SourceFilePath))
{
UE_LOG(LogShaderLabRegistry, Error,
TEXT("ShaderLab: duplicate material name '%s' from '%s' and '%s' — rename one file."),
*ObjName, *Existing->SourceFilePath, *Model.SourceFilePath);
*ObjName.ToString(), *Existing->SourceFilePath, *Model.SourceFilePath);
return nullptr;
}
}
UMaterial* Material = FindObject<UMaterial>(Pkg, *ObjName);
UMaterial* Material = FindObject<UMaterial>(Pkg, *ObjName.ToString());
const bool bNewlyCreated = (Material == nullptr);
if (bNewlyCreated)
{
@@ -90,16 +91,18 @@ UMaterial* FShaderLabMaterialRegistry::RegisterFromModel(const FShaderLabModel&
// (RF_Standalone alone is not a GC root in a cooked runtime), which removes its entry from
// the IoStore script-object table (RemoveUnreachableScriptObjects) and makes cooked Material
// Instances that reference it resolve their Parent to null -> fall back to the default material.
Material = NewObject<UMaterial>(Pkg, FName(*ObjName), RF_Public | RF_Standalone | RF_MarkAsRootSet);
Material = NewObject<UMaterial>(Pkg, ObjName, RF_Public | RF_Standalone | RF_MarkAsRootSet);
}
RegisteredModels.FindOrAdd(ObjName) = Model;
// Register with the loading system so imports to "/Script/UShaderLab.<ObjName>" from other
// packages resolve to this in-memory object even if requested mid async-load.
// packages resolve to this in-memory object — required for cooked builds, where the linker
// resolves a Material Instance's parent import through this registration (without it the parent
// resolves to null and the instance falls back to the default material).
NotifyRegistrationEvent(
FName(GShaderLabPackageName),
FName(*ObjName),
ObjName,
ENotifyRegistrationType::NRT_NoExportObject,
ENotifyRegistrationPhase::NRP_Finished,
nullptr,

View File

@@ -31,7 +31,7 @@ public:
UPackage* GetPackage();
/** Deterministic, UObject-safe object name for a shader name like "ShaderLab/RustyMetal". */
static FString MakeObjectName(const FString& ShaderName);
static FName MakeObjectName(const FString& ShaderName);
/** Full object path, e.g. "/Script/UShaderLab.ShaderLab_RustyMetal". */
static FString MakeObjectPath(const FString& ShaderName);
@@ -48,10 +48,10 @@ public:
FOnShaderLabBuildMaterial& OnBuildMaterial() { return BuildMaterialDelegate; }
/** Models registered so far, keyed by object name (used by the instance factory picker and the example/validation commandlets). */
const TMap<FString, FShaderLabModel>& GetRegisteredModels() const { return RegisteredModels; }
const TMap<FName, FShaderLabModel>& GetRegisteredModels() const { return RegisteredModels; }
private:
UPackage* Package = nullptr;
FOnShaderLabBuildMaterial BuildMaterialDelegate;
TMap<FString, FShaderLabModel> RegisteredModels;
TMap<FName, FShaderLabModel> RegisteredModels;
};

View File

@@ -4,6 +4,7 @@
#include "Engine/Engine.h"
#include "IDirectoryWatcher.h"
#include "Interfaces/IPluginManager.h"
#include "MaterialShared.h"
#include "Materials/Material.h"
#include "Misc/Paths.h"
#include "Modules/ModuleManager.h"
@@ -31,7 +32,15 @@ namespace
}
return;
}
// Recompile for rendering / editor preview (async).
// Recompile the base AND propagate to everything that depends on it. A bare PostEditChange
// recompiles only the base shell; the instances carry their own static-permutation shader maps
// (and the level components render those), so on a hot-reload they must be recompiled and
// re-pushed too. FMaterialUpdateContext does exactly that on scope exit: recompile the listed
// material, then recache every dependent instance and refresh the components/viewports using it.
FMaterialUpdateContext UpdateContext;
UpdateContext.AddMaterial(&Material);
Material.PreEditChange(nullptr);
Material.PostEditChange();
}
}

View File

@@ -30,12 +30,12 @@ namespace
// Collect the registered in-memory base materials (sorted by name for a stable layout).
TArray<UMaterial*> Bases;
TArray<FString> Names;
TArray<FName> Names;
Registry.GetRegisteredModels().GenerateKeyArray(Names);
Names.Sort();
for (const FString& Name : Names)
Names.Sort([](const FName& A, const FName& B) { return A.Compare(B) < 0; });
for (const FName& Name : Names)
{
if (UMaterial* Base = Registry.FindMaterial(Name))
if (UMaterial* Base = Registry.FindMaterial(Name.ToString()))
{
Bases.Add(Base);
}