개발/Unity

유니티 - OpenGL로 멀티 터치 이펙트 만들기 (Simple Screen Multi Touch Effect with Unity GL)

피로물든딸기 2023. 7. 10. 20:00
반응형

Unity 전체 링크

 

참고

- 유니티 GL로 화면에 그림 그리기

- OpenGL로 화면에 선 그리기

- OpenGL로 화면 터치 이펙트 만들기

- 멀티 터치 드래그를 이용하여 카메라 줌 인 / 아웃

- 멀티 터치 드래그로 오브젝트 크기 변경하기

 

화면 터치 이펙트를 만들었다면, 이제 멀티 터치 효과도 만들어보자.

아래는 여러 개의 손가락으로 화면을 터치한 것을 녹화하였다.

 

여러 개의 원을 만들어야 하기 때문에 원을 만드는 부분을 함수로 분리한다.

    void makeCircle(Vector3 touchPos, Color color)
    {
        GL.Color(color);

        List<Vector3> pos = new List<Vector3>();

        for (int i = 0; i < numberOfTriangle; i++)
        {
            float angle = i * (Mathf.PI * 2.0f) / numberOfTriangle;

            Vector3 dot = (new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0)) * radius;

            float width = (float)Screen.width;
            float height = (float)Screen.height;

            if (width > height)
            {
                dot.x = dot.x * height / width;
            }
            else
            {
                dot.y = dot.y * width / height;
            }

            pos.Add(dot + touchPos);
        }

        for (int i = 0; i < numberOfTriangle - 1; i++)
        {
            GL.Vertex3(touchPos.x, touchPos.y, 0);
            GL.Vertex3(pos[i + 1].x, pos[i + 1].y, 0);
            GL.Vertex3(pos[i].x, pos[i].y, 0);
        }

        GL.Vertex3(touchPos.x, touchPos.y, 0);
        GL.Vertex3(pos[0].x, pos[0].y, 0);
        GL.Vertex3(pos[numberOfTriangle - 1].x, pos[numberOfTriangle - 1].y, 0);
    }

 

모바일 화면의 터치 횟수에 따라 색을 다르게 하기 위해 colorSet을 선언하고, 각 좌표를 makeCircle에 넘기면 된다.

    int touchCount = touchPosList.Count;

    Color[] colorSet = new Color[] { Color.red, Color.green, Color.blue };

    for (int i = 0; i < touchCount; i++)
        makeCircle(touchPosList[i], colorSet[i % 3]);

 

Input.touchCount로 화면을 터치하고 있는 손가락의 개수를 알 수 있다.

이제 Update에서 Input.GetTouch를 이용해서 화면에 터치된 모든 좌표를 List에 저장하면 된다.

    void Update()
    {
        if (Input.GetMouseButton(0))
        {
            touchPosList = new List<Vector3>();

            int touchCount = Input.touchCount;
            for (int i = 0; i < touchCount; i++)
            {
                Vector3 inputPos = Input.GetTouch(i).position;

                Vector3 mousePos
                    = new Vector3(inputPos.x, inputPos.y, -Camera.main.transform.position.z);

                Vector3 touchPos = Camera.main.ScreenToViewportPoint(mousePos);

                touchPosList.Add(touchPos);
            }

            touchFlag = true;
        }
        else
        {
            touchFlag = false;
        }
    }

 

참고로 Input.GetTouch모바일 화면에서만 동작한다.

 

전체 코드는 다음과 같다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MobileTouch : MonoBehaviour
{
    Material mat;
    bool touchFlag;
    List<Vector3> touchPosList;

    int numberOfTriangle = 10;
    float radius = 0.1f;

    void makeCircle(Vector3 touchPos, Color color)
    {
        GL.Color(color);

        List<Vector3> pos = new List<Vector3>();

        for (int i = 0; i < numberOfTriangle; i++)
        {
            float angle = i * (Mathf.PI * 2.0f) / numberOfTriangle;

            Vector3 dot = (new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0)) * radius;

            float width = (float)Screen.width;
            float height = (float)Screen.height;

            if (width > height)
            {
                dot.x = dot.x * height / width;
            }
            else
            {
                dot.y = dot.y * width / height;
            }

            pos.Add(dot + touchPos);
        }

        for (int i = 0; i < numberOfTriangle - 1; i++)
        {
            GL.Vertex3(touchPos.x, touchPos.y, 0);
            GL.Vertex3(pos[i + 1].x, pos[i + 1].y, 0);
            GL.Vertex3(pos[i].x, pos[i].y, 0);
        }

        GL.Vertex3(touchPos.x, touchPos.y, 0);
        GL.Vertex3(pos[0].x, pos[0].y, 0);
        GL.Vertex3(pos[numberOfTriangle - 1].x, pos[numberOfTriangle - 1].y, 0);
    }
    void OnPostRender()
    {
        if (!mat)
        {
            Debug.LogError("Please Assign a material on the inspector");
            return;
        }

        if (touchFlag)
        {
            GL.PushMatrix();
            mat.SetPass(0);

            GL.LoadOrtho();

            GL.Begin(GL.TRIANGLES);

            int touchCount = touchPosList.Count;

            Color[] colorSet = new Color[] { Color.red, Color.green, Color.blue };

            for (int i = 0; i < touchCount; i++)
                makeCircle(touchPosList[i], colorSet[i % 3]);

            GL.End();
            GL.PopMatrix();
        }
    }

    void Start()
    {
        mat = new Material(Shader.Find("Draw/Quads"));
    }

    void Update()
    {
        if (Input.GetMouseButton(0))
        {
            touchPosList = new List<Vector3>();

            int touchCount = Input.touchCount;
            for (int i = 0; i < touchCount; i++)
            {
                Vector3 inputPos = Input.GetTouch(i).position;

                Vector3 mousePos
                    = new Vector3(inputPos.x, inputPos.y, -Camera.main.transform.position.z);

                Vector3 touchPos = Camera.main.ScreenToViewportPoint(mousePos);

                touchPosList.Add(touchPos);
            }

            touchFlag = true;
        }
        else
        {
            touchFlag = false;
        }
    }
}

 

반응형