본문 바로가기

Unreal Engine

핵이 있는 머터리얼 표현하기 (in UE)

안에 핵이 들어있는 머터리얼 표현을 구현해 보았다.

 

Radial Gradient

핵심은 Radial Gradient가 맵핑될 UV를 카메라 스페이스로 정렬해 주는 것이다.

카메라에서 오브젝트의 중심을 향하는 벡터와 거리를 각각 구해주었다. (거리는 이후 핵의 크기, 즉 Gradient의 Radius를 거리에 따라 조절할 때 사용한다.

CameraObjectDir = normalize(ObjectPosition - CameraPosition)

이렇게 구한 카메라 -> 오브젝트 벡터를 월드 Z 축과 외적해서, 카메라 방향에서 바라본 기준 Right 벡터를 구한다.

카메라 기준 Right 벡터와 카메라 -> 오브젝트 벡터를 다시 내적하면, 이번에는 카메라 기준의 Up 벡터를 구할 수 있다.

 

 

이렇게 구한 카메라에서 바라본 Up, Right 벡터를 기준으로 UV 좌표계를 구성한다.

Radial Gradient의 UV

그런데, 이렇게 단순 맵핑만 해 두면 핵이 안에 들어있는 것 처럼 보이기에는 부족하다.

보통 투명한 물체 안에 무언가 들어있다면, 물체의 성분에 따라 빛이 굴절되어 안쪽 물체가 표면 형태를 따라 변형되어 보인다. 이것을 흉내내기 위해 위에서 구한 UV를 적절히 변형시켰다.

 

UV DIstortion 없음
UV DIstortion 있음

나는 World Aligned 된 텍스처로 버텍스 위치를 조금씩 변화를 주었기 때문에, 이 텍스처를 활용해 UV를 변화시켜 주었다.

World Align 된 텍스처를 다시 카메라 스페이스로 변환해 준다.
Camera Space로 변환된 Noise를, 위에서 구한 UV 좌표에 add 해 준다.

1 - (N dot V) 를 곱해준 이유는, 카메라와 노멀이 정렬된 부분일수록 왜곡이 덜해지게 하기 위함이다.

이때 N dot V 계산에 사용된 N(노멀)은 위에서 World Aligned 된 텍스처 노멀을 사용하고 있다.

 

이렇게 계산된 UV 좌표를 사용해서 Radial Gradient를 맵핑한다.

앞에서 계산한 UV가 각각 -1 ~ 1 의 값을 가지기 때문에, 중심값인 (0, 0)을 CenterPosition으로 하였다.

카메라 거리가 멀어지면 핵의 크기도 변해야 하기 때문에, 앞에서 구한 카메라 -> 오브젝트의 거리를 일정 값으로 나누어 주었다. 여기에서 입력되는 Radius는 카메라로부터 오브젝트 중심 거리가 가 1.0일 때의 핵의 반지름이므로, 생각보다 큰 값이 들어가야 한다.

(스크린샷에서는 40.0 으로 설정한 상태이다)

 

이렇게 맵핑된 Radial gradient를 바탕 컬러와 적절히 혼합하면 된다.

Radial Gradient만 렌더링한 모습

 

응용 1. 핵의 위치, 크기 조절하기

Density와 Object Position 을 각각 Sine으로 반복적인 애니메이션을 줘서 위아래로 움직이게 해 보았다.

앞에서 Object Position을 사용한 부분에 Time에 따른 계산을 추가해 주었다.

ObjectPosition = ObjectPos + float3(0.0f, 0.0f, (sin(Time * 0.5) * Object Height).z);

여기에서 sin의 결과값은 -1 ~ 1 이므로 중심으로부터 위 아래로 움직이게 된다.

Time * 0.5 는 움직임 속도이다.

 

응용 2. 이미지 맵핑하기

UV 정렬을 활용한 것이기 때문에, radial gradient로 핵을 표현하는 것 말고도 다른 이미지를 맵핑할 수 있다.

아래는 태아 이미지를 맵핑해 본 것이다.

텍스처가 카메라를 향해 정렬되어 있기 때문에, 물체가 아닌 카메라를 돌리면 어색할 수 있다.