티스토리 뷰

지난 포스팅까지는 새로운 에셋 유형인 머티리얼을 만들었다.

오늘 포스팅은 텍스처를 선택한 상태에서 머티리얼 생성 버튼을 누르면 텍스처 이름에 따라 내부적으로 노드를 연결해주는 과정이다.

 

머티리얼 에셋 안에서 노드와 핀을 올바른 소켓에 연결하고자 한다. 예를들어 선택된 텍스처의 RGB를 Base Color 에 연결하게한다. 그 외에도 노멀은 노멀 소켓에 연결, 러프니스는 러프니스 소켓에 연결하게 하고 싶다.

달성목표

  1. 사용자의 선택에 따라 어떤 텍스처가 어떤 종류인지 알아야 한다.
  2. 다음 노드를 생성하고 올바른 핀에 연결해야 한다.

텍스처의 종류는 이름에 따라 텍스처를 선택하도록 한다. 고정된 이름 규칙이 있는 경우 작업이 수월해진다. 사용자식의 명명규칙으로 선택된 머티리얼들에 대한 새로운 배열을 만들어 머티리얼 노드 안에서 핀끼리 연결하게 할 것이다.

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Supported Texture Names")
	TArray<FString> BaseColorArray = {
		TEXT("_BaseColor"),
		TEXT("_Albedo"),
		TEXT("_Diffuse"),
		TEXT("_diff") };

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Supported Texture Names")
	TArray<FString> MetallicArray = {
			TEXT("_Metallic"),
			TEXT("_metal")
	};

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Supported Texture Names")
	TArray<FString> RoughnessArray = {
			TEXT("_Roughness"),
			TEXT("_RoughnessMap"),
			TEXT("_rough")
	};

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Supported Texture Names")
	TArray<FString> NormalArray = {
			TEXT("_Normal"),
			TEXT("_NormalMap"),
			TEXT("_nor")
	};

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Supported Texture Names")
	TArray<FString> AmbientOcclusionArray = {
			TEXT("_AmbientOcclusion"),
			TEXT("_AmbientOcclusionMap"),
			TEXT("_AO")
	};

위는 이름 규칙에 따른 배열을 만드는 것. 선택된 텍스처의 이름 안에 다음의 글자들이 포함되어 있으면 해당 유형의 텍스처로 인식하게 된다. 이를 보기 쉽게 UPROPERTY로 두어 에디터에 띄워준다.

 

선택된 텍스처들은 위의 분류에 따라 종류를 나누어준다.

if (!CreatedMaterial->BaseColor.IsConnected())

위의 방식으로 머티리얼 노드의 해당 부분이 연결 되어있는지를 알 수 있다. 

그런데!!!!

내가 개발하는 환경은 언리얼 5.1.1 이다. 5.1.1 에서는 더이상 위와 같은 코드를 지원하지 않는다. 동일한 역할을 하는 코드는 다음과 같다.

if (!CreatedMaterial->HasBaseColorConnected())

핀이 연결되어 있는지 알려주는 함수가 새롭게 등장했다. 그러면 베이스컬러에 직접 접근하지는 못하나요? 라는 질문이 생길수 있는데 접근 가능하다.

CreatedMaterial->GetEditorOnlyData()->BaseColor;

중간에 GetEditorOnlyData() 함수를 한번 거치게 된다. 따라서 베이스 컬러에 직접 접근하여 연결되어있는지 확인할 수도 있는데 나는 새로운 함수를 사용해보고자 한다. (아직까지 동작에는 문제가 없다!)

 

그 다음 함수를 추가하여 노드를 진짜로 연결해준다.

