Fix cook/runtime error

This commit is contained in:
Eragon-Brisingr
2026-07-03 17:44:09 +08:00
parent e76eb856f5
commit 530708cd29
5 changed files with 369 additions and 19 deletions

View File

@@ -226,6 +226,26 @@ namespace ShaderLabGraph
}
}
template <typename T>
static T* NewExpr(UMaterial& Material, int32& IoY, int32 Column);
// A Substrate material in the Decal domain must route its BSDF through a SubstrateConvertToDecal node — that
// node flags the material with the SSM_Decal shading model, without which the engine's Substrate sanitization
// (Material.cpp) silently resets MaterialDomain back to MD_Surface (→ DecalComponent then rejects it with
// "Decal Material must use Deferred Decal Material Domain"). This mirrors exactly what the material editor
// inserts when you pick the Deferred Decal domain. Returns the node to connect to FrontMaterial (the wrapper
// for Decal, otherwise the BSDF unchanged).
static UMaterialExpression* WrapBsdfForDecal(UMaterial& Material, const FShaderLabModel& Model, UMaterialExpression* Bsdf, int32& IoY)
{
if (Model.Settings.Domain != EShaderLabDomain::Decal)
{
return Bsdf;
}
UMaterialExpressionSubstrateConvertToDecal* Node = NewExpr<UMaterialExpressionSubstrateConvertToDecal>(Material, IoY, 300);
Node->DecalMaterial.Connect(0, Bsdf);
return Node;
}
static EBlendMode MapBlend(EShaderLabBlendMode B)
{
switch (B)
@@ -2383,14 +2403,22 @@ bool FShaderLabGraphBuilder::BuildInto(UMaterial& Material, const FShaderLabMode
case EShaderLabPropertyType::Texture3D:
case EShaderLabPropertyType::TextureCubeArray:
{
// Array / volume texture object parameter. The engine assigns a matching-dimension default when
// Texture is left null; the artist binds a real asset on the Material Instance. (Built-in white/
// black/grey/normal default tokens only exist for Texture2D, so they are not applied here.)
// Array / volume texture object parameter. Built-in white/black/grey/normal default tokens are
// Texture2D-only and must NOT be applied here, but an explicit asset-path default (e.g.
// "/Engine/EngineResources/DefaultVolumeTexture") of the matching dimension is honored. Left null,
// the engine assigns a matching-dimension default and the artist binds a real asset on the instance.
UMaterialExpressionTextureObjectParameter* E = NewExpr<UMaterialExpressionTextureObjectParameter>(Material, ParamY, -1000);
E->ParameterName = Prop.Name;
E->Group = FName(*Prop.Group);
E->SortPriority = Prop.SortPriority;
E->SamplerType = SAMPLERTYPE_Color;
if (Prop.TextureDefault.StartsWith(TEXT("/")))
{
UTexture* DefaultTex = LoadObject<UTexture>(nullptr, *Prop.TextureDefault);
checkf(DefaultTex, TEXT("ShaderLab property '%s': array/volume DefaultTexture '%s' failed to load."),
*Prop.Name.ToString(), *Prop.TextureDefault);
E->Texture = DefaultTex;
}
Node.Expr = E;
Node.bIsTexture = true;
break;
@@ -2485,7 +2513,7 @@ bool FShaderLabGraphBuilder::BuildInto(UMaterial& Material, const FShaderLabMode
{
return false;
}
EditorOnly->FrontMaterial.Connect(0, Slab);
EditorOnly->FrontMaterial.Connect(0, WrapBsdfForDecal(Material, Model, Slab, ParamY));
}
else
{
@@ -2562,7 +2590,7 @@ bool FShaderLabGraphBuilder::BuildInto(UMaterial& Material, const FShaderLabMode
{
return false;
}
EditorOnly->FrontMaterial.Connect(0, Root);
EditorOnly->FrontMaterial.Connect(0, WrapBsdfForDecal(Material, Model, Root, ParamY));
// Material-level Opacity / OpacityMask from named Value blocks.
auto ConnectMaterialOutput = [&](FExpressionInput& Pin, FName ValueName, const TCHAR* What) -> bool