본문 바로가기
[Unity]

[Unity] GL로 카메라 페이드 효과 구현하기

by 김기승 2023. 10. 5.

화면을 점차 어두워지거나 밝아지게끔 구현하려면 어떤 방법이 있을까?

직접 카메라 오브젝트 앞에 검은색 물체를 가져다 놓는 방법도 있고,

Canvas에 검은색 이미지를 두어 알파값을 조절하는 방법도 있을 것이다.

하지만, 위의 방법들은 기능의 비중에 비해 오버헤드가 크다고 볼 수 있다.

 

유니티에서는 OpenGL이라는 저수준(Low-Level) 그래픽 라이브러리 문법을 일부 지원한다.

이를 활용하면, Camera에 직접 그리기 명령을 호출하여 원하는 대로 도형을 만들어낼 수 있다.
이번 글에서는 이러한 도형으로 카메라 페이드 효과를 구현해보자.


원리

도형의 종류는 Lines(선), Triangles(삼각형), Quads(사각형)가 있다.

※ Strip도 있지만, 여기서는 생략한다.

 

각 도형의 점 개수만큼 위치를 지정해서 도형을 그릴 수가 있다.

아래의 그림을 보자.

Game 화면의 왼쪽 밑 모서리를 원점으로 2차원 좌표계를 가진다.

우리가 원하는 것은 화면 전부를 덮는 도형이므로, Quads를 그려보도록 하자.

먼저 (0, 0) 위치를 지정한다.

두번째로 (1, 0) 위치를 지정한다.

세번째로 (1, 1) 위치를 지정한다.

마지막으로 (0, 1) 위치를 지정한다.

 

이런 방식으로 지정한 위치 개수에 따라 도형이 만들어진다.

이 도형의 알파만 조절하면 페이드 효과가 만들어지는 것이다.


스크립트

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(Camera))] //Camera 컴포넌트 필수
public class GLFade : MonoBehaviour
{
    private Material mat; //화면에 사용할 머터리얼
    private Coroutine routine; //코루틴
    private float alpha; //알파값

    //__________________________________________________ Render
    private void OnPostRender()
    {
        if (!mat) //Material이 존재하지 않으면
        {
            mat = new Material(Shader.Find("Hidden/Internal-Colored")); //Material 생성
        }

        mat.SetPass(0);

        GL.PushMatrix(); //GL 렌더링 시작
        GL.LoadOrtho(); //화면 범위를 0~1로 변환

        GL.Begin(GL.QUADS); //Quad 그리기 시작
        GL.Color(new Color(0f, 0f, 0f, alpha)); //알파값을 적용한 색상 지정
        GL.Vertex3(0f, 0f, 0f); //왼쪽 밑
        GL.Vertex3(1f, 0f, 0f); //오른쪽 밑
        GL.Vertex3(1f, 1f, 0f); //오른쪽 위
        GL.Vertex3(0f, 1f, 0f); //왼쪽 위
        GL.End(); //Quad 그리기 종료

        GL.PopMatrix(); //GL 렌더링 종료
    }

    //__________________________________________________ Fade
    public void ToggleFade(bool value, float duration = 1f) //Fade를 수행하는 함수
    {
        if (routine != null) //이미 코루틴이 존재하면
        {
            StopCoroutine(routine); //코루틴 정지
            routine = null; //코루틴 제거
        }
        routine = StartCoroutine(FadeAlpha(value, duration)); //코루틴 실행
    }
    private IEnumerator FadeAlpha(bool value, float duration = 1f) //알파값을 Fade하는 코루틴 함수
    {
        float t = 0f; //0부터 1까지 증가할 변수
        while (t < 1f) //t가 1보다 작으면 반복
        {
            alpha = Mathf.Lerp(value ? 0f : 1f, value ? 1f : 0f, t); //t와 value에 따라 알파값 갱신
            yield return null; //프레임 대기
            t = Mathf.Clamp01(t + Time.deltaTime / duration); //속도를 반영하여 t 증가
        }
        alpha = value ? 1f : 0f; //빠져나오기전 알파값 정리
    }
}

 

모든 렌더링이 끝난 뒤에 GL Drawing의 결과가 나타나므로,

Update가 아닌 OnPostRender 함수를 사용해야한다.

따라서, Camera 컴포넌트에 부착해야만 작동한다.

함수 내부에는 위에서 설명한대로 작성했다.

 

아래에는 페이드 효과를 실행하는 ToggleFade 함수와,

일정 시간 동안 알파값을 조절하는 FadeAlpha 코루틴 함수로 구성했다.

 

※ 직접 도형에 사용할 머터리얼을 지정할 수는 있지만, 동적으로 생성하는 것이 훨씬 편리하다.

※ 참고 : https://docs.unity3d.com/ScriptReference/GL.html

 

Unity - Scripting API: GL

Use this class to manipulate active transformation matrices, issue rendering commands similar to OpenGL's immediate mode and do other low-level graphics tasks. Note that in almost all cases using Graphics.RenderMesh or CommandBuffer is more efficient than

docs.unity3d.com


적용하기

Camera에 스크립트를 적용해주고,

Canvas에 두 개의 버튼을 배치한다.

using UnityEngine;
using UnityEngine.UI;

public class ToggleButton : MonoBehaviour
{
    public GLFade glFade; //GLFade 스크립트
    public Button toggleTrueBt; //Toggle True 버튼
    public Button toggleFalseBt; //Toggle False 버튼

    private void Awake()
    {
        /* 버튼 이벤트 추가 */
        toggleTrueBt.onClick.AddListener(() =>
        {
            glFade.ToggleFade(true, 2f);
        });
        toggleFalseBt.onClick.AddListener(() =>
        {
            glFade.ToggleFade(false, 2f);
        });
    }
}

위의 스크립트를 적용하여 버튼을 클릭했을 때 반응할 수 있도록 했다.


▼ 결과.gif


카메라에 직접 그리는 타입이다보니,

공간감있는 1인칭이나 VR 등의 환경에서 제약없이 활용할 수 있을 것 같다.

 

이번에는 페이드 효과를 위해 사각형만 사용했는데,

다음에는 다양한 응용 주제들을 가지고 글을 쓸 수 있을 것 같다.

댓글