UE5 Material Parameter Collection
Material Parameter Collection(MPC)은 하나의 에셋에 스칼라·벡터 파라미터를 모아두고, 씬의 모든 머티리얼이 공유해서 읽을 수 있게 해주는 시스템입니다. 전역 날씨 강도, 시간대 색상, 플레이어 위치 기반 효과처럼 “씬 전체에 영향을 주는 파라미터”를 다룰 때 필수적입니다.
MPC의 핵심 강점은 GPU 상수 버퍼에 직접 매핑된다는 점입니다. 값이 바뀌면 모든 참조 머티리얼이 즉시 반영되며, Dynamic Material Instance처럼 인스턴스마다 별도 드로우 콜이 발생하지 않습니다.
1. MPC 에셋 생성 구조
섹션 제목: “1. MPC 에셋 생성 구조”Content Browser → 우클릭 → Materials → Material Parameter CollectionMPC 에셋 내부 구조 예시:
MPC_Weather Scalar Parameters: RainIntensity (0.0 ~ 1.0) FogDensity (0.0 ~ 0.5) TimeOfDay (0.0 = 자정, 0.5 = 정오, 1.0 = 자정) WindStrength (0.0 ~ 3.0)
Vector Parameters: SunColor (RGB + A) AmbientColor (RGB) WindDirection (XYZ = 방향 벡터, W = 미사용)
MPC_Gameplay Scalar Parameters: PlayerHealth (0.0 ~ 1.0) ← 체력바 외 머티리얼 이펙트 연동 DamageFlash (0.0 ~ 1.0) ← 피격 시 화면 붉게 Vector Parameters: PlayerWorldPos (XYZ) ← 플레이어 주변 눈/비 파티클 방향파라미터 한도: MPC 하나당 스칼라 1024개, 벡터 1024개까지 등록 가능합니다.
2. 머티리얼에서 MPC 참조
섹션 제목: “2. 머티리얼에서 MPC 참조”머티리얼 에디터에서 CollectionParameter 노드를 추가하고 MPC 에셋과 파라미터 이름을 선택합니다. 이 값은 런타임에 동적으로 변경됩니다.
[머티리얼 그래프 예: 비에 젖는 효과]CollectionParameter(MPC_Weather, RainIntensity) → Lerp(건조한 Roughness=0.8, 젖은 Roughness=0.1) → Roughness 핀 연결
CollectionParameter(MPC_Weather, RainIntensity) → Lerp(건조한 Normal, 물 흔적 Normal) → Normal 핀 연결HLSL 커스텀 노드에서 직접 접근하는 것은 불가능하지만, CollectionParameter 노드의 출력을 커스텀 노드의 입력으로 연결할 수 있습니다.
3. C++에서 MPC 값 변경
섹션 제목: “3. C++에서 MPC 값 변경”#pragma once#include "CoreMinimal.h"#include "GameFramework/Actor.h"#include "WeatherSystem.generated.h"
class UMaterialParameterCollection;class UMaterialParameterCollectionInstance;
UCLASS()class MYGAME_API AWeatherSystem : public AActor{ GENERATED_BODY()
public: AWeatherSystem();
UPROPERTY(EditAnywhere, Category="Weather") UMaterialParameterCollection* WeatherMPC;
UFUNCTION(BlueprintCallable, Category="Weather") void SetRainIntensity(float Intensity);
UFUNCTION(BlueprintCallable, Category="Weather") void SetTimeOfDay(float NormalizedTime);
UFUNCTION(BlueprintCallable, Category="Weather") void SetWindState(FVector Direction, float Strength);
private: UMaterialParameterCollectionInstance* _mpcInstance;
// 현재 날씨 상태 (부드러운 보간용) float _currentRain = 0.f; float _targetRain = 0.f;};#include "WeatherSystem.h"#include "Materials/MaterialParameterCollection.h"#include "Materials/MaterialParameterCollectionInstance.h"
AWeatherSystem::AWeatherSystem(){ PrimaryActorTick.bCanEverTick = true;}
void AWeatherSystem::BeginPlay(){ Super::BeginPlay(); if (WeatherMPC) { // 월드에 MPC 인스턴스를 가져옴 (없으면 자동 생성) _mpcInstance = GetWorld()->GetParameterCollectionInstance(WeatherMPC); }}
void AWeatherSystem::SetRainIntensity(float Intensity){ _targetRain = FMath::Clamp(Intensity, 0.f, 1.f); // 실제 적용은 Tick에서 부드럽게 보간}
void AWeatherSystem::SetTimeOfDay(float NormalizedTime){ if (!_mpcInstance) return;
float T = FMath::Frac(NormalizedTime); // 0~1 사이로 정규화 _mpcInstance->SetScalarParameterValue(FName("TimeOfDay"), T);
// 시간대에 따른 태양 색상 자동 계산 // 0=자정(어두움), 0.25=일출(붉음), 0.5=정오(밝음), 0.75=일몰(붉음) float DaytimeFactor = FMath::Sin(T * PI); FLinearColor DuskColor(1.f, 0.4f, 0.1f); // 일출/일몰: 붉은 계열 FLinearColor NoonColor(1.f, 0.95f, 0.8f); // 정오: 따뜻한 흰색 FLinearColor NightColor(0.05f, 0.07f, 0.15f); // 자정: 짙은 남색
FLinearColor SunColor; if (T < 0.5f) SunColor = FLinearColor::LerpUsingHSV(DuskColor, NoonColor, DaytimeFactor); else SunColor = FLinearColor::LerpUsingHSV(NoonColor, DuskColor, (T - 0.5f) * 2.f);
_mpcInstance->SetVectorParameterValue(FName("SunColor"), SunColor);
// 앰비언트 색상 (밤에는 달빛 푸른 계열) FLinearColor AmbientColor = FLinearColor::LerpUsingHSV( NightColor, FLinearColor(0.3f, 0.28f, 0.25f), DaytimeFactor); _mpcInstance->SetVectorParameterValue(FName("AmbientColor"), AmbientColor);}
void AWeatherSystem::SetWindState(FVector Direction, float Strength){ if (!_mpcInstance) return;
Direction = Direction.GetSafeNormal(); _mpcInstance->SetVectorParameterValue( FName("WindDirection"), FLinearColor(Direction.X, Direction.Y, Direction.Z, 0.f)); _mpcInstance->SetScalarParameterValue( FName("WindStrength"), FMath::Clamp(Strength, 0.f, 3.f));}
void AWeatherSystem::Tick(float DeltaTime){ Super::Tick(DeltaTime);
if (!_mpcInstance) return;
// 비 강도 부드럽게 보간 (급격한 변화 방지) _currentRain = FMath::FInterpTo(_currentRain, _targetRain, DeltaTime, 1.5f); _mpcInstance->SetScalarParameterValue(FName("RainIntensity"), _currentRain);
// 안개 밀도: 비가 많을수록 안개도 진해짐 float FogDensity = FMath::Lerp(0.f, 0.4f, _currentRain * 0.7f); _mpcInstance->SetScalarParameterValue(FName("FogDensity"), FogDensity);}4. 게임플레이 이펙트 연동
섹션 제목: “4. 게임플레이 이펙트 연동”플레이어 상태와 MPC를 연결해 전신 머티리얼 효과를 구현하는 패턴입니다.
// GameplayMPCComponent.h — 게임플레이 상태를 MPC에 브로드캐스트UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))class UGameplayMPCComponent : public UActorComponent{ GENERATED_BODY()
UPROPERTY(EditAnywhere, Category="MPC") UMaterialParameterCollection* GameplayMPC;
UMaterialParameterCollectionInstance* _inst = nullptr;
// 피격 플래시 타이머 FTimerHandle _flashTimer; float _flashValue = 0.f;
public: virtual void BeginPlay() override { Super::BeginPlay(); if (GameplayMPC) _inst = GetWorld()->GetParameterCollectionInstance(GameplayMPC); }
// 체력 변화 시 호출 (0.0 ~ 1.0) void UpdatePlayerHealth(float NormalizedHealth) { if (!_inst) return; _inst->SetScalarParameterValue(FName("PlayerHealth"), NormalizedHealth);
// 체력 낮을 때 경고 효과 (예: 화면 가장자리 붉게) float DangerLevel = FMath::Clamp(1.f - NormalizedHealth * 2.f, 0.f, 1.f); _inst->SetScalarParameterValue(FName("DangerLevel"), DangerLevel); }
// 피격 시 화면 플래시 void TriggerDamageFlash() { if (!_inst) return; _flashValue = 1.f; _inst->SetScalarParameterValue(FName("DamageFlash"), _flashValue);
// 타이머로 점점 감소 GetWorld()->GetTimerManager().SetTimer( _flashTimer, [this]() { _flashValue = FMath::Max(0.f, _flashValue - 0.1f); if (_inst) _inst->SetScalarParameterValue(FName("DamageFlash"), _flashValue); if (_flashValue <= 0.f) GetWorld()->GetTimerManager().ClearTimer(_flashTimer); }, 0.05f, true); // 50ms 간격으로 감소 }
// 플레이어 월드 위치 업데이트 (파티클/눈 방향 계산용) virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); if (!_inst) return;
FVector PlayerPos = GetOwner()->GetActorLocation(); _inst->SetVectorParameterValue( FName("PlayerWorldPos"), FLinearColor(PlayerPos.X, PlayerPos.Y, PlayerPos.Z, 0.f)); }};5. 디졸브 이펙트 — MPC 활용
섹션 제목: “5. 디졸브 이펙트 — MPC 활용”오브젝트 파괴/소환 시 전역적으로 디졸브 진행도를 제어하는 패턴입니다.
// 디졸브 매니저: 씬의 모든 디졸브 머티리얼을 동기화UCLASS()class ADissolveManager : public AActor{ GENERATED_BODY()
UPROPERTY(EditAnywhere) UMaterialParameterCollection* DissolveMPC;
UMaterialParameterCollectionInstance* _inst = nullptr;
public: void BeginPlay() override { Super::BeginPlay(); if (DissolveMPC) _inst = GetWorld()->GetParameterCollectionInstance(DissolveMPC); }
// 특정 액터를 디졸브 아웃 (0→1로 증가하며 사라짐) void DissolveOut(AActor* Target, float Duration) { // 해당 액터만 개별 DMI 사용 (전역 MPC와 분리) // → 전역 이펙트(보스 처치 시 전체 빛 폭발 등)는 MPC 사용 StartGlobalDissolveEffect(Duration); }
void StartGlobalDissolveEffect(float Duration) { // 타임라인 없이 간단히 Tick 기반 진행 float Elapsed = 0.f; GetWorldTimerManager().SetTimer( FTimerHandle{}, [this, Duration, &Elapsed]() { Elapsed += 0.033f; float Progress = FMath::Clamp(Elapsed / Duration, 0.f, 1.f); if (_inst) _inst->SetScalarParameterValue( FName("GlobalDissolveProgress"), Progress); }, 0.033f, true); }};6. 포스트프로세스와 연동
섹션 제목: “6. 포스트프로세스와 연동”MPC 파라미터를 포스트프로세스 머티리얼에서도 동일하게 참조할 수 있습니다.
[포스트프로세스 머티리얼 노드 예: 비 화면 왜곡]
CollectionParameter(MPC_Weather, RainIntensity) → Multiply(0.02) ← 최대 왜곡 강도 2% → SceneTexture 오프셋 입력
CollectionParameter(MPC_Weather, RainIntensity) → Power(2.0) ← 비가 강할 때만 두드러지게 → Vignette Intensity 입력
CollectionParameter(MPC_Gameplay, DamageFlash) → Lerp(원래 색상, 붉은 색, DamageFlash) → Emissive 출력실제 포스트프로세스 머티리얼을 C++에서 Post Process Volume에 할당:
// 포스트프로세스 머티리얼 런타임 적용void AMyCharacter::ApplyUnderwaterPP(bool bEnable){ // Post Process Volume이 아닌 캐릭터 PPV 컴포넌트에 적용 if (UnderwaterPPComponent) UnderwaterPPComponent->bEnabled = bEnable;
// MPC 값도 함께 변경해 주변 오브젝트 머티리얼도 반응 if (auto* Inst = GetWorld()->GetParameterCollectionInstance(GameplayMPC)) Inst->SetScalarParameterValue(FName("UnderwaterDepth"), bEnable ? 1.f : 0.f);}7. MPC와 Dynamic Material Instance 비교
섹션 제목: “7. MPC와 Dynamic Material Instance 비교”| 항목 | MPC | Dynamic Material Instance |
|---|---|---|
| 적용 범위 | 전역 (참조하는 모든 머티리얼) | 해당 인스턴스만 |
| 성능 비용 | 매우 낮음 (GPU 상수 버퍼) | 인스턴스 수에 비례 |
| 사용 사례 | 날씨, 시간대, 글로벌 이펙트 | 개별 오브젝트 색상·강도 |
| 파라미터 수 | 스칼라 1024 + 벡터 1024 | 머티리얼 파라미터 수만큼 |
| 머티리얼 수정 | 불필요 (공유) | 인스턴스 생성 필요 |
| 멀티플레이어 | 서버/클라이언트 독립 | 동일 |
함께 쓰는 패턴: 전역 날씨는 MPC로 제어하고, 특정 캐릭터의 피격 색 변화는 DMI로 처리합니다. MPC 값을 DMI의 마스크로 활용해 “비가 올 때만 캐릭터가 젖어 보이는” 효과도 구현할 수 있습니다.
MPC는 씬 전역에 영향을 주는 파라미터에 최적화된 도구이며, GPU 상수 버퍼를 활용해 오버헤드가 거의 없습니다. GetWorld()->GetParameterCollectionInstance(MPC)로 인스턴스를 가져와 SetScalarParameterValue / SetVectorParameterValue로 값을 변경하세요. 날씨/시간대처럼 전체 씬에 영향을 주는 효과는 MPC로, 개별 오브젝트의 상태 변화는 Dynamic Material Instance로 분리하는 것이 성능과 유지보수 모두에 유리합니다.