Portal
담당 구현 기능
Portal간 이동 기능 (포탈간 이동, 속도 변경)
Portal 생성기능 (맞은 벽의 각도에 맞춰 포탈 생성)
Portal 카메라 기능 ( 출구포탈의 풍경을 입구포탈에 투영 )
Portal 생성 가능 벽 구현(생성된 포탈에 맞춰 콜라이더 조정)
Portal 카메라 기능

구현 기능
실제 연결된것처럼 다른쪽 포탈 건너의 풍경이 보이게하는 기능
구현 원리
=> 각각의 포탈에 카메라를 하나씩 생성 (해당 카메라에 비치는 풍경을 다른 포탈에 송출)
=> 카메라 컴포넌트의 Target Texture 를 Render Texture를 생성해 할당
=> 해당 Texture을 가지는 Image를 포탈면Canvas에 생성
=> 카메라의 위치는 반대 포탈기준 플레이어의 LocalPosition을 이용(180도회전한 위치)하여 움직이게 만듦
(포탈과 플레이어 각도에따라 입체적으로 보이게하기위함)
=> 자연스럽게 보이게 하기위헤 카메라 절두체를 조정 (중요)

기본적으로 카메라 절두체는 카메라forward방향에 수직으로 되어있기때문에 절두체를 수동으로 조작할 필요가 있음

카메라 절두체 수동 조정 방법
카메라 컴포넌트의 속성 projectionMatrix;값을 직접 설정
projectionMatrix의 데이터형은 4x4 매트릭스 형태
그림의 표에 맞게 숫자를 대입
각 좌표는 카메라를 기준으로 본 좌표를 뜻함
=> 절두체는 부모인 포탈의 위치이고, 카메라는 포탈의 자식이므로 카메라의 LocalPositon과 절두체 크기(=포탈크기) 를 이용해 구함
r = 절두체 오른쪽 중앙 지점 좌표
l = 절두체 왼쪽중앙 지점 좌표
t = 절두체 중앙 위쪽 지점 좌표
b = 절두체 중앙 아래 지점 좌표
n = 절두체 중앙과의 거리
f = 최대 랜더링 거리

원하는 값을 계산하여 수동으로 조작하면 플레이어의 위치에 맞게 자연스러운 풍경을 반대포탈에 투영가능
해당 기능 코드

===========================================================
void SetCameraPositon() //반대측(반대색깔) 포탈에 비칠 풍경을 찍을 카메라 위치 세팅
{
Vector3 localPos = otherPotal.transform.InverseTransformPoint(player.cameraContainer.position); //반대측 포탈 기준 플레이어의 local좌표 계산
localPos.z = -localPos.z; //계산된 local좌표를 y축으로 180도 회전
localPos.x = -localPos.x;
portalCamera.transform.localPosition = localPos;
CameraProjectionUpdate(); //중요중요중요, 카메라의 "절두체"를 포탈과의 거리,각도에 맞춰 조정
Vector3 lookPoint = transform.position + (0.01f * transform.forward);
portalCamera.transform.localRotation = Quaternion.identity;
=============================================================================

========================================================================
void CameraProjectionUpdate()
{
Vector3 localPos = portalCamera.transform.localPosition;
float right = -localPos.x + (portalWidth / 2f);
float left = -localPos.x - (portalWidth / 2f);
float top = -localPos.y + (portalHeight / 2f);
float bottom = -localPos.y - (portalHeight / 2f);
float near = Vector3.Distance(portalCamera.transform.position, transform.position) + 0.01f;
float far = 300f;
Matrix4x4 _metrix = new Matrix4x4();
_metrix[0, 0] = 2f * near / (right - left);
_metrix[0, 2] = (right + left) / (right - left);
_metrix[1, 1] = 2f * near / (top - bottom);
_metrix[1, 2] = (top + bottom) / (top - bottom);
_metrix[2, 2] = -(far + near) / (far - near);
_metrix[2, 3] = -(2f * far * near) / (far - near);
_metrix[3, 2] = -1f;
portalCamera.projectionMatrix = _metrix;
}
================================================================================
트러블슈팅
처음에는 이 과정으로 절두체의 기울기(카메라forward 벡터와 절두체 평면의 각도) 만을 변경하는것으로 이해하여
포탈을 소환하는 로직과 같은 방법으로 카메라의 LocalRotation.z = 0 으로 고정시키며 forward방향이 포탈을 향하도록 함
결과로 엉뚱한 곳을 비추며 절두체 기울기와 포탈평면이 달라짐
여러번, 여러 각도에서 카메라를 실험하여 정면에선 오차가 덜하고 각도가 커질수록 기울기 오차가 2배정도 심해지는것을 보고 해당 코드를 삭제후 정상작동을 확인
Portal 생성 가능 벽 구현
목표 기능
포탈을 생성하면 생성된 포탈을 통과 할 수 있도록 해당 부분의 충돌이 없어지는 벽
구현 원리
=> 벽과 동일한 크기의 메인콜라이더
=> 포탈이 생성될시 포탈 생성 위치에 맞춰 가변적인 크기를 가지는 콜라이더 4개를 비활성화 상태로 생성
=> 레이캐스트로 해당 오브젝트(이하 포탈벽) 을 감지하여 포탈생성을 위한 메서드 활성화
=> 포탈생성 위치를 가능한 영역으로 보정(벽과 벽사이 중간은 생성불가)하여 생성 좌표값 반환
=> 메인 콜라이더 비활성화
=> 보정된 좌표값에 포탈 크기를 이용하여 나머지 4개 콜라이더의 크기를 조정
=> 해당 포탈이 없어지거나 옮겨지면 다시 메인콜라이더 활성화,나머지콜라이더 비활성화


해당 코드


이상 다른 기능들도 만든것이 있으나(UI, 포탈건 등) 프로젝트내 담당 핵심 기능에 대한 설명 이였습니다.