CustomDepth stencil 2 on spline meshes, SplineNetwork rebuild, PP occluded (disabled)
- Enable RenderCustomDepth + stencil value 2 on spline tube mesh - Restore stencil 2 on deselect (selection sets stencil 1 for outline) - Auto-generated M_PS_Editor_SplineOccluded PP material (stencil + depth compare) - PP occluded effect disabled for now (depth comparison unreliable) - AISpline triggers SplineNetwork::RebuildNetwork on BeginPlay (next tick) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,9 @@ void APS_Editor_Pawn::BeginPlay()
|
||||
OutlinePostProcess->Settings.WeightedBlendables.Array.Add(FWeightedBlendable(1.0f, OutlineMat));
|
||||
UE_LOG(LogTemp, Log, TEXT("PS_Editor: Selection outline material loaded"));
|
||||
}
|
||||
|
||||
// TODO: Spline occluded PP material — disabled for now, depth comparison unreliable
|
||||
// Consider translucent second-pass approach instead of post-process
|
||||
else
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("PS_Editor: Outline material /PS_Editor/M_PS_Editor_SelectionOutline not found. "
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "Materials/MaterialExpressionComponentMask.h"
|
||||
#include "Materials/MaterialExpressionAppendVector.h"
|
||||
#include "Materials/MaterialExpressionVectorParameter.h"
|
||||
#include "Materials/MaterialExpressionIf.h"
|
||||
#include "AssetRegistry/AssetRegistryModule.h"
|
||||
#include "UObject/SavePackage.h"
|
||||
#include "Misc/PackageName.h"
|
||||
@@ -220,6 +221,168 @@ static void CreateOutlineMaterialAsset()
|
||||
UE_LOG(LogTemp, Log, TEXT("PS_Editor: Selection outline material auto-generated (8-sample, dynamic resolution)"));
|
||||
}
|
||||
|
||||
static void CreateSplineOccludedMaterialAsset()
|
||||
{
|
||||
const FString MaterialPath = TEXT("/PS_Editor/M_PS_Editor_SplineOccluded");
|
||||
const FString AssetName = TEXT("M_PS_Editor_SplineOccluded");
|
||||
|
||||
if (LoadObject<UMaterial>(nullptr, *(MaterialPath + TEXT(".") + AssetName)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UPackage* Package = CreatePackage(*MaterialPath);
|
||||
UMaterial* Mat = NewObject<UMaterial>(Package, *AssetName, RF_Public | RF_Standalone);
|
||||
Mat->MaterialDomain = EMaterialDomain::MD_PostProcess;
|
||||
Mat->BlendableLocation = BL_SceneColorAfterDOF;
|
||||
|
||||
auto AddExpr = [&](UMaterialExpression* Expr) { Mat->GetExpressionCollection().AddExpression(Expr); };
|
||||
|
||||
// ---- Scene inputs ----
|
||||
UMaterialExpressionSceneTexture* SceneColor = NewObject<UMaterialExpressionSceneTexture>(Mat);
|
||||
SceneColor->SceneTextureId = PPI_PostProcessInput0;
|
||||
AddExpr(SceneColor);
|
||||
SceneColor->MaterialExpressionEditorX = -400;
|
||||
SceneColor->MaterialExpressionEditorY = 0;
|
||||
|
||||
UMaterialExpressionSceneTexture* CustomStencil = NewObject<UMaterialExpressionSceneTexture>(Mat);
|
||||
CustomStencil->SceneTextureId = PPI_CustomStencil;
|
||||
AddExpr(CustomStencil);
|
||||
CustomStencil->MaterialExpressionEditorX = -400;
|
||||
CustomStencil->MaterialExpressionEditorY = 200;
|
||||
|
||||
UMaterialExpressionSceneTexture* CustomDepthTex = NewObject<UMaterialExpressionSceneTexture>(Mat);
|
||||
CustomDepthTex->SceneTextureId = PPI_CustomDepth;
|
||||
AddExpr(CustomDepthTex);
|
||||
CustomDepthTex->MaterialExpressionEditorX = -400;
|
||||
CustomDepthTex->MaterialExpressionEditorY = 400;
|
||||
|
||||
UMaterialExpressionSceneTexture* SceneDepthTex = NewObject<UMaterialExpressionSceneTexture>(Mat);
|
||||
SceneDepthTex->SceneTextureId = PPI_SceneDepth;
|
||||
AddExpr(SceneDepthTex);
|
||||
SceneDepthTex->MaterialExpressionEditorX = -400;
|
||||
SceneDepthTex->MaterialExpressionEditorY = 600;
|
||||
|
||||
// ---- Stencil == 2 check: abs(stencil - 2) < 0.5 ----
|
||||
UMaterialExpressionConstant* StencilTarget = NewObject<UMaterialExpressionConstant>(Mat);
|
||||
StencilTarget->R = 2.0f;
|
||||
AddExpr(StencilTarget);
|
||||
StencilTarget->MaterialExpressionEditorX = -200;
|
||||
StencilTarget->MaterialExpressionEditorY = 200;
|
||||
|
||||
UMaterialExpressionSubtract* StencilDiff = NewObject<UMaterialExpressionSubtract>(Mat);
|
||||
AddExpr(StencilDiff);
|
||||
StencilDiff->A.Connect(0, CustomStencil);
|
||||
StencilDiff->B.Connect(0, StencilTarget);
|
||||
StencilDiff->MaterialExpressionEditorX = 0;
|
||||
StencilDiff->MaterialExpressionEditorY = 200;
|
||||
|
||||
UMaterialExpressionAbs* StencilAbs = NewObject<UMaterialExpressionAbs>(Mat);
|
||||
AddExpr(StencilAbs);
|
||||
StencilAbs->Input.Connect(0, StencilDiff);
|
||||
StencilAbs->MaterialExpressionEditorX = 200;
|
||||
StencilAbs->MaterialExpressionEditorY = 200;
|
||||
|
||||
// Constants for IF outputs
|
||||
UMaterialExpressionConstant* One = NewObject<UMaterialExpressionConstant>(Mat);
|
||||
One->R = 1.0f;
|
||||
AddExpr(One);
|
||||
One->MaterialExpressionEditorX = 200;
|
||||
One->MaterialExpressionEditorY = 100;
|
||||
|
||||
UMaterialExpressionConstant* Zero = NewObject<UMaterialExpressionConstant>(Mat);
|
||||
Zero->R = 0.0f;
|
||||
AddExpr(Zero);
|
||||
Zero->MaterialExpressionEditorX = 200;
|
||||
Zero->MaterialExpressionEditorY = 350;
|
||||
|
||||
UMaterialExpressionConstant* Half = NewObject<UMaterialExpressionConstant>(Mat);
|
||||
Half->R = 0.5f;
|
||||
AddExpr(Half);
|
||||
Half->MaterialExpressionEditorX = 200;
|
||||
Half->MaterialExpressionEditorY = 250;
|
||||
|
||||
// IF(Half > StencilAbs, 1, 0) → IsSpline
|
||||
UMaterialExpressionIf* IsSpline = NewObject<UMaterialExpressionIf>(Mat);
|
||||
AddExpr(IsSpline);
|
||||
IsSpline->A.Connect(0, Half);
|
||||
IsSpline->B.Connect(0, StencilAbs);
|
||||
IsSpline->AGreaterThanB.Connect(0, One);
|
||||
IsSpline->AEqualsB.Connect(0, Zero);
|
||||
IsSpline->ALessThanB.Connect(0, Zero);
|
||||
IsSpline->MaterialExpressionEditorX = 400;
|
||||
IsSpline->MaterialExpressionEditorY = 200;
|
||||
|
||||
// ---- Depth comparison: CustomDepth > SceneDepth + 1 ----
|
||||
UMaterialExpressionConstant* DepthBias = NewObject<UMaterialExpressionConstant>(Mat);
|
||||
DepthBias->R = 1.0f;
|
||||
AddExpr(DepthBias);
|
||||
DepthBias->MaterialExpressionEditorX = -200;
|
||||
DepthBias->MaterialExpressionEditorY = 600;
|
||||
|
||||
UMaterialExpressionAdd* SceneDepthBiased = NewObject<UMaterialExpressionAdd>(Mat);
|
||||
AddExpr(SceneDepthBiased);
|
||||
SceneDepthBiased->A.Connect(0, SceneDepthTex);
|
||||
SceneDepthBiased->B.Connect(0, DepthBias);
|
||||
SceneDepthBiased->MaterialExpressionEditorX = 0;
|
||||
SceneDepthBiased->MaterialExpressionEditorY = 600;
|
||||
|
||||
// IF(CustomDepth > SceneDepth+1, 1, 0) → IsOccluded
|
||||
UMaterialExpressionIf* IsOccluded = NewObject<UMaterialExpressionIf>(Mat);
|
||||
AddExpr(IsOccluded);
|
||||
IsOccluded->A.Connect(0, CustomDepthTex);
|
||||
IsOccluded->B.Connect(0, SceneDepthBiased);
|
||||
IsOccluded->AGreaterThanB.Connect(0, One);
|
||||
IsOccluded->AEqualsB.Connect(0, Zero);
|
||||
IsOccluded->ALessThanB.Connect(0, Zero);
|
||||
IsOccluded->MaterialExpressionEditorX = 400;
|
||||
IsOccluded->MaterialExpressionEditorY = 500;
|
||||
|
||||
// ---- Final mask = IsSpline * IsOccluded * 0.6 ----
|
||||
UMaterialExpressionMultiply* CombinedMask = NewObject<UMaterialExpressionMultiply>(Mat);
|
||||
AddExpr(CombinedMask);
|
||||
CombinedMask->A.Connect(0, IsSpline);
|
||||
CombinedMask->B.Connect(0, IsOccluded);
|
||||
CombinedMask->MaterialExpressionEditorX = 600;
|
||||
CombinedMask->MaterialExpressionEditorY = 350;
|
||||
|
||||
UMaterialExpressionMultiply* FinalMask = NewObject<UMaterialExpressionMultiply>(Mat);
|
||||
AddExpr(FinalMask);
|
||||
FinalMask->A.Connect(0, CombinedMask);
|
||||
FinalMask->ConstB = 0.6f;
|
||||
FinalMask->MaterialExpressionEditorX = 800;
|
||||
FinalMask->MaterialExpressionEditorY = 350;
|
||||
|
||||
// ---- Gray color ----
|
||||
UMaterialExpressionConstant4Vector* GrayColor = NewObject<UMaterialExpressionConstant4Vector>(Mat);
|
||||
GrayColor->Constant = FLinearColor(0.35f, 0.35f, 0.35f, 1.0f);
|
||||
AddExpr(GrayColor);
|
||||
GrayColor->MaterialExpressionEditorX = 600;
|
||||
GrayColor->MaterialExpressionEditorY = 600;
|
||||
|
||||
// ---- Lerp(SceneColor, GrayColor, FinalMask) ----
|
||||
UMaterialExpressionLinearInterpolate* Lerp = NewObject<UMaterialExpressionLinearInterpolate>(Mat);
|
||||
AddExpr(Lerp);
|
||||
Lerp->A.Connect(0, SceneColor);
|
||||
Lerp->B.Connect(0, GrayColor);
|
||||
Lerp->Alpha.Connect(0, FinalMask);
|
||||
Lerp->MaterialExpressionEditorX = 1000;
|
||||
Lerp->MaterialExpressionEditorY = 200;
|
||||
|
||||
Mat->GetEditorOnlyData()->EmissiveColor.Connect(0, Lerp);
|
||||
|
||||
Mat->PreEditChange(nullptr);
|
||||
Mat->PostEditChange();
|
||||
|
||||
FString PackageFilename = FPackageName::LongPackageNameToFilename(MaterialPath, FPackageName::GetAssetPackageExtension());
|
||||
FSavePackageArgs SaveArgs;
|
||||
SaveArgs.TopLevelFlags = RF_Public | RF_Standalone;
|
||||
UPackage::SavePackage(Package, Mat, *PackageFilename, SaveArgs);
|
||||
FAssetRegistryModule::AssetCreated(Mat);
|
||||
|
||||
UE_LOG(LogTemp, Log, TEXT("PS_Editor: Spline occluded PP material auto-generated (stencil 2, depth compare)"));
|
||||
}
|
||||
|
||||
static void CreateSplineLineMaterialAsset()
|
||||
{
|
||||
const FString MaterialPath = TEXT("/PS_Editor/M_PS_Editor_SplineLine");
|
||||
@@ -270,6 +433,7 @@ void FPS_EditorModule::StartupModule()
|
||||
#if WITH_EDITOR
|
||||
FCoreDelegates::OnPostEngineInit.AddStatic(&CreateOutlineMaterialAsset);
|
||||
FCoreDelegates::OnPostEngineInit.AddStatic(&CreateSplineLineMaterialAsset);
|
||||
FCoreDelegates::OnPostEngineInit.AddStatic(&CreateSplineOccludedMaterialAsset);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ APS_Editor_SplineActor::APS_Editor_SplineActor()
|
||||
SplineMeshComp->SetCollisionResponseToChannel(ECC_Camera, ECR_Block);
|
||||
SplineMeshComp->bUseComplexAsSimpleCollision = true;
|
||||
SplineMeshComp->SetCastShadow(false);
|
||||
SplineMeshComp->SetRenderCustomDepth(true);
|
||||
SplineMeshComp->SetCustomDepthStencilValue(2);
|
||||
|
||||
// Handle parent
|
||||
HandleRoot = CreateDefaultSubobject<USceneComponent>(TEXT("HandleRoot"));
|
||||
@@ -421,15 +423,12 @@ void APS_Editor_SplineActor::SetSelected(bool bSelected)
|
||||
if (SplineMeshComp)
|
||||
{
|
||||
UMaterialInstanceDynamic* Mat = bSelected ? SplineMatSelected : SplineMat;
|
||||
UE_LOG(LogTemp, Log, TEXT("PS_Editor: SetSelected(%s) - SplineMat=%s, SplineMatSelected=%s, Using=%s"),
|
||||
bSelected ? TEXT("true") : TEXT("false"),
|
||||
SplineMat ? TEXT("valid") : TEXT("NULL"),
|
||||
SplineMatSelected ? TEXT("valid") : TEXT("NULL"),
|
||||
Mat ? TEXT("valid") : TEXT("NULL"));
|
||||
if (Mat)
|
||||
{
|
||||
SplineMeshComp->SetMaterial(0, Mat);
|
||||
}
|
||||
// Restore stencil 2 for occluded PP effect when deselected (selection sets it to 1)
|
||||
SplineMeshComp->SetCustomDepthStencilValue(bSelected ? 1 : 2);
|
||||
}
|
||||
|
||||
// Center cube: selected color when selected, normal color otherwise
|
||||
|
||||
Reference in New Issue
Block a user