반응형

Shading Model과 GBuffer에 대한 설정까지 완료하였으니, Material Node 설정을 하도록 한다.

 

참고하는 링크에서는 CustomData를 사용하지 않고, 새로운 출력 노드를 생성하는 방식으로 진행한다고 한다.

일단은 Tutorial을 따라하는 중이기 때문에, 추후에 CustomData를 사용하는 방식을 따로 알아보려고 한다.

(키워드 : MakeMaterialAttribute, BreakMaterialAttribute)

 

Engine/Source/Runtime/Engine/Classes/Materials/ 경로 내에, MaterialExpression들이 존재한다.

해당 표현식 노드로 Cell Shading 노드를 만들어보도록 하겠다.

 

MaterialExpressionCustomOutput Class를 상속받는 Class 하나 생성해야한다.

// MaterialExpressionCellShadingCustomOutput.h :: Create

#pragma once

#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "MaterialExpressionIO.h"
#include "MaterialValueType.h"
#include "Materials/MaterialExpressionCustomOutput.h"
#include "MaterialExpressionCellShadingCustomOutput.generated.h"

UCLASS()
class UMaterialExpressionCellShadingCustomOutput : public UMaterialExpressionCustomOutput
{
	GENERATED_UCLASS_BODY()

	UPROPERTY(meta = (RequiredInput = "true"))
	FExpressionInput Input;

#if WITH_EDITOR
	virtual int32 Compile(class FMaterialCompiler* Compiler, int32 OutputIndex) override;
	virtual void GetCaption(TArray<FString>& OutCaptions) const override;
	virtual uint32 GetInputType(int32 InputIndex) override { return MCT_Float3; }
	virtual FExpressionInput* GetInput(int32 InputIndex) override;
#endif
	virtual int32 GetNumOutputs() const override { return 1; }
	virtual FString GetFunctionName() const override { return TEXT("GetCellShading"); }
	virtual FString GetDisplayName() const override { return TEXT("CellShading"); }
};

기본 Override 함수들을 추가해주고, Function Name과 Display Name을 설정해준다.

Material Node를 사용할 때 노출되는 이름은 Function Name이 된다.

 

클래스 함수 정의부는 모두 MaterialExpressions.cpp 파일에서 정의가 되기 때문에, 마찬가지로 진행해준다.

// Material Expressions.cpp

~~ ... ~~

#include "Materials/MaterialExpressionCameraVectorWS.h"
#include "Materials/MaterialExpressionCellShadingCustomOutput.h"
#include "Materials/MaterialExpressionCeil.h"

~~ ... ~~

///////////////////////////////////////////////////////////////////////////////
// Cell Shading Custom Output
///////////////////////////////////////////////////////////////////////////////

UMaterialExpressionCellShadingCustomOutput::UMaterialExpressionCellShadingCustomOutput(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
#if WITH_EDITORONLY_DATA
	// Structure to hold one-time initialization
	struct FConstructorStatics
	{
		FText NAME_Utility;
		FConstructorStatics(const FString& DisplayName, const FString& FunctionName)
			: NAME_Utility(LOCTEXT("Utility", "Utility"))
		{
		}
	};
	static FConstructorStatics ConstructorStatics(GetDisplayName(), GetFunctionName());

	MenuCategories.Add(ConstructorStatics.NAME_Utility);

	bCollapsed = true;

	// No outputs
	Outputs.Reset();
#endif
}

#if WITH_EDITOR
int32  UMaterialExpressionCellShadingCustomOutput::Compile(FMaterialCompiler* Compiler, int32 OutputIndex)
{
	if (Input.GetTracedInput().Expression)
	{
		return Compiler->CustomOutput(this, OutputIndex, Input.Compile(Compiler));
	}
	else
	{
		return CompilerError(Compiler, TEXT("Input missing"));
	}
	return INDEX_NONE;
}


void UMaterialExpressionCellShadingCustomOutput::GetCaption(TArray<FString>& OutCaptions) const
{
	OutCaptions.Add(GetDisplayName());
}