bool UQuickMaterialCreationWidget::TryConnectBaseColor(
	UMaterialExpressionTextureSample* TextureSampleNode, UTexture2D* SelectedTexture, UMaterial* CreatedMaterial)
{
	for (const auto& BaseColorName : BaseColorArray)
	{
		if (SelectedTexture->GetName().Contains(BaseColorName))
		{
			// 베이스컬러 텍스처를 여기서 이어준다.
			TextureSampleNode->Texture = SelectedTexture;
			// UE 5.1.1 부터 아래 코드 불가.
			//CreatedMaterial->Expression.Add(TextureSampleNode);
			// 아래와 같이 사용할 것.
			CreatedMaterial->GetEditorOnlyData()->ExpressionCollection.Expressions.Add(TextureSampleNode);
			CreatedMaterial->GetEditorOnlyData()->BaseColor.Expression = TextureSampleNode;
			CreatedMaterial->GetEditorOnlyData()->PostEditChange();

			TextureSampleNode->MaterialExpressionEditorX -= 600;

			return true;
		}
	}

	return false;
}

위의 함수의 과정은 다음과 같다.

  1. 텍스처 샘플 노드 생성
  2. 노드에 텍스처 세팅
  3. 텍스처 압축 설정 및 텍스처 샘플 유형 설정
  4. 핀을 연결

위의 베이스 컬러에서는 텍스처 세팅을 변경하지 않았는데 아래에서는 할 것이다.

텍스처 샘플 노드를 만들어서 텍스처를 세팅해주고, 머티리얼과 텍스처 샘플노드를 연결해주면 된다.

 

다른 메탈릭, 노멀, AO 등에 대해서도 동일하게 해주면 된다.

메탈릭부터는 텍스처 압축세팅과 sRGB 타입, Sampler Type 에 대해서도 수정해준다.

bool UQuickMaterialCreationWidget::TryConnectMetalic(
	UMaterialExpressionTextureSample* TextureSampleNode, 
	UTexture2D* SelectedTexture, UMaterial* CreatedMaterial)
{
	for (const auto& MetalicName : MetallicArray)
	{
		if (SelectedTexture->GetName().Contains(MetalicName))
		{
			// 메탈릭 텍스처를 여기서 이어준다.
			SelectedTexture->CompressionSettings = TextureCompressionSettings::TC_Default;
			SelectedTexture->SRGB = false;
			SelectedTexture->PostEditChange();

			TextureSampleNode->Texture = SelectedTexture;
			TextureSampleNode->SamplerType = EMaterialSamplerType::SAMPLERTYPE_LinearColor;

			CreatedMaterial->GetEditorOnlyData()->ExpressionCollection.Expressions.Add(TextureSampleNode);
			CreatedMaterial->GetEditorOnlyData()->Metallic.Expression = TextureSampleNode;
			CreatedMaterial->GetEditorOnlyData()->PostEditChange();

			TextureSampleNode->MaterialExpressionEditorX -= 600;
			TextureSampleNode->MaterialExpressionEditorY += 240;

			return true;
		}
	}

	return false;
}

정확한 수치들은 마스터 머티리얼에 가서 뜯어보면 된다.

예를들어 노말은 머티리얼 샘플러타입을 노말으로 바꾸어줘야한다. 자세한건... 직접 확인!

그렇게 러프니스와 AO등도 연결해줌.

텍스처를 선택하고 머티리얼 생성 버튼을 누르면 이렇게 알아서 연결이 된다.

TextureSampleNode->MaterialExpressionEditorX -= 600;
TextureSampleNode->MaterialExpressionEditorY += 240;

위의 코드는 텍스처 샘플노드의 위치를 바꿔줌! 설정 안하면 머티리얼 노드랑 겹쳐있게 된다. (아주귀찮아짐)

 

그리고 이제 새로운 유형의 텍스처가 있다

Arm 이라고 되어있는 텍스처의 유형이다. (나도 처음본다.)

쉽게 말하면

AO, Roughness, Metallic 을 하나의 텍스처로 만든 형태이다. 

지금의 형태는 위의 3가지 텍스처를 각각 연결한 형태이다. 베이스컬러와 노말까지 합한다면 하나의 머티리얼에 5가지 텍스처가 붙는 형태다.

