Unity 본캠프 TIL

Unity 본캠프 TILUnity 본캠프 TIL (25/03/21) Chapter5 Unity숙련 팀프로젝트 종합 TIL - 2

kk2247401 2025. 3. 21. 21:08

Portal

 

담당 구현 기능

Portal간 이동 기능 (포탈간 이동, 속도 변경)

Portal 생성기능 (맞은 벽의 각도에 맞춰 포탈 생성)

Portal 카메라 기능 ( 출구포탈의 풍경을 입구포탈에 투영 )

Portal 생성 가능 벽 구현(생성된 포탈에 맞춰 콜라이더 조정)

 

 

 

Portal 카메라 기능

 

반대편 풍경이 보임

 

구현 기능

실제 연결된것처럼 다른쪽 포탈 건너의 풍경이 보이게하는 기능

 

구현 원리

=> 각각의 포탈에 카메라를 하나씩 생성 (해당 카메라에 비치는 풍경을 다른 포탈에 송출)

=> 카메라 컴포넌트의 Target Texture 를 Render Texture를 생성해 할당

=> 해당 Texture을 가지는 Image를 포탈면Canvas에 생성

=> 카메라의 위치는 반대 포탈기준 플레이어의 LocalPosition을 이용(180도회전한 위치)하여 움직이게 만듦

     (포탈과 플레이어 각도에따라 입체적으로 보이게하기위함)

=> 자연스럽게 보이게 하기위헤 카메라 절두체를 조정 (중요)

 

 

반대포탈의 뒤편에서 플레이어가 보고있는듯한 효과

 

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

카메라의 forward방향에 위치하고, forward와 수직으로 되있는 기본 절두체

 

카메라 절두체 수동 조정 방법

카메라 컴포넌트의 속성 projectionMatrix;값을 직접 설정

projectionMatrix의 데이터형은 4x4 매트릭스 형태

 

그림의 표에 맞게 숫자를 대입

각 좌표는 카메라를 기준으로 본 좌표를 뜻함

=> 절두체는 부모인 포탈의 위치이고, 카메라는 포탈의 자식이므로 카메라의 LocalPositon과 절두체 크기(=포탈크기) 를 이용해 구함

 

r = 절두체 오른쪽 중앙 지점 좌표

l = 절두체 왼쪽중앙 지점 좌표

t = 절두체 중앙 위쪽 지점 좌표

b = 절두체 중앙 아래 지점 좌표

n = 절두체 중앙과의 거리

f = 최대 랜더링 거리

절두체 중앙과 카메라를 잇는 직선과 절두체평면의 각도가 세타인 절두체

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

 

해당 기능 코드

카메라의 위치를 지정하는 코드 (update로 최신화)

 

===========================================================

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개 콜라이더의 크기를 조정

=> 해당 포탈이 없어지거나 옮겨지면 다시 메인콜라이더 활성화,나머지콜라이더 비활성화

평소의 1개 메인 콜라이더
포탈 생성시 4개의 콜라이더

 

 

해당 코드

(벽과 바닥 2가지 타입이 있으므로 base를 상속) 포탈생성시 메인꺼주고 나머지 활성화 코드

 

나머지 콜라이더 크기 계산 코드

 

 

 

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