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:
@@ -28,6 +28,8 @@ APS_BehaviorEditor_AISpline::APS_BehaviorEditor_AISpline()
|
|||||||
SplineMeshComp->SetCollisionResponseToChannel(ECC_Camera, ECR_Block);
|
SplineMeshComp->SetCollisionResponseToChannel(ECC_Camera, ECR_Block);
|
||||||
SplineMeshComp->bUseComplexAsSimpleCollision = true;
|
SplineMeshComp->bUseComplexAsSimpleCollision = true;
|
||||||
SplineMeshComp->SetCastShadow(false);
|
SplineMeshComp->SetCastShadow(false);
|
||||||
|
SplineMeshComp->SetRenderCustomDepth(true);
|
||||||
|
SplineMeshComp->SetCustomDepthStencilValue(2);
|
||||||
|
|
||||||
// Handle parent
|
// Handle parent
|
||||||
HandleRoot = CreateDefaultSubobject<USceneComponent>(TEXT("HandleRoot"));
|
HandleRoot = CreateDefaultSubobject<USceneComponent>(TEXT("HandleRoot"));
|
||||||
@@ -386,6 +388,7 @@ void APS_BehaviorEditor_AISpline::SetSelected(bool bSelected)
|
|||||||
{
|
{
|
||||||
UMaterialInstanceDynamic* Mat = bSelected ? SplineMatSelected : SplineMat;
|
UMaterialInstanceDynamic* Mat = bSelected ? SplineMatSelected : SplineMat;
|
||||||
if (Mat) SplineMeshComp->SetMaterial(0, Mat);
|
if (Mat) SplineMeshComp->SetMaterial(0, Mat);
|
||||||
|
SplineMeshComp->SetCustomDepthStencilValue(bSelected ? 1 : 2);
|
||||||
}
|
}
|
||||||
if (CenterCubeMat)
|
if (CenterCubeMat)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ void APS_Editor_Pawn::BeginPlay()
|
|||||||
OutlinePostProcess->Settings.WeightedBlendables.Array.Add(FWeightedBlendable(1.0f, OutlineMat));
|
OutlinePostProcess->Settings.WeightedBlendables.Array.Add(FWeightedBlendable(1.0f, OutlineMat));
|
||||||
UE_LOG(LogTemp, Log, TEXT("PS_Editor: Selection outline material loaded"));
|
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
|
else
|
||||||
{
|
{
|
||||||
UE_LOG(LogTemp, Warning, TEXT("PS_Editor: Outline material /PS_Editor/M_PS_Editor_SelectionOutline not found. "
|
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/MaterialExpressionComponentMask.h"
|
||||||
#include "Materials/MaterialExpressionAppendVector.h"
|
#include "Materials/MaterialExpressionAppendVector.h"
|
||||||
#include "Materials/MaterialExpressionVectorParameter.h"
|
#include "Materials/MaterialExpressionVectorParameter.h"
|
||||||
|
#include "Materials/MaterialExpressionIf.h"
|
||||||
#include "AssetRegistry/AssetRegistryModule.h"
|
#include "AssetRegistry/AssetRegistryModule.h"
|
||||||
#include "UObject/SavePackage.h"
|
#include "UObject/SavePackage.h"
|
||||||
#include "Misc/PackageName.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)"));
|
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()
|
static void CreateSplineLineMaterialAsset()
|
||||||
{
|
{
|
||||||
const FString MaterialPath = TEXT("/PS_Editor/M_PS_Editor_SplineLine");
|
const FString MaterialPath = TEXT("/PS_Editor/M_PS_Editor_SplineLine");
|
||||||
@@ -270,6 +433,7 @@ void FPS_EditorModule::StartupModule()
|
|||||||
#if WITH_EDITOR
|
#if WITH_EDITOR
|
||||||
FCoreDelegates::OnPostEngineInit.AddStatic(&CreateOutlineMaterialAsset);
|
FCoreDelegates::OnPostEngineInit.AddStatic(&CreateOutlineMaterialAsset);
|
||||||
FCoreDelegates::OnPostEngineInit.AddStatic(&CreateSplineLineMaterialAsset);
|
FCoreDelegates::OnPostEngineInit.AddStatic(&CreateSplineLineMaterialAsset);
|
||||||
|
FCoreDelegates::OnPostEngineInit.AddStatic(&CreateSplineOccludedMaterialAsset);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ APS_Editor_SplineActor::APS_Editor_SplineActor()
|
|||||||
SplineMeshComp->SetCollisionResponseToChannel(ECC_Camera, ECR_Block);
|
SplineMeshComp->SetCollisionResponseToChannel(ECC_Camera, ECR_Block);
|
||||||
SplineMeshComp->bUseComplexAsSimpleCollision = true;
|
SplineMeshComp->bUseComplexAsSimpleCollision = true;
|
||||||
SplineMeshComp->SetCastShadow(false);
|
SplineMeshComp->SetCastShadow(false);
|
||||||
|
SplineMeshComp->SetRenderCustomDepth(true);
|
||||||
|
SplineMeshComp->SetCustomDepthStencilValue(2);
|
||||||
|
|
||||||
// Handle parent
|
// Handle parent
|
||||||
HandleRoot = CreateDefaultSubobject<USceneComponent>(TEXT("HandleRoot"));
|
HandleRoot = CreateDefaultSubobject<USceneComponent>(TEXT("HandleRoot"));
|
||||||
@@ -421,15 +423,12 @@ void APS_Editor_SplineActor::SetSelected(bool bSelected)
|
|||||||
if (SplineMeshComp)
|
if (SplineMeshComp)
|
||||||
{
|
{
|
||||||
UMaterialInstanceDynamic* Mat = bSelected ? SplineMatSelected : SplineMat;
|
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)
|
if (Mat)
|
||||||
{
|
{
|
||||||
SplineMeshComp->SetMaterial(0, 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
|
// Center cube: selected color when selected, normal color otherwise
|
||||||
|
|||||||
Reference in New Issue
Block a user