내가 제작하고 있는 VR카레이싱 게임에서, 차량의 사이드 미러와 백미러를 구현하려고 했다.
미러를 구현하기 위해, 처음 시도한 방법은 Reflection Probe를 이용한 방법이다.
하지만 이내, 문제가 생겨 유니티 카메라를 이용한 방법으로 변경했다.
아래는 그 과정이다.
1. 첫 번째 시도: Reflection Probe
유니티 Reflection Probe (반사 프로브)
주변의 모든 방향에서 캡처하는 카메라와 유사합니다. 캡처된 이미지는 반사 머티리얼이 있는 오브젝트에서 사용할 수 있는 큐브맵(Cubemap)으로 저장됩니다. 특정 씬에는 여러 반사 프로브를 사
ksuo.tistory.com
위 글을 참고하여 제작했다.
간단히 말해서, 특정 Material에 이 Reflection Probe를 붙이면, 이 Reflection Probe가 모든 방향의 반사광을 계산해서 그 Material에 거울 같은 반사효과를 만들어낸다.
이 Reflection Probe에는 반사를 계산하는 여러 Type이 있는데, 나는 그중에서 실시간으로 반사광을 계산해서 Material에 반영시켜 주는 Realtime type을 선택했다.
게임 플레이 도중, 차량과 유저의 움직임에 따라 Material에 보이는 거울의 상이 실시간으로 달라져야 하기 때문이다.
즉, Realtime type의 Reflection Probe를 차량의 사이드 미러 및 백미러 모델에 적용돼있는 Material에 붙여서 미러 기능을 구현했다.
물론 이 방법은 실시간으로 반사광을 계산하기 때문에, 어느 정도 성능의 문제가 생길 것이라고 예상했다.
그럼에도 이 방법을 사용한 이유는 두 번째 방법(카메라 이용)보다 구현이 간단하고, 유저가 보기에도 더 자연스러운 거울 효과를 줄 수 있기 때문이었다.
하지만 테스트를 해보니 성능 문제가 예상했던 것보다 훨씬 더 컸다.
이 게임의 초당 프레임이 약 60FPS에서 30FPS 미만으로 급격하게 떨어진 것이다.
그래서 Material에 보이는 거울의 상의 해상도를 낮춰봤지만 성능 개선의 효과는 별로 없었다.
그래서, 결국 두 번째 방법으로 변경했다.
2. 두 번째 시도: 카메라 이용
유니티 MIRROR(거울) 구현하는 방법
Mirror 세팅하기 빈오브젝트를 하나 생성해 줍니다. 다음으로, 빈오브젝트 자식으로 quad를 하나 생성해 줍니다. 스케일(Size : x , y)을 9: 16으로 설정해 주고 Scale을 줄여줍니다. 줄이고 난 후에는 "좌
wlsdn629.tistory.com
위 글을 참고하여 제작했다.
간단히 말해서, 특정 Material에 특정 카메라가 비추는 화면을 넣는 것이다.
하지만 위 방법을 내 게임에 적용하는데에 두 가지 문제가 있었다.
1. 문제1: 사이드 미러, 백미러에 적용돼있는 Material은 단 하나다.
내가 가져온 차량 모델 에셋에는 위 사진처럼 총 3가지 Material이 적용되어 있다.
그중 하나의 Material인 "Reflaction"이 양쪽 사이드 미러, 백미러에 모두 적용되어 있다.
만약, 이 Material에 이 방법(이 Material에 특정 카메라가 비추는 화면을 넣는 것)을 적용한다면, 이 특정 카메라가 비추는 단 하나의 화면이 양쪽 사이드미러, 백미러에 모두 적용되기 때문에, 양쪽 사이드미러, 백미러가 비추는 거울 상들은 모두 같아지게 될 것이다.
하지만, 양쪽 사이드미러, 백미러가 비추는 상은 모두 달라야 하기 때문에 이것은 문제가 된다.
이 문제를 해결하기 위해서는 양쪽 사이드 미러, 백미러 모델에 다시 모두 다른 Material을 적용해야 한다.
하지만 그러려면 차량 모델 자체를 다시 수정해야 하는데 그것은 불가능하다.
따라서, 대안으로 Quad(사각형 게임오브젝트) 3개를 새로 생성해서, 각각 왼쪽 사이드미러, 오른쪽 사이드미러, 백미러 부분에 겹쳤다.
그리고 이 각각의 Quad에 모두 다른 Material을 적용한 다음, 이 각각의 Material에 따로따로 그 방법을 적용했다.
즉, 사이드미러, 백미러 모델 자체에 그 방법을 적용하는 게 아닌, 이 모델들에 겹쳐있는 모델들에 따로따로 그 방법을 적용한 것이다.
그렇게 해서 첫 번째 문제를 해결했지만, 아직 문제가 하나 더 남았다.
2. 문제 2: 카메라가 거울 뒤에 있으면 상을 제대로 비추지 못함
유저가 위치와 시선을 이동함에 따라 거울에 비치는 상도 바뀌어야 한다.
그래서 내가 참고한 글에서는 유저의 위치 및 시선 이동에 따라, 카메라의 위치 및 로테이션도 변경하는 코드를 작성했다.
하지만 그렇게 카메라가 이동하다가 거울모델 뒤로 가버리면 카메라를 거울모델이 가려버려서 상을 제대로 비추지 못하게 된다.
그래서 내가 참고한 글에서는 거울모델을 카메라 필터링에서 지움으로써 이를 해결했다.
하지만 나는 그렇게 할 수 없었다.
애초에 내가 가져온 차량 모델 자체에 사이드미러, 백미러 모델이 따로 나뉘어 있지 않고, 모두 모델 하나로 통합되어 있기 때문이다.(다시 나누려면 역시 모델 자체를 수정해야 한다...)
그래서 사이드미러, 백미러 모델만 따로 카메라 필터링에서 지울 수는 없고, 지우려면 차량 모델 자체를 카메라 필터링에서 지울 수밖에 없다.
하지만 당연히 내 차량도 거울에 비춰져야 하기 때문에 그럴 수는 없다.
그래서 나는 카메라의 초기 위치를 거울 살짝 앞에 두고, 카메라의 위치 및 로테이션을 변경하는 코드를 로테이션만 변경하는 코드로 변경해서, 카메라가 애초에 거울 모델 뒤로 가지 않게 만들었다.
아래는 그렇게 해서 수정한 카메라 이동 코드 내용이다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MirrorCameraMovement : MonoBehaviour //플레이어가 거울을 바라보는 위치에 따라 미러카메라의 위치 및 회전 변경
{
public Transform playerTarget;
public Transform mirror;
public float rotateRatio = 1f; //회전을 몇 배로 할 것인지.
private void Start()
{
if (mirror == null)
{
mirror = transform.parent;
}
}
void Update()
{
//카메라 위치변경
Vector3 localPlayer = mirror.InverseTransformPoint(playerTarget.position);
//transform.position = mirror.TransformPoint(new Vector3(localPlayer.x, localPlayer.y, -localPlayer.z));
//카메라 회전변경
Vector3 lookTarget = mirror.TransformPoint(new Vector3(-localPlayer.x*rotateRatio, localPlayer.y, localPlayer.z));
transform.LookAt(lookTarget);
}
}
물론 이렇게 코드를 변경하면, 유저의 앞 뒤 움직임에 따라 변하는 거울 상을 반영하지 않게 된다.
하지만, 유저는 게임 내내 대부분 차량에 타고 있으므로, 유저가 차량을 기준으로 앞뒤로 움직이는 경우는 거의 없기 때문에 그렇게 큰 문제는 아니다.
이렇게 해서 두 가지 문제를 모두 해결했다.
아래는 그렇게 해서 만들어진 거울들 중 왼쪽 사이드미러이다.
물론, 보다시피 Quad가 사이드미러 밖으로 살짝 튀어나와있지만, 모델러가 아닌 나는 이게 최선이다...
그리고 이렇게 모델 자체의 특성으로 인한 문제들(Material, 모델이 나뉘어져있지 않는 등)을 겪어보니, 프로그래머가 편하도록 모델을 만들어주고 수정해주는 모델러에 대한 필요성이 절실히 느껴졌다...
댓글과 공감클릭은 더 좋은글을 위한 큰 힘이 되니 댓글과 공감클릭 부탁드립니다!!
'프로젝트 > FPS+레이싱게임' 카테고리의 다른 글
레이싱 게임 트랙포인트(체크포인트) 설치 자동화(코너 자동 판단) (0) | 2024.07.09 |
---|---|
레이싱 게임 실시간 순위 계산 로직 만들기 (2) | 2024.07.09 |
게임 결과창 UI 띄우기 및 게임기록 저장: 파일저장(2) (0) | 2024.05.10 |
게임 결과창 UI 띄우기 및 게임기록 저장: switch문, enum, 코루틴, 파일저장(1) (0) | 2024.01.16 |