언리얼 나이아가라 대부분의 기능은 노드로 구현이 가능함 지버퍼나 스크린 데이터도
가끔 없는기능이나 불편한 기능이 존재해 노드를 추가할 필요가 있는데 나이아가라는 머터리얼처럼 간단히 추가할 수 가 없음
일정때문에 너무 급히 만들다보니 완전 디테일하게 파악하지 못하고 대충 이런 흐름을 따라 추가할수 있다 정도로만 보시면될듯합니다.
일단 모든 노드는 각자의 데이터인터페이스 클래스를 갖고 있음
플러그인으로 만드는것도 가능하다고 하지만 처음해보는거라
그냥 나이아가라 플러그인 안쪽에 파일을 추가함
Engine\Plugins\FX\Niagara\Source\Niagara\Classes\NiagaraDataInterfaceCheckPlatform.h
Engine\Plugins\FX\Niagara\Source\Niagara\Private\NiagaraDataInterfaceCheckPlatform.cpp
헤더
#pragma once
#include "NiagaraCommon.h"
#include "NiagaraShared.h"
#include "NiagaraPlatformSet.h"
#include "NiagaraDataInterface.h"
#include "NiagaraDataInterfaceCheckPlatform.generated.h"
UCLASS(EditInlineNew, Category="Performance", meta = (DisplayName = "CheckPlatform"))
class UNiagaraDataInterfaceCheckPlatform : public UNiagaraDataInterface
{
GENERATED_BODY()
public:
UNiagaraDataInterfaceCheckPlatform();
//UObject Interface
NIAGARA_API virtual void PostInitProperties() override;
//UObject Interface End
public:
#if WITH_EDITORONLY_DATA
NIAGARA_API virtual void GetFunctionsInternal(TArray<FNiagaraFunctionSignature>& OutFunctions) const override;
#endif
NIAGARA_API virtual void GetVMExternalFunction(const FVMExternalFunctionBindingInfo& BindingInfo,
void* InstanceData,
FVMExternalFunction& OutFunc) override;
NIAGARA_API void ExecIsMobile(FVectorVMExternalFunctionContext& Context);
bool bIsMobile;
protected:
NIAGARA_API virtual bool CopyToInternal(UNiagaraDataInterface* Destination) const override;
//~ UNiagaraDataInterface interface
private:
};
소스
#include "NiagaraDataInterfaceCheckPlatform.h"
#include "NiagaraTypes.h"
//#include "NiagaraFunctionSignature.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(NiagaraDataInterfaceCheckPlatform)
//@pts NiagaraMobileOpt DataInterface
UNiagaraDataInterfaceCheckPlatform::UNiagaraDataInterfaceCheckPlatform()
{
}
void UNiagaraDataInterfaceCheckPlatform::PostInitProperties()
{
Super::PostInitProperties();
if (HasAnyFlags(RF_ClassDefaultObject))
{
ENiagaraTypeRegistryFlags Flags = ENiagaraTypeRegistryFlags::AllowAnyVariable | ENiagaraTypeRegistryFlags::AllowParameter;
FNiagaraTypeRegistry::Register(FNiagaraTypeDefinition(GetClass()), Flags);
}
}
#if WITH_EDITORONLY_DATA
void UNiagaraDataInterfaceCheckPlatform::GetFunctionsInternal(TArray<FNiagaraFunctionSignature>& OutFunctions) const
{
{
FNiagaraFunctionSignature Sig;
Sig.Name = FName("IsMobile");
Sig.bMemberFunction = true;
Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PlatformCheckSet")));
Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("Result")));
OutFunctions.Add(Sig);
}
}
#endif
void UNiagaraDataInterfaceCheckPlatform::GetVMExternalFunction(
const FVMExternalFunctionBindingInfo& BindingInfo,
void* InstanceData,
FVMExternalFunction& OutFunc)
{
if (BindingInfo.Name == FName("IsMobile") && BindingInfo.GetNumInputs() == 0 && BindingInfo.GetNumOutputs() == 1)
{
OutFunc = FVMExternalFunction::CreateUObject(this, &UNiagaraDataInterfaceCheckPlatform::ExecIsMobile);
}
}
bool UNiagaraDataInterfaceCheckPlatform::CopyToInternal(UNiagaraDataInterface* Destination) const
{
if (!Super::CopyToInternal(Destination))
{
return false;
}
UNiagaraDataInterfaceCheckPlatform* DestinationTyped = CastChecked<UNiagaraDataInterfaceCheckPlatform>(Destination);
DestinationTyped->bIsMobile = bIsMobile;
return true;
}
void UNiagaraDataInterfaceCheckPlatform::ExecIsMobile(FVectorVMExternalFunctionContext& Context)
{
VectorVM::FExternalFuncRegisterHandler<FNiagaraBool> OutValue(Context);
//실제 디바이스에서 처리
#if PLATFORM_ANDROID || PLATFORM_IOS
bIsMobile = true;
#else
bIsMobile = false;
#endif
//에디터 프리뷰용 처리
#if WITH_EDITOR
if (UWorld* World = GetWorld())
{
ERHIFeatureLevel::Type FeatureLevel = World->GetFeatureLevel();
bIsMobile = (FeatureLevel <= ERHIFeatureLevel::ES3_1);
}
else
{
// fallback
ERHIFeatureLevel::Type FeatureLevel = GMaxRHIFeatureLevel;
FeatureLevel = GEditor->PreviewPlatform.GetEffectivePreviewFeatureLevel();
if (FeatureLevel)
{
bIsMobile = (FeatureLevel <= ERHIFeatureLevel::ES3_1);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("FeatureLevel is Empty"));
}
}
#endif
for (int32 i = 0; i < Context.GetNumInstances(); ++i)
{
*OutValue.GetDestAndAdvance() = FNiagaraBool(bIsMobile);
}
}
UNiagaraDataInterface 를 상속받아 클래스를 생성하는데
함수 호출을

