ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 플레이어 시야 FOV 구현
    게임 클라이언트 개발/Unity 2023. 12. 13. 20:27

    Unity로 탑 뷰 형식의 게임을 제작할 때 플레이어의 시야를 제한하여 게임의 긴장도를 줄 수 있다.

     

    어몽어스와 같은 마피아 게임 장르인 Interactopia 프로젝트를 진행할 때, 플레이어의 시야를 제한하기 위해 FOV를 구현했던 과정을 작성하고자 한다.

     

    https://github.com/woghrk12/FOV2D.git

     

    GitHub - woghrk12/FOV2D

    Contribute to woghrk12/FOV2D development by creating an account on GitHub.

    github.com

     

    Light 2D

    가장 빠르게 시야를 구현할 수 있는 방법으론 Light 2D Component를 활용하는 것이다. Point Light를 캐릭터의 위치로 고정하고 벽에 Shadow Caster 2D Component를 설정하여 시야를 구현할 수 있다.

     

    Shadow Caster 2D 컴포넌트가 설정된 벽

     

    하지만, Light 2D Component와 Shadow Caster 2D Component를 사용하여 구현할 경우, 두 가지 문제점이 발생한다.

    1. 시야 밖의 오브젝트도 간접 빛의 영향을 받아 보이는 현상
    2. 빛의 범위 밖은 아예 보이지 않는 현상

    Light 2D와 Shadow Caster 2D를 활용한 시야

     

    Universal Renderer Data

    Light 2D Component를 사용할 경우 발생한 문제점을 해결하기 위한 키 포인트는 다음과 같다.

    1. 시야의 영향을 받을 오브젝트를 분류해야 한다.
    2. 시야 밖의 오브젝트는 렌더링 자체를 하지 않아야 한다.

     

    Rendering Pipeline에서 Stencil Buffer를 활용하면 위 요구 사항을 모두 만족할 수 있다. 우선, 캐릭터 위치로부터 레이캐스팅을 통해 마스킹을 위한 영역을 Mesh로 생성한다.

    FOV에 따라 런타임에 생성한 시야 Mesh

     

    마스킹의 영향을 받지 않는 배경들, 즉, Forward Rendering 될 Layer를 설정한다. 2D로 프로젝트를 생성한 경우 Renderer Data로 Renderer 2D Data를 사용하는데, Forward Rendering은 2D에서 사용할 수 없다. Universal Renderer Data를 새로 생성하여 할당해줘야 한다.

    Universal Renderer Data의 Filtering 세팅

     

    이후 각 Layer의 Stencil Buffer를 세팅해 준다. 시야 영역(Mask)의 Stencil Value를 1로 설정하고 시야 내에서만 렌더링 되어야 하는 오브젝트(BehindMask; 캐릭터, 적 등)의 Stencil을 Stencil Value가 1인 영역에서만 렌더링 하고, 시야 밖(Black)인 Stencil Value가 1이 아닌 영역은 반투명 검은 오브젝트를 렌더링 하여 어둡게 표현한다.

    Universal Renderer Data에 추가한 Render Object Feature (Mask, BehindMask, Black)
    Universal Renderer Data를 활용한 시야

     

    단, Universal Renderer Data는 3D 렌더링 데이터이고, Light2D Component를 사용하기 위한 Renderer 2D Data는 2D 렌더링 데이터이다. 2D와 3D는 렌더링 되는 방식이 달라 두 데이터를 같이 사용할 수 없어 위 기법을 사용할 경우 Light를 적용할 수 없다.

     

    Sprite Mask

    이번에는 Renderer Data를 수정하지 않고 Sprite Mask Component를 활용한다. 위에서 Mesh를 생성한 방법과 마찬가지로 레이캐스팅을 통해 시야의 범위를 위한 정점을 추출한다.

     

    해당 정점들로 Mesh를 생성하는 것이 아닌 Sprite Mask에서 사용될 Sprite의 Texture를 재조립한다. Sprite Component의 OverrideGeometry 함수를 통해 Texture를 재조립할 수 있다.

    // spriteMask : Sprite Mask Component
    // vertices : Raycasting으로 추출한 정점 배열
    // triangles : 삼각형을 조립할 정점들의 Index 배열
    spriteMask.sprite.OverrideGeometry(vertices, triangles);

     

    시야의 영향을 받을 스프라이트의 Mask Interaction을 Visible Inside Mask로 설정해 주면 Sprite Mask를 활용한 시야를 구현할 수 있다.

    시야의 영향을 받을 Sprite Renderer
    Sprite Mask Component를 활용한 시야

     

    '게임 클라이언트 개발 > Unity' 카테고리의 다른 글

    Animation Missing! 해결법  (0) 2024.04.12
    길찾기 알고리즘과 최적화  (0) 2023.11.27
    UGUI의 성능 최적화  (0) 2023.11.08
    Unity 스크립트 최적화  (0) 2023.11.07
Designed by Tistory.