FExpressionInput* UMaterialExpressionCellShadingCustomOutput::GetInput(int32 InputIndex)
{
	return &Input;
}
#endif // WITH_EDITOR

~~ ... ~~

기본 내부 코드는 다른 Custom Output 함수를 참고하여 작성하였다.

필자가 참고한 내용은 링크와 동일한 BentNormal 이다.

 

해당 작업까지 하면, Material Expression Function이 생긴 것을 확인할 수 있다.

Cell Shading Expression

하지만 내부 로직이 구현되어 있지 않기 때문에, 생성만으로도 Compile Error가 발생한다.


Material Attribute

현재 Cell Shading Material Attribute는 기본 Attribute이기 떄문에, 사용하고자 하는 Pin을 활성화 시켜야한다.

 

Attribute는 Material::IsPropertyActive_Internal 함수에서 활성화 시킬 수 있다.

// Material.cpp

~~ ... ~~
static bool IsPropertyActive_Internal(EMaterialProperty InProperty,
	EMaterialDomain Domain,
	EBlendMode BlendMode,
	FMaterialShadingModelField ShadingModels,
	ETranslucencyLightingMode TranslucencyLightingMode,
	bool bBlendableOutputAlpha,
	bool bUsesDistortion,
	bool bUsesShadingModelFromMaterialExpression,
	bool bIsTranslucencyWritingVelocity,
	bool bIsThinSurface,
	bool bIsSupported)
{
	~~ ... ~~

    case MP_Opacity:
        Active = (bIsTranslucentBlendMode && !IsModulateBlendMode(BlendMode)) || ShadingModels.HasShadingModel(MSM_SingleLayerWater);
        if (IsSubsurfaceShadingModel(ShadingModels))
        {
            Active = true;
        }
        break;

	~~ ... ~~

    case MP_Tangent:
        Active = ShadingModels.HasAnyShadingModel({ MSM_DefaultLit, MSM_ClearCoat }) && (!bIsTranslucentBlendMode || !bIsVolumetricTranslucencyLightingMode);
        break;
    case MP_SubsurfaceColor:
        Active = ShadingModels.HasAnyShadingModel({ MSM_Subsurface, MSM_PreintegratedSkin, MSM_TwoSidedFoliage, MSM_Cloth, MSM_DR_CellShading });
        break;
    case MP_CustomData0:
        Active = ShadingModels.HasAnyShadingModel({ MSM_ClearCoat, MSM_Hair, MSM_Cloth, MSM_Eye, MSM_SubsurfaceProfile });
        break;
            
	~~ ... ~~

 

Opacity는 IsSubsurfaceShadingModel 함수로 처리되기 때문에, 해당 함수에 조건을 추가한다.

// MaterialShared.h

~~ ... ~~

inline bool IsSubsurfaceShadingModel(FMaterialShadingModelField ShadingModel)
{
	return ShadingModel.HasShadingModel(MSM_Subsurface) || ShadingModel.HasShadingModel(MSM_PreintegratedSkin) ||
		ShadingModel.HasShadingModel(MSM_SubsurfaceProfile) || ShadingModel.HasShadingModel(MSM_TwoSidedFoliage) ||
		ShadingModel.HasShadingModel(MSM_Cloth) || ShadingModel.HasShadingModel(MSM_Eye) || ShadingModel.HasShadingModel(MSM_DR_CellShading);
}

~~ ... ~~

 

Custom Pin 추가 방법

더보기

추가로 CustomData를 Material로 설정하려면, MaterialAttributeDefinitionMap.cpp 파일 내에 있는 아래의 함수를 통해 Pin을 추가할 수 있다.

 

FText FMaterialAttributeDefinitionMap::GetAttributeOverrideForMaterial(const FGuid& AttributeID, UMaterial* Material)

Set Attribute

위의 설정으로 Opacity, Subsurface Color가 활성화 된 것을 확인할 수 있다.

반응형

+ Recent posts