[ 2025 03 06 ] 다수 버텍스 그래픽 처리를 위한 최적화 방법 - Whitmem
[ 2025 03 06 ] 다수 버텍스 그래픽 처리를 위한 최적화 방법
Graphic History
2025-03-06 23:14 게시 7f8f52ca8a766656a186

0
0
47
이 페이지는 외부 공간에 무단 복제할 수 없으며 오직 있는 그대로 게시되며 부정확한 내용을 포함할 수 있습니다. 법률이 허용하는 한 가이드 라인에 맞춰 게시 내용을 인용하거나 출처로 표기할 수 있습니다.
This page is not to be distributed to external services; it is provided as is and may contain inaccuracies.
다수 버텍스 그래픽 처리를 위한 최적화 방법
본 게시글은 2D, 3D 그래픽스 처리를 위해 필자가 고민하고 공부한 내용을 정리한 것으로, 정확성을 보장하지 아니한다.
필자는 공부하는 모든 것들을 기록하는 내부 클라우드를 사용해오고 있고, 이는 모두 텍스트 기반의 문서를 기록할 수 있는 필드로 구현되어 있다. 하지만 최근 음악 공부를 함에 있어서, 음표를 그리거나 펜으로 작성하여 기록하는 기능이 필요했으며, 이를 사이트 기반으로 구현하고자 하였다.
유일하게 쉬워보이지만 성능 최적화가 사실상 고난도라 접근하지 못한 부분이기에 더 해결하고픈 욕망이 있다.
이미 최적의 성능으로 벡터 그림을 그릴 수 있는 그래픽 소프트웨어 및 앱이 잘 나와있지만, 내 사이트에 실시간 연동할 수 없다는 문제가 존재한다. 따라서 웹 사이트에서 그래픽 API를 사용해 벡터 기반 버텍스를 처리하고 그리고, 지울 수 있는 그런 기능을 구현하고자 하였다.
기술 고민
보통의 그림 소프트웨어들을 보면 벡터 처리가 아닌 레스터화 된 이미지로 기록된다.
여기서 지우개로 일부분을 지워주면, 해당 영역만 지워진다.
일단 나에게는 이러한 방식은 적합하지 않았다. 그림 소프트웨어를 만드는 것이 목표가 아니라, 필기 사이트를 만드는 것이 목표였기 때문에, 벡터 기반으로 처리할 필요가 있었다. 즉 그려지는 이 모든 정점 정보를 메모리에 기록하고 있다가 사용자가 다시 그리기 요청을 할 때 재빠르게 화면에 그려내는 것. 그것이 나의 기술 과제였다.
드로잉 방식
대충 글만 적을 수 있도록 구현하는 것이 목표였다면, 굳이 그래픽스 API가 아니라 Canvas 수준에서 제공되는 DrawLine 을 사용해도 무방하다. 하지만 이러한 작업들은 선을 커스터마이징 할 수 없을 뿐더러 대량 벡터를 처리하다보면 반드시 성능 문제에 직면한다. 이것이 내가 몇 년간 선 관련 소프트웨어를 구현하지 못한 이유다. 처음에는 그럴싸하다가, 선을 이리저리 긋다보면 버벅이는 문제, 어떤 방법을 써도 해결할 수 없었다. 그 이유는 접근 방법이 잘못 되었기 때문이다. 대량의 벡터를 실시간으로 그리고 처리하기 위해서는 반드시 그래픽스 라이브러리와 이를 다시 최적화할만한 눈속임 방법이 필요했다.
일반 캔버스에 그리기 효과를 구현하면 위와 같다. 마우스가 지나가는 부분을 사각형으로 찍어주거나 DrawLine 해주면 된다.
위 이미지를 보면 각 경계가 사각형으로 예쁘지 않은 것을 확인할 수 있으며, 드로우가 끝나는 부분이 눈이 아프게 에일리어싱 현상이 발생하는 것을 확인할 수 있다.
따라서 원하는 브러시 모양을 구현하기 위해서는, 브러시 텍스처를 만든 뒤, 선위에 단순히 사각형이 아니라, 텍스처를 씌워주는 작업이 필요했다.
임의로 둥근 브러시를 만든 뒤에, UV 좌표를 지정해준다. UV 좌표는 2D 그래픽스에서 텍스처를 띄우는 텍스처 좌표계이다. 우선 기본적으로 이 이미지를 4등분으로 나눈 뒤, 선이 그려지는 방향 벡터로 중간 UV 영역을 계속 무한히 반복하고, 시작 지점, 끝 지점에만 앞 부분 UV 영역과 뒷 부분 영역을 온전히 처리해주면 된다.
즉 위와 같은 UV 영역이 있을 때, 원하는 시작 라인과 끝 라인을 엮을 때 UV를 그대로 적용하면 아래와 같이 된다.
따라서 반복이 시작되는 좌표 정점에 UV를 0.5로 지정하여 반복이 되도록 구현한다.
즉 아무리 무수히 긴 선이라한들, 버텍스는 8개있으면 된다. 삼각형이 6개 그려지고, 그 위에 텍스처가 씌워지는 것이다.
즉 그리고자 하는 두 직선 빨간점이 있을 때 반지름 5만큼을 그리려면, 각 빨간점으로부터 5 떨어진 수직선으로 정점을 하나 구하고, 이로부터 다시 UV 절반만큼 빠지는 위치의 정점, 끝 지점의 빨간 점에도 똑같은 작업을 진행해주어 그림이 그려지는 평면 버텍스를 생성할 수 있다.
이러한 작업은 빨간점에서 그려지는 선의 방향 벡터를 구한 뒤에, 그 방향 벡터의 외적 벡터 2개를 구한 뒤, 빨간 점에서 덧셈 해주면 된다.
이제 브러시 크기를 조절하려면 각 정점에서 면이 생성되는 정점 길이만 조절해주면 되는 것이다.
이제 텍스처를 씌워주면 그럴싸한 브러시가 적용된 선이 그려지는 것을 확인할 수 있다.
지우기 구현
선분과 정점간의 거리 공식을 사용해서, 마우스 범위에 도달한 경우 (사실은 3D 공간이기 때문에 역투영 처리가 필요하다. Z 깊이가 없으므로 임의 0으로 지정하여 역투영하였다.) 해당 지점에 존재하는 선분 벡터를 지우도록 구현한다. 지워진 경우 다시 그래픽 렌더링을 수행한다.
해당 선을 한번에 지우게끔 구현이 가능하다.
최적화 문제
아직 빠지지 않은 한 가지 문제가 존재하는데, 바로 최적화 문제이다. 그리거나 지울 때 마다 버텍스를 다시 렌더링해야 한다는 문제가 존재할 뿐더러, 이미 그려진 것은 이미지 메모리로 적재한다고 하더라도 버텍스가 많아지면 많아질 수록 새로고침하는데 많은 시간이 소요되는 문제가 존재하였다.
그리는 내용이 많아질수록 그릴 때 마다 연산해야 할 양은 늘어나기 때문에, CPU로 처리하는데 한계가 존재한다. 따라서 그리는 정점들을 한 메시가 아닌, 버텍스에 임의로 추가하고, 관리하는 방법을 택했다.
수 많은 정점들을 렌더링하기 위해서 기본적으로 반복처리를 수행하는데, 이는 CPU 프로세서 단에서 수행된다. 즉 CPU 프로세서 단에서 DrawCall을 그래픽카드로 보내고, 그래픽 카드가 이 요청을 받아 화면상에 출력을 수행하는데, DrawCall이 많으면 많아질 수록 CPU의 부담이 심해진다. 즉 그래픽은 병렬 연산을 수행할 수 있지만, 메시가 모두 분할화되어 있는 경우 DrawCall만 하느라 CPU 부담만 커진다. 그렇기 때문에 VertexBuffer에 직접 Vertex 를 삽입하고, 정점 정보를 공유하는 IndexBuffer을 수동으로 삽입하고, UV 정보를 수동으로 삽입하여 최종적으로 하나의 메시에 여러 버텍스가 공유되도록 하였다.
이 과정에서 offset 정보가 유실되지 않도록 별도 객체를 만들어 관리를 해 줘야 한다. Index 정보는 Vertex의 Offset에 상대적이기 때문이다. 그 결과 대량의 선을 그리는데에도 전혀 성능상 문제가 없는 사이트를 만들 수 있었다. 다음은 조금 더 최적화를 하기 위해 텍스처 교체 방법을 탐구해보고자 한다. 끝.
댓글 0개
댓글은 일회용 패스워드가 발급되며 사이트 이용 약관에 동의로 간주됩니다.
확인
Whitmemit 개인 일지 블로그는 개인이 운영하는 정보 공유 공간으로 사용자의 민감한 개인 정보를 직접 요구하거나 요청하지 않습니다. 기본적인 사이트 방문시 처리되는 처리 정보에 대해서는 '사이트 처리 방침'을 참고하십시오. 추가적인 기능의 제공을 위하여 쿠키 정보를 사용하고 있습니다. Whitmemit 에서 처리하는 정보는 식별 용도로 사용되며 기타 글꼴 및 폰트 라이브러리에서 쿠키 정보를 사용할 수 있습니다.
이 자료는 모두 필수 자료로 간주되며, 사이트 이용을 하거나, 탐색하는 경우 동의로 간주합니다.