#[[Tip] Auto fading without requiring changing static meshes to BP_FadeActor objects

12 messages · Page 1 of 1 (latest)

spiral wraith
#

Replacing all the static meshes in the world with fade actor versions is a lot of work in big projects. So I wrote a simple class that automatically converts static mesh materials in the world on the fly. This also temporarily works for simple objects that contain meshes - such as the previous fade actor. Note that I use the fade material function outlined in my previous post to just fade around the camera: https://discord.com/channels/807733033192390676/1241167258122846228. So for this implementation, we don't need to convert materials to Material instances.

There are some objects that will still need custom fade interface support, but that's a project for later.

Discord

Discord is great for playing games and chilling with friends, or even building a worldwide community. Customize your own space to talk, play, and hang out.

#

I opted to create a simple data asset that maps material names to materials that have the fade functionality. Be sure to configure this in blueprints and set it in the UFadeCollisionComponent in BP_AuraCharacter.

All of my code is contained within UFadeCollisionComponent which replaces the BoxComponent that is placed along the camera boom. With this change you can remove the old fade code in Aura Character.

Here is the header file:

#
#pragma once

#include "CoreMinimal.h"
#include "Components/BoxComponent.h"
#include "FadeCollisionComponent.generated.h"

UCLASS()
class AURA_API UFadeMaterials : public UDataAsset
{
    GENERATED_BODY()
    
public:
    UMaterialInterface* FindFadeMaterial(FString& MaterialAssetName)
    {
       UMaterialInterface** MaterialPtr = FadeMaterials.Find(MaterialAssetName);
       return MaterialPtr ? *MaterialPtr : nullptr;
    };
    
protected:
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "FadeMaterials")
    TMap<FString, UMaterialInterface*> FadeMaterials;
};

/**
 * 
 */
UCLASS()
class AURA_API UFadeCollisionComponent : public UBoxComponent
{
    GENERATED_BODY()

    UFadeCollisionComponent();
    
public:
    virtual void InitializeComponent() override;

    UFUNCTION()
    virtual void OnBoxBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);

    UFUNCTION()
    virtual void OnBoxEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
    
    // Map material names to versions that support fade around the camera axis
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Fade")
    UFadeMaterials* FadeMaterials;

protected:
    void SwapInFadeMaterials(UStaticMeshComponent* StaticMesh);
    void RestoreOriginalMaterials(UStaticMeshComponent* StaticMesh);
    
    TMap<TObjectPtr<UStaticMeshComponent>, TArray<TObjectPtr<UMaterialInterface>>> MeshToOriginalMaterialsMap;
};
#

And the CPP file:

#

..

#

..

#

Here is a sample of part of my data table:

#

[[Tip] Auto fading without requiring changing static meshes to BP_FadeActor objects

spiral wraith
#

I think that it is perfectly acceptable to externally modify static meshes placed directly in the world. However one could argue that externally modifying the internals of other more complex objects goes too far. That is probably better done with an interface on that object as it might hold state on the various materials. I only did this as a stop gap to work with the old fade actors. Sort of a wonky experiment. Something that I will fix next. Just using the old fade interface in those cases is probably better. I could perhaps provide helper library functions to swap materials for use in those objects, or a fade helper component.

spiral wraith
#

I went back to calling the fade interface if not colliding with a static mesh. Better programming practice.

// If we collided with a static mesh, try to swap in fade materials
if (const AStaticMeshActor* StaticMeshActor = Cast<AStaticMeshActor>(OtherActor))
{
    if (UStaticMeshComponent* StaticMesh = StaticMeshActor->GetStaticMeshComponent())
    {
       SwapInFadeMaterials(StaticMesh);
    }
}

// Collided with some other actor so if it supports the fade interface, call Fade
else if (OtherActor->Implements<UFadeInterface>())
{
    IFadeInterface::Execute_Fade(OtherActor);
}

Now for polish. Plan to create helper for implementing fade in objects like the lighted beacon. Might experiment with easing in the fade. It doesn't look bad without, and simplifies things, but will experiment. But first, I need to complete the GAS course. In last section but I keep getting distracted. 😉

spiral wraith
#

I was concerned about needlessly loading the fade materials at startup. So I switched to use TSoftObjectPtr instead:

class AURA_API UFadeMaterials : public UDataAsset
{
    GENERATED_BODY()
    
public:
    UMaterialInterface* FindFadeMaterial(FString& MaterialAssetName)
    {
       TSoftObjectPtr<UMaterialInterface>* MaterialPtr = FadeMaterials.Find(MaterialAssetName);
       return MaterialPtr ? MaterialPtr->Get() : nullptr;
    };
    
protected:
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "FadeMaterials")
    TMap<FString, TSoftObjectPtr<UMaterialInterface>> FadeMaterials;
};

I "think" this should work, but I don't have deep knowledge in this area. HiveMind - any gotchas I'm missing here? I do use TObjectPtr to store the material while in use.