이전 글 보기
https://mountain-noroo.tistory.com/73
데칼 회전
데칼은 범위 안에 Depth타깃에 걸리는 픽셀이 있다면 데칼을 출력한다.
데칼 머티리얼을 만들 때는
머티리얼 도메인을 Deferred Decal
블렌드 모드를 Translucent로 설정해 준다.
CustomRotator라는 노드가 머티리얼을 회전시켜 준다.
원하는 각도, 중심축을 0~1 사이의 값으로 입력한다.
중앙을 중심으로 돌기 위해 0.5, 0.5의 값을 입력하였다.
그리고 각도를 파라미터로 변환하였다.
m_Material = m_Decal->CreateDynamicMaterialInstance();
회전 코드는 C++에서 작성하는데
데칼 컴포넌트에서 CreateDynamicMaterialnstance로 동적 머티리얼을 생성한다.
BeginPlay에서 동적 머티리얼을 생성해 주소를 가져오자.
CreateDynamicMaterialInstance 함수 내부
class UMaterialInstanceDynamic* UDecalComponent::CreateDynamicMaterialInstance()
{
UMaterialInterface* CurrentMaterial = DecalMaterial;
// If we already set a MID, then we need to create based on its parent.
if (UMaterialInstanceDynamic* CurrentMaterialMID = Cast<UMaterialInstanceDynamic>(CurrentMaterial))
{
CurrentMaterial = CurrentMaterialMID->Parent;
}
// Create the MID
UMaterialInstanceDynamic* NewMaterialInstance = UMaterialInstanceDynamic::Create(CurrentMaterial, this);
// Assign the MID
SetDecalMaterial(NewMaterialInstance);
return NewMaterialInstance;
}
내부에서는 현재 머티리얼을 복제해 다이내믹 머티리얼을 만들고 덮어쓰기 하고 있다.
// 둘다 동적 머티리얼의 주소를 의미함
// m_Decal->GetDecalMaterial();
// m_Material;
m_Angle += DeltaTime * 1.f;
m_Material->SetScalarParameterValue(TEXT("Angle"), m_Angle);
Tick 함수 내부에서 파라미터에 접근해 각도를 변화시키고 있다.
아직 문제가 있다
텍스처의 바깥 부분은 이렇게 반복되고 있기 때문에
모서리 쪽의 좌표가 돌다 보니 사각형 영역을 벗어났고
반복되는 부분의 텍스처가 출력되는 것이다.
해결 방법은 간단하다.
Saturate 노드로 UV 좌표 값이 들어오면 0~1 사이로 잘라주면 된다.
노이즈
랜덤 한 값을 주고 싶을 때 노이즈 텍스처를 사용한다.
원래 UV에 노이즈 텍스처의 랜덤 한 색상 값을 더해주면(값이 너무 차이 나지 않기 위해 0.1을 곱했다.)
일그러진 효과를 줄 수 있다.
한술 더 떠서 어제 했던 흘러가는 듯한 효과를 적용하면
결과적으로 일렁이는 느낌을 표현 가능하다.
소프트 파티클 개선
Before
After
소프트 파티클을 조금 바꾸어주었다.
정확히 무엇이 바뀌었냐 하면
이전에 만든 소프트 파티클 머티리얼은 알파값을 땅에 맞닿는 지점을 기준으로 위로 페이드 하였지만
이번에 개선한 소프트 파티클 머티리얼은 알파값을 땅에 맞닿는 지점을 기준으로 아래로 페이드 시킨다.
정리하자면 땅 아래, Depth Test에서 잘리는 픽셀들에 어떻게 페이드 효과를 줄까에 대해 알아보겠다.
일단 머티리얼의 디테일 창에서
Translucency -> 뎁스 테스트 비활성화를 체크해준다.
뎁스 테스트를 실패하면 잘려나가기 때문
픽셀이 땅 아래로 파고들었는지 알아내기 위해서는 Pixel Depth, Scene Depth라는 두 노드가 필요하다.
Pixel Depth는 현재 머티리얼을 참조하는 메시의 Depth 값만을 나타내는 것이라 땅을 파고 들어간 부분도 메시의 Depth 값이 리턴된다.
Scene Depth는 화면에 보이는 모든 픽셀의 Depth 값을 나타낸다. 즉 땅을 파고 들어간 부분이라면 땅의 Depth 값이 리턴된다.
(노드에 설명이 제일 잘 되어있다.)
땅 아래 픽셀들은 Scene Depth < Pixel Depth 이다.
애초에 Depth가 더 커서 잘리는 거니까.
그렇다면 Pixel Depth - Scene Depth를 했을 때 땅 위 픽셀은 값이 동일하니 0이 될 것이며
땅 아래의 픽셀은 땅에 비해 얼마나 깊이 들어가있는지의 값이 나올 것이다.
이 값을 Fade 기준치로 나누면
기준치보다 낮은 값은 1보다 커지고
페이드 되어야하는 값은 0~1 사이의 값을 가지게 되는데
이 때 1-x를 적용하면 1에 가까워질수록(기준치. 알파값이 0이되는 부분)0에 가까워지는 것으로 반전된다.
기준치를 넘어간 값은 0보다 작아진다.
이제 이 값을 그대로 알파값에 넣어도 되겠다.
텍스처에서 원래 알파값이 0인 부분도 적용하기 위해 if문을 사용하였다.
다른 부분은 저번 포스팅과 동일하다.
아웃라인 라이트
메시의 외곽으로 갈 수록 eye벡터와 노멀의 내적이 코사인 0에 가까워진다 (수직에 가까워지니까)
이 내적 값은 Fresnel로 받아올 수 있고
외곽값만 강하게 따기 위해 Exponentln의 값을 높여준다. (이 값만큼 내적한 값을 거듭제곱한다.)
잔상
PoseableMeshComponent를 사용하면 잔상 효과를 줄 수 있다.
void APoseCopy::CopyCurrentPose(USkeletalMesh* _Mesh, USkeletalMeshComponent* _SkeletalMeshCom, float _LifeTime)
{
m_PosCom->SetSkeletalMesh(_Mesh);
m_PosCom->CopyPoseFromSkeletalComponent(_SkeletalMeshCom);
int32 iMrlCount = m_PosCom->GetNumMaterials();
for (int32 i = 0; i < iMrlCount; ++i)
{
m_PosCom->SetMaterial(i, m_Mtrl);
}
if (_LifeTime == 0.f)
{
return;
}
SetLifeSpan(_LifeTime);
}
컴포넌트에 스켈레탈메시, 스켈레탈메시 컴포넌트를 넘겨주어야 한다.
또한 머티리얼에는 방금 만든 외곽선 빛 머티리얼을 적용시켰다.
// 포즈카피 액터 스폰시켜보기
FActorSpawnParameters param1 = {};
param1.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
APoseCopy* pPosCopyActor = GetWorld()->SpawnActor<APoseCopy>(APoseCopy::StaticClass(), GetActorLocation(), GetActorRotation(), param1);
pPosCopyActor->CopyCurrentPose(GetMesh()->GetSkeletalMeshAsset(), GetMesh(), 5.f);
애니메이션을 재생할 때 포즈카피 액터를 스폰시킨다.
'언리얼 > Assortrack UE5' 카테고리의 다른 글
[언리얼] 학원 25일차: 포스트 프로세스, 스텐실, 나이아가라 (1) | 2023.10.11 |
---|---|
[언리얼] 학원 24일차: Material (1) | 2023.10.10 |
[언리얼] 학원 22일차: Material(ScreenUV, MRT(Deffered)) 활용 (0) | 2023.09.26 |
[언리얼] 학원 21일차: 툴팁, 마우스 커서, 빌보드 (0) | 2023.09.25 |
[언리얼] 학원 20일차: 인벤토리 끄기(UMG Input) (0) | 2023.09.22 |