비긴 디폴트처럼 아예 빈 곳에서 호출하는건 찾지 못해서 어쩔수 없이 위 체크 플랫폼 같은 형식으로 만들게됨
생성자 함수는 무조건 만들어주어야 하는것 같음 - 잘 모름
UNiagaraDataInterfaceCheckPlatform::UNiagaraDataInterfaceCheckPlatform()
{
}
void UNiagaraDataInterfaceCheckPlatform::PostInitProperties()
{
Super::PostInitProperties();
if (HasAnyFlags(RF_ClassDefaultObject))
{
ENiagaraTypeRegistryFlags Flags = ENiagaraTypeRegistryFlags::AllowAnyVariable | ENiagaraTypeRegistryFlags::AllowParameter;
FNiagaraTypeRegistry::Register(FNiagaraTypeDefinition(GetClass()), Flags);
}
}
이 함수는 나이아가라에 프로퍼티로 데이터인터페이스를 등록해줍니다
뭔가 저기서(ENiagaraTypeRegistryFlags같은거) 수정을 하면 어디서든 등장할 수 있을거같은데 시간이 없어서 다 해보진 못했음
#if WITH_EDITORONLY_DATA
void UNiagaraDataInterfaceCheckPlatform::GetFunctionsInternal(TArray<FNiagaraFunctionSignature>& OutFunctions) const
{
{
FNiagaraFunctionSignature Sig;
Sig.Name = FName("IsMobile");
Sig.bMemberFunction = true;
Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PlatformCheckSet")));
Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("Result")));
OutFunctions.Add(Sig);
}
}
#endif
이 함수가 그 내가 추가할 함수의 시그니처를 만들어주는 함수 저기서 선언한 형태로 핀이나 이름을 설정할 수 있고 함수 바디는 다른곳에서 처리해줌..
void UNiagaraDataInterfaceCheckPlatform::GetVMExternalFunction(
const FVMExternalFunctionBindingInfo& BindingInfo,
void* InstanceData,
FVMExternalFunction& OutFunc)
{
if (BindingInfo.Name == FName("IsMobile") && BindingInfo.GetNumInputs() == 0 && BindingInfo.GetNumOutputs() == 1)
{
OutFunc = FVMExternalFunction::CreateUObject(this, &UNiagaraDataInterfaceCheckPlatform::ExecIsMobile);
}
}
이 함수가 vm에서 함수를 실행하게 해주는 함수이며 규칙도 동일함 시그니처 네임으로 확인하므로 여러 개도 될거같긴한데 테스트는 못해봄…
bool UNiagaraDataInterfaceCheckPlatform::CopyToInternal(UNiagaraDataInterface* Destination) const
{
if (!Super::CopyToInternal(Destination))
{
return false;
}
UNiagaraDataInterfaceCheckPlatform* DestinationTyped = CastChecked<UNiagaraDataInterfaceCheckPlatform>(Destination);
DestinationTyped->bIsMobile = bIsMobile;
return true;
}
이 함수는 정확히 파악을 하지 못했음 위 함수가 없을때는 핀이 등록이 되지 않았음 그래서 뭔가 비슷한 형태의 노드를 찾다보니 죄다 이 함수가 있어서 보니 내부에서 생성한 규칙을 글로벌로 처리해주는느낌이어서 형식에 맞게 고쳐주니 노드에서 보이는것 같음
이 기능이 맨 위 함수에 있다고 생각이되는데 페어 함수인거같긴함
void UNiagaraDataInterfaceCheckPlatform::ExecIsMobile(FVectorVMExternalFunctionContext& Context)
{
VectorVM::FExternalFuncRegisterHandler<FNiagaraBool> OutValue(Context);
//실제 디바이스에서 처리
#if PLATFORM_ANDROID || PLATFORM_IOS
bIsMobile = true;
#else
bIsMobile = false;
#endif
//에디터 프리뷰용 처리
#if WITH_EDITOR
if (UWorld* World = GetWorld())
{
ERHIFeatureLevel::Type FeatureLevel = World->GetFeatureLevel();
bIsMobile = (FeatureLevel <= ERHIFeatureLevel::ES3_1);
}
else
{
// fallback
ERHIFeatureLevel::Type FeatureLevel = GMaxRHIFeatureLevel;
FeatureLevel = GEditor->PreviewPlatform.GetEffectivePreviewFeatureLevel();
if (FeatureLevel)
{
bIsMobile = (FeatureLevel <= ERHIFeatureLevel::ES3_1);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("FeatureLevel is Empty"));
}
}
#endif
for (int32 i = 0; i < Context.GetNumInstances(); ++i)
{
*OutValue.GetDestAndAdvance() = FNiagaraBool(bIsMobile);
}
}
바디 요 기능을 쓰기위해 인터페이스를 뚫는 과정이었고 내용은 모바일 체크임
실제로 기능자체라기보다는 나이아가라에 원하는 기능을 추가 할 수 있는 인터페이스의 구조나 흐름을 보기위해 기록은 남김
'unreal > UnrealCode' 카테고리의 다른 글
| [Unreal_Editor]5.44 에디터피처레벨 변경시 이벤트 추가하기 (1) | 2026.01.15 |
|---|---|
| [Unreal_Editor]5.44버전 머터리얼 커스텀 핀 추가하기 (0) | 2025.03.20 |
| [Unreal_Editor]언리얼 에디터 언어변경 토글버튼 추가(한 / 영) (0) | 2025.02.25 |
| [Unreal_Engine]모바일 디바이스에서 stat 글씨 크기 늘리기 (0) | 2024.04.05 |
| Unreal_애님 블루프린트 최적화 관련 몇가지 코드 (0) | 2023.04.18 |