언리얼 나이아가라 대부분의 기능은 노드로 구현이 가능함 지버퍼나 스크린 데이터도

가끔 없는기능이나 불편한 기능이 존재해 노드를 추가할 필요가 있는데 나이아가라는 머터리얼처럼 간단히 추가할 없음

 

일정때문에 너무 급히 만들다보니 완전 디테일하게 파악하지 못하고 대충 이런 흐름을 따라 추가할수 있다 정도로만 보시면될듯합니다.

 

 

일단 모든 노드는 각자의 데이터인터페이스 클래스를 갖고 있음

플러그인으로 만드는것도 가능하다고 하지만 처음해보는거라

그냥 나이아가라 플러그인 안쪽에 파일을 추가함

 

 

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);

    }

}

 

바디 기능을 쓰기위해 인터페이스를 뚫는 과정이었고 내용은 모바일 체크임

실제로 기능자체라기보다는 나이아가라에 원하는 기능을 추가 있는 인터페이스의 구조나 흐름을 보기위해 기록은 남김

+ Recent posts