이는 메모리를 과도하게 잡아먹으며 이를 개선하기 위한 점이 위의 3가지를 하나의 텍스처로 만든 ARM 텍스처다. R은AO, G는 메탈릭, B는 러프니스로 연결된다.

좌 : 기본연결 & 우 : Arm텍스처 연결

 

기본 RBG가 아닌 다른 R,G,B,RBGA 노드는 인덱스 번호로 연결할 수 있다.

RGB는 0 , R은 1, G=2, B=3, RGBA = 4 가 된다.

 

ARM 텍스처를 연결하기 위해서는 다음과 같은 방법으로 연결하면 된다.

	CreatedMaterial->GetEditorOnlyData()->ExpressionCollection.Expressions.Add(TextureSampleNode);
	CreatedMaterial->GetEditorOnlyData()->AmbientOcclusion.Connect(1, TextureSampleNode);
	CreatedMaterial->GetEditorOnlyData()->Roughness.Connect(2, TextureSampleNode);
	CreatedMaterial->GetEditorOnlyData()->Metallic.Connect(3, TextureSampleNode);
	CreatedMaterial->GetEditorOnlyData()->PostEditChange();

CreatedMaterial->GetEditorOnlyData()->Metallic.Expression = TextureSampleNode;

로 연결하는 방식과 비슷하지만 조금은 다르다.

ARM 텍스처를 사용하냐 마냐는 에디터상에서 설정하도록 한다.

 

이제 마지막 과정!

머티리얼을 만들면서 머티리얼 인스턴스까지 생성하는 과정이다.

에셋을 만들때와 동일하게 FAssetToolsModule 을 가져오고 팩토리를 생성하여 에셋 생성할때 넣어준다.

머티리얼 인스턴스 팩토리는 UMaterialInstanceConstantFactoryNew 가 된다.

에셋 생성과 비슷하므로 코드만 올린다.

좀 다른점은 인스턴스를 생성하고 생성한 인스턴스의 부모를 기존 머티리얼로 설정해주는것!

이 부분만 좀 다르다.

UMaterialInstanceConstant* UQuickMaterialCreationWidget::CreateMaterialInstanceAsset(
	UMaterial* CreatedMaterial, FString NameOfMaterialInstance, const FString& PathToPutMaterial)
{
	NameOfMaterialInstance.RemoveFromStart(TEXT("M_"));
	NameOfMaterialInstance.InsertAt(0, TEXT("MI_"));

	UMaterialInstanceConstantFactoryNew* MIFactoryNew = NewObject<UMaterialInstanceConstantFactoryNew>();

	FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));

	UObject* CreatedObject = AssetToolsModule.Get().CreateAsset(
		NameOfMaterialInstance, PathToPutMaterial, UMaterialInstanceConstant::StaticClass(), MIFactoryNew);

	if (UMaterialInstanceConstant* CreatedMI = Cast<UMaterialInstanceConstant>(CreatedObject))
	{
		CreatedMI->SetParentEditorOnly(CreatedMaterial);
		CreatedMI->PostEditChange();
		CreatedMaterial->PostEditChange();

		return CreatedMI;
	}

	return nullptr;
}

이렇게 머티리얼을 생성하고 코드로 내부의 핀 연결 및 머티리얼 인스턴스까지 만드는 방법을 살펴보았다.


Git 주소 -> https://github.com/InKyung-U/CustomEditor

 

GitHub - InKyung-U/CustomEditor

Contribute to InKyung-U/CustomEditor development by creating an account on GitHub.

github.com

 

'Unreal > Custom Editor' 카테고리의 다른 글

[UE 5.1] Actor Randomize Transform  (0) 2023.10.30
[UE 5.1] Actor Duplicate - 1  (0) 2023.10.27
[UE 5.1] Custom Material Tool - 1  (0) 2023.10.11
[UE 5.1] Custom Icon  (0) 2023.09.20
[UE 5.1] Custom Slate Widget 04  (0) 2023.09.19
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함