MI stuff is now workign
This commit is contained in:
BIN
Content/Testing/M_Test.uasset
LFS
BIN
Content/Testing/M_Test.uasset
LFS
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,80 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "MCPHandler.h"
|
||||||
|
#include "MCPFetcher.h"
|
||||||
|
#include "MCPUtils.h"
|
||||||
|
#include "Materials/MaterialInstanceConstant.h"
|
||||||
|
#include "MaterialTypes.h"
|
||||||
|
#include "MaterialInstance_ClearParameter.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UMCP_MaterialInstance_ClearParameter : public UObject, public IMCPHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Material Instance path"))
|
||||||
|
FString Path;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Parameter name to clear"))
|
||||||
|
FString Parameter;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Parameter association: 'Global', 'Layer', or 'Blend'. Default: 'Global'", Optional))
|
||||||
|
FString ParameterAssociation = TEXT("Global");
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Layer/blend index (0-based). Only used when ParameterAssociation is 'Layer' or 'Blend'", Optional))
|
||||||
|
int32 ParameterLayer = INDEX_NONE;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Remove a parameter override from a Material Instance, reverting it to the parent material's value.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
|
||||||
|
{
|
||||||
|
MCPFetcher F(Result);
|
||||||
|
UMaterialInstanceConstant* MI = F.Asset(Path).Cast<UMaterialInstanceConstant>();
|
||||||
|
if (!MI) return;
|
||||||
|
|
||||||
|
// Parse the association string.
|
||||||
|
EMaterialParameterAssociation Association;
|
||||||
|
if (!MCPUtils::ParseMaterialParameterAssociation(ParameterAssociation, Association, Result))
|
||||||
|
return;
|
||||||
|
|
||||||
|
FMaterialParameterInfo ParamID(*Parameter, Association, ParameterLayer);
|
||||||
|
|
||||||
|
// Remove the override from all parameter arrays.
|
||||||
|
auto RemoveFrom = [&](auto& Arr) {
|
||||||
|
return Arr.RemoveAll([&](auto& Entry) { return Entry.ParameterInfo == ParamID; });
|
||||||
|
};
|
||||||
|
|
||||||
|
F.PreEdit();
|
||||||
|
int32 Removed = 0;
|
||||||
|
Removed += RemoveFrom(MI->ScalarParameterValues);
|
||||||
|
Removed += RemoveFrom(MI->VectorParameterValues);
|
||||||
|
Removed += RemoveFrom(MI->DoubleVectorParameterValues);
|
||||||
|
Removed += RemoveFrom(MI->TextureParameterValues);
|
||||||
|
Removed += RemoveFrom(MI->TextureCollectionParameterValues);
|
||||||
|
Removed += RemoveFrom(MI->RuntimeVirtualTextureParameterValues);
|
||||||
|
Removed += RemoveFrom(MI->SparseVolumeTextureParameterValues);
|
||||||
|
Removed += RemoveFrom(MI->FontParameterValues);
|
||||||
|
F.PostEdit();
|
||||||
|
|
||||||
|
if (Removed == 0)
|
||||||
|
{
|
||||||
|
Result.Appendf(TEXT("No override found for parameter '%s' (association=%s layer=%d) on %s"),
|
||||||
|
*Parameter, *ParameterAssociation, ParameterLayer, *MCPUtils::FormatName(MI));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MCPUtils::SaveGenericPackage(MI);
|
||||||
|
Result.Appendf(TEXT("Cleared override for '%s' on %s\n"),
|
||||||
|
*Parameter, *MCPUtils::FormatName(MI));
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -2,16 +2,10 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "MCPHandler.h"
|
#include "MCPHandler.h"
|
||||||
#include "MCPAssetFinder.h"
|
#include "MCPFetcher.h"
|
||||||
#include "MCPUtils.h"
|
#include "MCPUtils.h"
|
||||||
#include "Materials/Material.h"
|
|
||||||
#include "Materials/MaterialInterface.h"
|
|
||||||
#include "Materials/MaterialInstanceConstant.h"
|
#include "Materials/MaterialInstanceConstant.h"
|
||||||
#include "Materials/MaterialExpressionScalarParameter.h"
|
#include "MaterialTypes.h"
|
||||||
#include "Materials/MaterialExpressionVectorParameter.h"
|
|
||||||
#include "Materials/MaterialExpressionTextureSampleParameter2D.h"
|
|
||||||
#include "Materials/MaterialExpressionStaticSwitchParameter.h"
|
|
||||||
#include "Engine/Texture.h"
|
|
||||||
#include "MaterialInstance_DumpParameters.generated.h"
|
#include "MaterialInstance_DumpParameters.generated.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -25,144 +19,38 @@ class UMCP_MaterialInstance_DumpParameters : public UObject, public IMCPHandler
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UPROPERTY(meta=(Description="Material Instance name or path to inspect"))
|
UPROPERTY(meta=(Description="Material Instance path"))
|
||||||
FString MaterialInstance;
|
FString Path;
|
||||||
|
|
||||||
virtual FString GetDescription() const override
|
virtual FString GetDescription() const override
|
||||||
{
|
{
|
||||||
return TEXT("List all parameters on a Material Instance, including overridden and inherited parameters.");
|
return TEXT("List all parameters on a Material Instance, showing current values and which are overridden.");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
|
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
|
||||||
{
|
{
|
||||||
MCPAssets<UMaterialInstanceConstant> Assets;
|
MCPFetcher F(Result);
|
||||||
if (!Assets.Exact(MaterialInstance).Errors(Result).ENone().ETwo().Load()) return;
|
UMaterialInstanceConstant* MI = F.Asset(Path).Cast<UMaterialInstanceConstant>();
|
||||||
UMaterialInstanceConstant* MI = Assets.Object();
|
if (!MI) return;
|
||||||
|
|
||||||
Result.Appendf(TEXT("MaterialInstance: %s\n"), *MCPUtils::FormatName(MI));
|
auto AllParams = MCPUtils::GetMaterialParameters(MI);
|
||||||
|
|
||||||
// Parent chain
|
// Overridden parameters first.
|
||||||
if (MI->Parent)
|
|
||||||
{
|
|
||||||
Result.Append(TEXT("Parent chain:"));
|
|
||||||
UMaterialInterface* Current = MI->Parent;
|
|
||||||
while (Current)
|
|
||||||
{
|
|
||||||
if (UMaterial* Mat = Cast<UMaterial>(Current))
|
|
||||||
{
|
|
||||||
Result.Appendf(TEXT(" %s"), *MCPUtils::FormatName(Mat));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (UMaterialInstance* ParentMI = Cast<UMaterialInstance>(Current))
|
|
||||||
{
|
|
||||||
Result.Appendf(TEXT(" %s ->"), *MCPUtils::FormatName(ParentMI));
|
|
||||||
UMaterialInstanceConstant* ParentMIC = Cast<UMaterialInstanceConstant>(Current);
|
|
||||||
Current = ParentMIC ? ParentMIC->Parent : nullptr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Result.Appendf(TEXT(" %s"), *Current->GetPathName());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Result.Append(TEXT("\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect names of overridden parameters for filtering inherited ones
|
|
||||||
TSet<FString> OverriddenScalars, OverriddenVectors, OverriddenTextures, OverriddenStaticSwitches;
|
|
||||||
for (const FScalarParameterValue& P : MI->ScalarParameterValues)
|
|
||||||
OverriddenScalars.Add(P.ParameterInfo.Name.ToString());
|
|
||||||
for (const FVectorParameterValue& P : MI->VectorParameterValues)
|
|
||||||
OverriddenVectors.Add(P.ParameterInfo.Name.ToString());
|
|
||||||
for (const FTextureParameterValue& P : MI->TextureParameterValues)
|
|
||||||
OverriddenTextures.Add(P.ParameterInfo.Name.ToString());
|
|
||||||
{
|
|
||||||
FStaticParameterSet SP;
|
|
||||||
MI->GetStaticParameterValues(SP);
|
|
||||||
for (const FStaticSwitchParameter& P : SP.StaticSwitchParameters)
|
|
||||||
if (P.bOverride)
|
|
||||||
OverriddenStaticSwitches.Add(P.ParameterInfo.Name.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overridden parameters
|
|
||||||
bool bHasOverrides = false;
|
bool bHasOverrides = false;
|
||||||
auto EnsureOverrideHeader = [&]() {
|
for (auto& [Info, Meta] : AllParams)
|
||||||
|
{
|
||||||
|
if (!Meta.bOverride) continue;
|
||||||
if (!bHasOverrides) { Result.Append(TEXT("\nOverridden Parameters:\n")); bHasOverrides = true; }
|
if (!bHasOverrides) { Result.Append(TEXT("\nOverridden Parameters:\n")); bHasOverrides = true; }
|
||||||
};
|
MCPUtils::FormatMaterialParameter(Result, Info, Meta);
|
||||||
|
|
||||||
for (const FScalarParameterValue& P : MI->ScalarParameterValues)
|
|
||||||
{
|
|
||||||
EnsureOverrideHeader();
|
|
||||||
Result.Appendf(TEXT(" Scalar \"%s\" = %g\n"), *P.ParameterInfo.Name.ToString(), P.ParameterValue);
|
|
||||||
}
|
|
||||||
for (const FVectorParameterValue& P : MI->VectorParameterValues)
|
|
||||||
{
|
|
||||||
EnsureOverrideHeader();
|
|
||||||
Result.Appendf(TEXT(" Vector \"%s\" = (%.3f, %.3f, %.3f, %.3f)\n"),
|
|
||||||
*P.ParameterInfo.Name.ToString(),
|
|
||||||
P.ParameterValue.R, P.ParameterValue.G, P.ParameterValue.B, P.ParameterValue.A);
|
|
||||||
}
|
|
||||||
for (const FTextureParameterValue& P : MI->TextureParameterValues)
|
|
||||||
{
|
|
||||||
EnsureOverrideHeader();
|
|
||||||
Result.Appendf(TEXT(" Texture \"%s\" = %s\n"),
|
|
||||||
*P.ParameterInfo.Name.ToString(),
|
|
||||||
P.ParameterValue ? *MCPUtils::FormatName(P.ParameterValue) : TEXT("None"));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FStaticParameterSet StaticParams;
|
|
||||||
MI->GetStaticParameterValues(StaticParams);
|
|
||||||
for (const FStaticSwitchParameter& P : StaticParams.StaticSwitchParameters)
|
|
||||||
{
|
|
||||||
if (!P.bOverride) continue;
|
|
||||||
EnsureOverrideHeader();
|
|
||||||
Result.Appendf(TEXT(" StaticSwitch \"%s\" = %s\n"),
|
|
||||||
*P.ParameterInfo.Name.ToString(), P.Value ? TEXT("true") : TEXT("false"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inherited (non-overridden) parameters from the base material
|
// Inherited (non-overridden) parameters.
|
||||||
UMaterial* BaseMat = MI->GetMaterial();
|
|
||||||
if (!BaseMat) return;
|
|
||||||
|
|
||||||
bool bHasInherited = false;
|
bool bHasInherited = false;
|
||||||
auto EnsureInheritedHeader = [&]() {
|
for (auto& [Info, Meta] : AllParams)
|
||||||
|
{
|
||||||
|
if (Meta.bOverride) continue;
|
||||||
if (!bHasInherited) { Result.Append(TEXT("\nInherited Parameters (not overridden):\n")); bHasInherited = true; }
|
if (!bHasInherited) { Result.Append(TEXT("\nInherited Parameters (not overridden):\n")); bHasInherited = true; }
|
||||||
};
|
MCPUtils::FormatMaterialParameter(Result, Info, Meta);
|
||||||
|
|
||||||
for (UMaterialExpression* Expr : BaseMat->GetExpressions())
|
|
||||||
{
|
|
||||||
if (!Expr) continue;
|
|
||||||
|
|
||||||
if (auto* SP = Cast<UMaterialExpressionScalarParameter>(Expr))
|
|
||||||
{
|
|
||||||
if (OverriddenScalars.Contains(SP->ParameterName.ToString())) continue;
|
|
||||||
EnsureInheritedHeader();
|
|
||||||
Result.Appendf(TEXT(" Scalar \"%s\" default=%g\n"), *SP->ParameterName.ToString(), SP->DefaultValue);
|
|
||||||
}
|
|
||||||
else if (auto* VP = Cast<UMaterialExpressionVectorParameter>(Expr))
|
|
||||||
{
|
|
||||||
if (OverriddenVectors.Contains(VP->ParameterName.ToString())) continue;
|
|
||||||
EnsureInheritedHeader();
|
|
||||||
Result.Appendf(TEXT(" Vector \"%s\" default=(%.3f, %.3f, %.3f, %.3f)\n"),
|
|
||||||
*VP->ParameterName.ToString(),
|
|
||||||
VP->DefaultValue.R, VP->DefaultValue.G, VP->DefaultValue.B, VP->DefaultValue.A);
|
|
||||||
}
|
|
||||||
else if (auto* TP = Cast<UMaterialExpressionTextureSampleParameter2D>(Expr))
|
|
||||||
{
|
|
||||||
if (OverriddenTextures.Contains(TP->ParameterName.ToString())) continue;
|
|
||||||
EnsureInheritedHeader();
|
|
||||||
Result.Appendf(TEXT(" Texture \"%s\" default=%s\n"),
|
|
||||||
*TP->ParameterName.ToString(),
|
|
||||||
TP->Texture ? *MCPUtils::FormatName(TP->Texture) : TEXT("None"));
|
|
||||||
}
|
|
||||||
else if (auto* SSP = Cast<UMaterialExpressionStaticSwitchParameter>(Expr))
|
|
||||||
{
|
|
||||||
if (OverriddenStaticSwitches.Contains(SSP->ParameterName.ToString())) continue;
|
|
||||||
EnsureInheritedHeader();
|
|
||||||
Result.Appendf(TEXT(" StaticSwitch \"%s\" default=%s\n"),
|
|
||||||
*SSP->ParameterName.ToString(), SSP->DefaultValue ? TEXT("true") : TEXT("false"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "MCPFetcher.h"
|
#include "MCPFetcher.h"
|
||||||
#include "MCPUtils.h"
|
#include "MCPUtils.h"
|
||||||
#include "Materials/MaterialInstanceConstant.h"
|
#include "Materials/MaterialInstanceConstant.h"
|
||||||
|
#include "MaterialTypes.h"
|
||||||
#include "Misc/DefaultValueHelper.h"
|
#include "Misc/DefaultValueHelper.h"
|
||||||
#include "MaterialInstance_SetParameter.generated.h"
|
#include "MaterialInstance_SetParameter.generated.h"
|
||||||
|
|
||||||
@@ -25,6 +26,12 @@ public:
|
|||||||
UPROPERTY(meta=(Description="Parameter name to set"))
|
UPROPERTY(meta=(Description="Parameter name to set"))
|
||||||
FString Parameter;
|
FString Parameter;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Parameter association: 'Global', 'Layer', or 'Blend'. Default: 'Global'", Optional))
|
||||||
|
FString ParameterAssociation = TEXT("Global");
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Layer/blend index (0-based). Only used when ParameterAssociation is 'Layer' or 'Blend'", Optional))
|
||||||
|
int32 ParameterLayer = INDEX_NONE;
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Value to set (uses Unreal text format, e.g. '0.5' for scalar, '(R=1,G=0,B=0,A=1)' for vector)"))
|
UPROPERTY(meta=(Description="Value to set (uses Unreal text format, e.g. '0.5' for scalar, '(R=1,G=0,B=0,A=1)' for vector)"))
|
||||||
FString Value;
|
FString Value;
|
||||||
|
|
||||||
@@ -39,38 +46,30 @@ public:
|
|||||||
UMaterialInstanceConstant* MI = F.Asset(Path).Cast<UMaterialInstanceConstant>();
|
UMaterialInstanceConstant* MI = F.Asset(Path).Cast<UMaterialInstanceConstant>();
|
||||||
if (!MI) return;
|
if (!MI) return;
|
||||||
|
|
||||||
auto Parameters = MCPUtils::MaterialParameters(MI);
|
// Parse the association string.
|
||||||
|
EMaterialParameterAssociation Association;
|
||||||
|
if (!MCPUtils::ParseMaterialParameterAssociation(ParameterAssociation, Association, Result))
|
||||||
|
return;
|
||||||
|
|
||||||
// Find a parameter with a matching name.
|
// Build the parameter ID to look up.
|
||||||
FName Name(*Parameter);
|
FMaterialParameterInfo ParamID(*Parameter, Association, ParameterLayer);
|
||||||
MCPMaterialParameter* Found = nullptr;
|
|
||||||
int MatchCount = 0;
|
// Find it in the material's parameter map.
|
||||||
for (auto& P : Parameters)
|
auto AllParams = MCPUtils::GetMaterialParameters(MI);
|
||||||
|
FMaterialParameterMetadata* Found = AllParams.Find(ParamID);
|
||||||
|
if (!Found)
|
||||||
{
|
{
|
||||||
if (P.Name == Name)
|
Result.Appendf(TEXT("No parameter named '%s' with association=%s layer=%d"),
|
||||||
{
|
*Parameter, *ParameterAssociation, ParameterLayer);
|
||||||
MatchCount++;
|
|
||||||
Found = &P;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (MatchCount > 1)
|
|
||||||
{
|
|
||||||
Result.Appendf(TEXT("More than one parameter named '%s'"), *Parameter);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (MatchCount == 0)
|
if (Found->PrimitiveDataIndex != INDEX_NONE)
|
||||||
{
|
|
||||||
Result.Appendf(TEXT("No parameter named '%s'"), *Parameter);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Found->Metadata.PrimitiveDataIndex != INDEX_NONE)
|
|
||||||
{
|
{
|
||||||
Result.Appendf(TEXT("Parameter '%s' uses custom primitive data and cannot be set on a material instance"), *Parameter);
|
Result.Appendf(TEXT("Parameter '%s' uses custom primitive data and cannot be set on a material instance"), *Parameter);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMaterialParameterInfo Info(*Parameter);
|
EMaterialParameterType Type = Found->Value.Type;
|
||||||
EMaterialParameterType Type = Found->Metadata.Value.Type;
|
|
||||||
|
|
||||||
F.PreEdit();
|
F.PreEdit();
|
||||||
switch (Type)
|
switch (Type)
|
||||||
@@ -83,7 +82,7 @@ public:
|
|||||||
Result.Appendf(TEXT("Failed to parse '%s' as a float"), *Value);
|
Result.Appendf(TEXT("Failed to parse '%s' as a float"), *Value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MI->SetScalarParameterValueEditorOnly(Info, ScalarValue);
|
MI->SetScalarParameterValueEditorOnly(ParamID, ScalarValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EMaterialParameterType::Vector:
|
case EMaterialParameterType::Vector:
|
||||||
@@ -94,11 +93,11 @@ public:
|
|||||||
Result.Appendf(TEXT("Failed to parse '%s' as a color/vector (expected format: '(R=1,G=0,B=0,A=1)')"), *Value);
|
Result.Appendf(TEXT("Failed to parse '%s' as a color/vector (expected format: '(R=1,G=0,B=0,A=1)')"), *Value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MI->SetVectorParameterValueEditorOnly(Info, Color);
|
MI->SetVectorParameterValueEditorOnly(ParamID, Color);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
Result.Appendf(TEXT("Unsupported parameter type for '%s'"), *Parameter);
|
Result.Appendf(TEXT("Parameters of type %d (see EMaterialParameterType) are not implemented"), (int)Type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
F.PostEdit();
|
F.PostEdit();
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "MCPHandler.h"
|
||||||
|
#include "MCPFetcher.h"
|
||||||
|
#include "MCPUtils.h"
|
||||||
|
#include "Materials/Material.h"
|
||||||
|
#include "MaterialTypes.h"
|
||||||
|
#include "Material_DumpParameters.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UMCP_Material_DumpParameters : public UObject, public IMCPHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Material path"))
|
||||||
|
FString Path;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("List all parameters on a Material, showing their default values.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
|
||||||
|
{
|
||||||
|
MCPFetcher F(Result);
|
||||||
|
UMaterial* Mat = F.Asset(Path).Cast<UMaterial>();
|
||||||
|
if (!Mat) return;
|
||||||
|
|
||||||
|
auto AllParams = MCPUtils::GetMaterialParameters(Mat);
|
||||||
|
|
||||||
|
for (auto& [Info, Meta] : AllParams)
|
||||||
|
{
|
||||||
|
MCPUtils::FormatMaterialParameter(Result, Info, Meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
|
||||||
#include "MCPHandler.h"
|
|
||||||
#include "MCPAssetFinder.h"
|
|
||||||
#include "MCPUtils.h"
|
|
||||||
#include "Materials/Material.h"
|
|
||||||
#include "Materials/MaterialInterface.h"
|
|
||||||
#include "Materials/MaterialInstanceConstant.h"
|
|
||||||
#include "Materials/MaterialExpressionScalarParameter.h"
|
|
||||||
#include "Materials/MaterialExpressionVectorParameter.h"
|
|
||||||
#include "Materials/MaterialExpressionTextureSampleParameter2D.h"
|
|
||||||
#include "Materials/MaterialExpressionStaticSwitchParameter.h"
|
|
||||||
#include "Engine/Texture.h"
|
|
||||||
#include "Material_SetInstanceParameter.generated.h"
|
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
UCLASS()
|
|
||||||
class UMCP_Material_SetInstanceParameter : public UObject, public IMCPHandler
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
UPROPERTY(meta=(Description="Material Instance name or path"))
|
|
||||||
FString MaterialInstance;
|
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Parameter name to set"))
|
|
||||||
FString ParameterName;
|
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Value to set (number for scalar, object with r/g/b/a for vector, string path for texture, bool for staticSwitch)"))
|
|
||||||
FMCPJsonObject Value;
|
|
||||||
|
|
||||||
UPROPERTY(meta=(Optional, Description="Parameter type: scalar, vector, texture, staticSwitch. Auto-detected from parent if omitted."))
|
|
||||||
FString Type;
|
|
||||||
|
|
||||||
UPROPERTY(meta=(Optional, Description="If true, validate without applying changes"))
|
|
||||||
bool DryRun = false;
|
|
||||||
|
|
||||||
virtual FString GetDescription() const override
|
|
||||||
{
|
|
||||||
return TEXT("Set a parameter override on a Material Instance. "
|
|
||||||
"Supports scalar, vector, texture, and static switch parameter types.");
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
|
|
||||||
{
|
|
||||||
if (!Json->HasField(TEXT("value")))
|
|
||||||
{
|
|
||||||
Result.Append(TEXT("ERROR: Missing required field: value\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the Material Instance
|
|
||||||
MCPAssets<UMaterialInstanceConstant> Assets;
|
|
||||||
if (!Assets.Exact(MaterialInstance).Errors(Result).ENone().ETwo().Load()) return;
|
|
||||||
UMaterialInstanceConstant* MI = Assets.Object();
|
|
||||||
|
|
||||||
// Determine the parameter type -- explicit or auto-detect from parent
|
|
||||||
FString TypeStr = Type;
|
|
||||||
if (TypeStr.IsEmpty())
|
|
||||||
TypeStr = AutoDetectType(MI);
|
|
||||||
|
|
||||||
if (TypeStr.IsEmpty())
|
|
||||||
{
|
|
||||||
Result.Appendf(TEXT("ERROR: Could not determine parameter type for '%s'. Specify the 'type' field explicitly (scalar, vector, texture, staticSwitch).\n"),
|
|
||||||
*ParameterName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FMaterialParameterInfo ParamInfo(*ParameterName);
|
|
||||||
FString NewValueDescription;
|
|
||||||
|
|
||||||
if (TypeStr.Equals(TEXT("scalar"), ESearchCase::IgnoreCase))
|
|
||||||
{
|
|
||||||
double FloatValue = Json->GetNumberField(TEXT("value"));
|
|
||||||
if (!DryRun)
|
|
||||||
MI->SetScalarParameterValueEditorOnly(ParamInfo, (float)FloatValue);
|
|
||||||
NewValueDescription = FString::Printf(TEXT("%g"), FloatValue);
|
|
||||||
}
|
|
||||||
else if (TypeStr.Equals(TEXT("vector"), ESearchCase::IgnoreCase))
|
|
||||||
{
|
|
||||||
const TSharedPtr<FJsonObject>* ValueObj = nullptr;
|
|
||||||
if (!Json->TryGetObjectField(TEXT("value"), ValueObj) || !ValueObj || !(*ValueObj).IsValid())
|
|
||||||
{
|
|
||||||
Result.Append(TEXT("ERROR: For vector parameters, 'value' must be an object with r, g, b (and optional a) fields.\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double R = (*ValueObj)->GetNumberField(TEXT("r"));
|
|
||||||
double G = (*ValueObj)->GetNumberField(TEXT("g"));
|
|
||||||
double B = (*ValueObj)->GetNumberField(TEXT("b"));
|
|
||||||
double A = (*ValueObj)->HasField(TEXT("a")) ? (*ValueObj)->GetNumberField(TEXT("a")) : 1.0;
|
|
||||||
FLinearColor Color((float)R, (float)G, (float)B, (float)A);
|
|
||||||
|
|
||||||
if (!DryRun)
|
|
||||||
MI->SetVectorParameterValueEditorOnly(ParamInfo, Color);
|
|
||||||
NewValueDescription = FString::Printf(TEXT("(%.3f, %.3f, %.3f, %.3f)"), R, G, B, A);
|
|
||||||
}
|
|
||||||
else if (TypeStr.Equals(TEXT("texture"), ESearchCase::IgnoreCase))
|
|
||||||
{
|
|
||||||
FString TexturePath = Json->GetStringField(TEXT("value"));
|
|
||||||
if (TexturePath.IsEmpty())
|
|
||||||
{
|
|
||||||
Result.Append(TEXT("ERROR: For texture parameters, 'value' must be a texture asset path string.\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MCPAssets<UTexture> TexAssets;
|
|
||||||
if (!TexAssets.Exact(TexturePath).AllContent().Errors(Result).ENone().ETwo().Load()) return;
|
|
||||||
UTexture* TextureObj = TexAssets.Object();
|
|
||||||
|
|
||||||
if (!DryRun)
|
|
||||||
MI->SetTextureParameterValueEditorOnly(ParamInfo, TextureObj);
|
|
||||||
NewValueDescription = MCPUtils::FormatName(TextureObj);
|
|
||||||
}
|
|
||||||
else if (TypeStr.Equals(TEXT("staticSwitch"), ESearchCase::IgnoreCase))
|
|
||||||
{
|
|
||||||
bool bSwitchValue = Json->GetBoolField(TEXT("value"));
|
|
||||||
|
|
||||||
if (!DryRun)
|
|
||||||
{
|
|
||||||
FStaticParameterSet StaticParams;
|
|
||||||
MI->GetStaticParameterValues(StaticParams);
|
|
||||||
|
|
||||||
bool bFound = false;
|
|
||||||
for (FStaticSwitchParameter& Param : StaticParams.StaticSwitchParameters)
|
|
||||||
{
|
|
||||||
if (Param.ParameterInfo.Name == FName(*ParameterName))
|
|
||||||
{
|
|
||||||
Param.Value = bSwitchValue;
|
|
||||||
Param.bOverride = true;
|
|
||||||
bFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bFound)
|
|
||||||
{
|
|
||||||
FStaticSwitchParameter NewParam;
|
|
||||||
NewParam.ParameterInfo.Name = FName(*ParameterName);
|
|
||||||
NewParam.Value = bSwitchValue;
|
|
||||||
NewParam.bOverride = true;
|
|
||||||
StaticParams.StaticSwitchParameters.Add(NewParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
MI->UpdateStaticPermutation(StaticParams);
|
|
||||||
}
|
|
||||||
NewValueDescription = bSwitchValue ? TEXT("true") : TEXT("false");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Result.Appendf(TEXT("ERROR: Unknown parameter type '%s'. Valid types: scalar, vector, texture, staticSwitch\n"), *TypeStr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DryRun)
|
|
||||||
{
|
|
||||||
MCPUtils::PreEdit({MI});
|
|
||||||
MCPUtils::PostEdit({MI});
|
|
||||||
MCPUtils::SaveGenericPackage(MI);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DryRun)
|
|
||||||
Result.Appendf(TEXT("[DRY RUN] Would set %s \"%s\" = %s on %s\n"), *TypeStr, *ParameterName, *NewValueDescription, *MCPUtils::FormatName(MI));
|
|
||||||
else
|
|
||||||
Result.Appendf(TEXT("Set %s \"%s\" = %s on %s\n"), *TypeStr, *ParameterName, *NewValueDescription, *MCPUtils::FormatName(MI));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Auto-detect parameter type by examining the base material's expressions.
|
|
||||||
FString AutoDetectType(UMaterialInstanceConstant* MI)
|
|
||||||
{
|
|
||||||
UMaterial* BaseMat = MI->GetMaterial();
|
|
||||||
if (!BaseMat) return FString();
|
|
||||||
|
|
||||||
for (UMaterialExpression* Expr : BaseMat->GetExpressions())
|
|
||||||
{
|
|
||||||
if (!Expr) continue;
|
|
||||||
if (auto* SP = Cast<UMaterialExpressionScalarParameter>(Expr))
|
|
||||||
{
|
|
||||||
if (SP->ParameterName.ToString() == ParameterName)
|
|
||||||
return TEXT("scalar");
|
|
||||||
}
|
|
||||||
else if (auto* VP = Cast<UMaterialExpressionVectorParameter>(Expr))
|
|
||||||
{
|
|
||||||
if (VP->ParameterName.ToString() == ParameterName)
|
|
||||||
return TEXT("vector");
|
|
||||||
}
|
|
||||||
else if (auto* TP = Cast<UMaterialExpressionTextureSampleParameter2D>(Expr))
|
|
||||||
{
|
|
||||||
if (TP->ParameterName.ToString() == ParameterName)
|
|
||||||
return TEXT("texture");
|
|
||||||
}
|
|
||||||
else if (auto* SSP = Cast<UMaterialExpressionStaticSwitchParameter>(Expr))
|
|
||||||
{
|
|
||||||
if (SSP->ParameterName.ToString() == ParameterName)
|
|
||||||
return TEXT("staticSwitch");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return FString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1150,21 +1150,79 @@ void MCPUtils::PostEdit(const TArray<UObject*>& Objects)
|
|||||||
GEditor->RedrawAllViewports();
|
GEditor->RedrawAllViewports();
|
||||||
}
|
}
|
||||||
|
|
||||||
TArray<MCPMaterialParameter> MCPUtils::MaterialParameters(UMaterialInstanceConstant *MI)
|
|
||||||
|
TMap<FMaterialParameterInfo, FMaterialParameterMetadata> MCPUtils::GetMaterialParameters(UMaterialInterface* Material)
|
||||||
{
|
{
|
||||||
TArray<MCPMaterialParameter> Results;
|
TMap<FMaterialParameterInfo, FMaterialParameterMetadata> Result;
|
||||||
UMaterial* BaseMat = MI->GetMaterial();
|
if (!Material) return Result;
|
||||||
if (!BaseMat) return Results;
|
TMap<FMaterialParameterInfo, FMaterialParameterMetadata> Temp;
|
||||||
for (UMaterialExpression* Expr : BaseMat->GetExpressions())
|
for (int32 i = 0; i < (int32)EMaterialParameterType::NumRuntime; i++)
|
||||||
{
|
{
|
||||||
if (!Expr || !Expr->bIsParameterExpression) continue;
|
Material->GetAllParametersOfType((EMaterialParameterType)i, Temp);
|
||||||
MCPMaterialParameter P;
|
Result.Append(Temp);
|
||||||
P.Name = Expr->GetParameterName();
|
}
|
||||||
if (P.Name.IsNone()) continue;
|
return Result;
|
||||||
if (!Expr->GetParameterValue(P.Metadata)) continue;
|
}
|
||||||
Results.Add(P);
|
|
||||||
|
bool MCPUtils::ParseMaterialParameterAssociation(const FString& Str, EMaterialParameterAssociation& OutAssociation, MCPErrorCallback Error)
|
||||||
|
{
|
||||||
|
if (Str.Equals(TEXT("Global"), ESearchCase::IgnoreCase))
|
||||||
|
OutAssociation = GlobalParameter;
|
||||||
|
else if (Str.Equals(TEXT("Layer"), ESearchCase::IgnoreCase))
|
||||||
|
OutAssociation = LayerParameter;
|
||||||
|
else if (Str.Equals(TEXT("Blend"), ESearchCase::IgnoreCase))
|
||||||
|
OutAssociation = BlendParameter;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error.SetError(FString::Printf(TEXT("Invalid ParameterAssociation '%s' (expected 'Global', 'Layer', or 'Blend')"), *Str));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCPUtils::FormatMaterialParameter(FStringBuilderBase& Result, const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta)
|
||||||
|
{
|
||||||
|
// Association prefix for layer/blend parameters.
|
||||||
|
FString Prefix;
|
||||||
|
if (Info.Association == LayerParameter)
|
||||||
|
Prefix = FString::Printf(TEXT("[Layer %d] "), Info.Index);
|
||||||
|
else if (Info.Association == BlendParameter)
|
||||||
|
Prefix = FString::Printf(TEXT("[Blend %d] "), Info.Index);
|
||||||
|
|
||||||
|
switch (Meta.Value.Type)
|
||||||
|
{
|
||||||
|
case EMaterialParameterType::Scalar:
|
||||||
|
Result.Appendf(TEXT(" %sScalar \"%s\" = %g\n"), *Prefix, *Info.Name.ToString(), Meta.Value.AsScalar());
|
||||||
|
break;
|
||||||
|
case EMaterialParameterType::Vector:
|
||||||
|
{
|
||||||
|
FLinearColor C = Meta.Value.AsLinearColor();
|
||||||
|
Result.Appendf(TEXT(" %sVector \"%s\" = (R=%.3f, G=%.3f, B=%.3f, A=%.3f)\n"),
|
||||||
|
*Prefix, *Info.Name.ToString(), C.R, C.G, C.B, C.A);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EMaterialParameterType::DoubleVector:
|
||||||
|
{
|
||||||
|
FVector4d V = Meta.Value.AsVector4d();
|
||||||
|
Result.Appendf(TEXT(" %sDoubleVector \"%s\" = (%.3f, %.3f, %.3f, %.3f)\n"),
|
||||||
|
*Prefix, *Info.Name.ToString(), V.X, V.Y, V.Z, V.W);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EMaterialParameterType::Texture:
|
||||||
|
{
|
||||||
|
UTexture* Tex = Cast<UTexture>(Meta.Value.AsTextureObject());
|
||||||
|
Result.Appendf(TEXT(" %sTexture \"%s\" = %s\n"),
|
||||||
|
*Prefix, *Info.Name.ToString(), Tex ? *MCPUtils::FormatName(Tex) : TEXT("None"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EMaterialParameterType::StaticSwitch:
|
||||||
|
Result.Appendf(TEXT(" %sStaticSwitch \"%s\" = %s\n"),
|
||||||
|
*Prefix, *Info.Name.ToString(), Meta.Value.AsStaticSwitch() ? TEXT("true") : TEXT("false"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Result.Appendf(TEXT(" %sType%d \"%s\"\n"), *Prefix, (int)Meta.Value.Type, *Info.Name.ToString());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return Results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MCPUtils::SaveMaterialPackage(UMaterial* Material)
|
bool MCPUtils::SaveMaterialPackage(UMaterial* Material)
|
||||||
|
|||||||
@@ -98,12 +98,6 @@ struct MCPErrorCallback
|
|||||||
void SetError(const FString& Msg) const { Func(Msg); }
|
void SetError(const FString& Msg) const { Func(Msg); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MCPMaterialParameter
|
|
||||||
{
|
|
||||||
FName Name;
|
|
||||||
FMaterialParameterMetadata Metadata;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Stateless utility functions used by MCP handlers and the MCP server.
|
// Stateless utility functions used by MCP handlers and the MCP server.
|
||||||
// This is effectively a namespace — all methods are static.
|
// This is effectively a namespace — all methods are static.
|
||||||
class MCPUtils
|
class MCPUtils
|
||||||
@@ -285,8 +279,10 @@ public:
|
|||||||
static void PreEdit(const TArray<UObject*>& Objects);
|
static void PreEdit(const TArray<UObject*>& Objects);
|
||||||
static void PostEdit(const TArray<UObject*>& Objects);
|
static void PostEdit(const TArray<UObject*>& Objects);
|
||||||
|
|
||||||
// ----- Material Instance -----
|
// ----- Material Parameters -----
|
||||||
static TArray<MCPMaterialParameter> MaterialParameters(UMaterialInstanceConstant *MI);
|
static TMap<FMaterialParameterInfo, FMaterialParameterMetadata> GetMaterialParameters(UMaterialInterface* Material);
|
||||||
|
static bool ParseMaterialParameterAssociation(const FString& Str, EMaterialParameterAssociation& OutAssociation, MCPErrorCallback Error = nullptr);
|
||||||
|
static void FormatMaterialParameter(FStringBuilderBase& Result, const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta);
|
||||||
|
|
||||||
// ----- Editable template -----
|
// ----- Editable template -----
|
||||||
// Given an object, returns the appropriate template object for generic
|
// Given an object, returns the appropriate template object for generic
|
||||||
|
|||||||
Reference in New Issue
Block a user