Jasontreks Blog

DM 보내기

메세지는 텔레그램 챗봇에 의해 익명으로 전달됩니다. 답장을 받으려면 이메일을 입력하세요.
Send

그래픽 디자인 - Non-Interactive 환경 요소

캐릭터 디자인을 완료한 우리 팀은 지면, 나무, 풀 등의 오브젝트들을 디자인하였다. 이들은 게임에서 플레이어와 특별한 상호작용을 하지는 않고 월드를 꾸미는 역할만 한다.

나무 디자인

가장 먼저 나무를 디자인했다. 나와 디자인 역할을 맡은 팀원이 각자 참고로 할 나무 그림을 찾고 일러스트레이터로 그려보았는데, 내가 그린 것보다 팀원이 그린 것이 훨씬 나아서 팀원이 그린 나무를 게임에 반영하기로 결정했다.

Abstract art
팀원이 그린 나무

풀 디자인

이어서 풀을 디자인했는데, 아래와 같이 두꺼운 잎을 3~4가닥 정도로 구성한 모양으로 디자인했다.

Abstract art
첫 번째 풀 디자인

근데 게임에서 보기에 풀이라기보단 알로에나 선인장 같은 사막에서 자라는 식물처럼 보이기도 하고, 묘하게 다른 오브젝트들과 조화가 안 되는 듯한 느낌이 들었다.

Abstract art
게임에 적용된 풀의 모습

그래서 아래처럼 풀의 디자인을 좀더 가늘고 밀집되어 있는 잡초와 같은 느낌이 들도록 다시 디자인했고, 일부 색상을 바꿔 두 가지로 디자인하였다.

Abstract art
게임에 적용된 모습

지면 디자인

넓은 땅을 전부 일일이 그리는 것은 굉장히 수고스러운 일이다. 때문에 대부분의 게임에서는 타일의 각 방향이 반대쪽과 맞물려 경계선 없이 이어지도록 하는 심리스 텍스처(Seamless Texture)를 디자인해 배치하는 타일링 기법을 사용한다.

Abstract art
심리스 텍스처를 이용한 예시. 요즘은 반복적으로 등장하는 패턴을 희석시켜 더 자연스럽게 하는 TexTile 기법을 사용한다.

우리 게임 역시 이 기법으로 지면을 디자인할 계획이었다. 나는 디자인을 맡은 다른 팀원에게(캐릭터, 나무를 디자인한 팀원과 다른 팀원) 두 가지의 지형 블록 스프라이트를 주문했다. 조건은 아래와 같았다.

  1. 가장 위에 배치할 플레이어와 접하는 표면 블록 스프라이트. 표면이 풀로 덮여 있으며 좌, 우 방향으로 심리스여야 한다.
  2. 표면 블록 밑하단을 채울 내부 블록 스프라이트. 풀 없이 흙만 그려야 하며 모든 방향으로 심리스여야 한다.
  3. 표면 블록의 하단과 내부 블록 상단은 심리스여야 한다.
  4. 두 스프라이트는 전부 같은 크기로 1대1 비율이어야 한다.

주문을 맡은 팀원은 아래와 같이 완벽하게 결과물을 냈다.

Godot의 Sprite2D 객체에 이 두 텍스처를 적용하고, Texture Wrapping을 Repeat 모드로 설정해 양쪽으로 늘리면 지면을 표현할 수 있다.

Abstract art

구름 디자인 및 ParallaxLayer 적용

하늘을 꾸미기 위해 구름을 그려 허공에 배치할 계획이였다. 나는 지형 블록 디자인을 맡은 팀원에게 다섯 가지 구름 디자인을 주문했고, 그 결과물은 아래와 같다.

이제 이 구름 텍스처들을 Sprite2D 노드에 적용해 배치하기만 하면 되는데, 2D 씬에서는 기본적으로 원근감 처리가 안되기 때문에 플레이어가 이동할 때 다른 오브젝트와 같은 속도로 구름이 지나간다면 굉장히 어색해 보이게 된다.

따라서 구름, 산처럼 멀리 있다고 인식되는 환경 요소는 원근감 처리를 해야 게임 내 세상의 적절한 공간 감각을 유저가 느낄 수 있다.

이를 위해 Godot은 2D 씬에서도 멀리 있는 정도를 정의해 원근감을 구현할 수 있도록 아래 노드들을 제공한다.

Abstract art
  • Parallax2D: 단독 오브젝트에 원근감을 적용할 수 있는 노드. 가장 최신 방식.
  • ParallaxLayer: 여러 오브젝트들 묶어 원근감을 주는 노드.
  • ParallaxBackground: ParallaxLayer들을 관리하는 부모 노드.

나는 ParallaxBackground와 ParallaxLayer를 사용해 원근감이 적용된 구름 배경을 만들었다. 구름은 두 레이어 그룹으로 나눠 원근감을 다르게 적용해 구현했다.

그리고 쉐이더에서 하늘 색상을 곱해 하늘 배경과 조화되도록 색감을 조정했다. 하지만 완전히 하얀색인 구름이 더 낫다고 생각이 들기도 한다.

바람에 의한 흔들림 효과 적용

그렇게 티가 나는 것은 아니지만 디테일을 조금 더 살리고 싶어서 풀과 나무에 바람에 의해 흔들리는 움직임을 부여하였다.

이 효과는 스켈레탈 애니메이션이나 스프라이트 애니메이션이 아닌 픽셀 쉐이더에서 사인 함수를 적용하는 방식으로 구현하였다.

y=asin(bx+c)y=a*sin(bx+c)
  • x: 현재 픽셀의 세로 좌표 값.
  • a: 진폭 값으로, 얼마가 격하게 흔들리는지 조절하여 바람의 세기를 표현한다.
  • b: 주기 값으로, 마루의 수를 조절할 수 있다. 즉 흔들리는 개체의 재질이 유연하거나 빳빳한 정도를 조절해 질감 표현을 할 수 있다.
  • c: 위상 값으로, 현재 시간과 속도를 곱한 값을 사용한다. 현재 시간은 지속적인 움직임 효과를 위해 필수적이며, 속도는 흔들림의 빠르기를 조절한다.
void fragment() {
	vec2 uv = UV;
    float sway = sin(TIME * sway_speed + UV.y * waves) * sway_strength * (1.0 - UV.y);
    uv.x += sway / 100.0;

    COLOR = texture(TEXTURE, uv);
}

sway_strength(1.0 - UV.y)를 곱한 것은 픽셀이 바닥에서 멀어질수록 더 많이 흔들리는 점을 표현하기 위함이다.

waves, sway_strength, sway_speed 이 세 가지 변수의 값을 쉐이더 파라미터로 전달해 원하는 동작이 나오도록 세밀하게 조절할 수 있다.

해당 효과는 나무에도 똑같이 적용하였다.

아래는 흔들림 효과가 게임 내에서 적용된 모습이다. 엄청난 차이를 보여주고 있지는 않지만 이러한 사소한 디테일이 게임의 현장감을 좀더 살려주고 있다는 점은 분명해 보인다.

다음 포스트

그래픽 디자인 - 탄환 및 대포