0425
2025년 4월 25일
카테고리: 게임엔진, UI 컴포넌트 개발

조금 머리가 많이 아팠다.
그니까 상황이 이랬다.
나는 처음에 Godot에 있는 콘테이너를 보면
콘테이너를 삐져나간 오브젝트(예 : 버튼)의 영역에 대해서는
- 마우스로 안눌린다
- 콘테이너 영역 이후부터 보이지 않는다.
이런 특성이 있다는 걸 알고 있었다.
이걸 (특히 안 보이는 2번 기능) 구현해 보려 했는데,
처음에는 가장 먼저 떠오른 게
glScissor였어서 걍 그거 쓰지 뭐 했다.
근데 생각해보니까, 얼마 전에
카메라가 회전할 수도 있지 않나?
그렇게 되면 UI 자체가 회전하는 상황이 없더라도,
카메라가 회전하면 UI가 스크린에 사각형의 형태로 그려진다는
보장이 깨진다.
이걸 어떻게 타파하지?
나는 카메라가 회전하거나 줌인아웃되어도
1번 충돌영역 클리핑과 2번 렌더영역 클리핑
이 기능을 꼭 넣고 싶었다.
하지만 glScissor는 말 그대로
자르긴 자르는데 그게 Window Space다.
즉 사각형으로밖에 못자른다.
그래서 생각해낸게
스텐실 마스킹인데,
스텐실이면 사각형 영역 겹칠 수도 있고
회전이나 줌도 자유로웠지만,
- 코드가 너무 더럽다.
- 이때 클리핑이 255번(스텐실버퍼 한계점) 이상 되는 경우를 구현 못했는데 그런 특수한 상황 만들기 싫었다.
아무튼 그랬는데
결국 답을 찾았다.
근데 그 답이 너무 간단했다.
분명 효과적인 답은 아니지만, 직관적이다.
바로 Frag 셰이더 내에서
'월드 기반' 클리핑 rect를 받아서
'월드 기준 점' 이 그 rect안에 없다면
그 픽셀을 discard하는 것이다.
난 이 기술을 Dynamic Scissor라고 이름붙였고
아무리 생각해도
"회전하는 카메라에도 잘 작동하는 UI"
라는 장점 1개밖에 없어서
컴파일 타임에 옵션으로 넣기로 했다.
그러나 아무리 장점1개라도,
난 저게 너무 구현하고싶엇다.
또 나중 가서 안 건데,
Godot의 renderdoc 캡쳐에서는 예상대로 glScissor를 쓰길래
카메라가 회전하면 클리핑이 어케되는지 봤는데,
ㅋㅋㅋ고장남ㅋㅋㅋ
Conatainer안에 버튼 여러개 넣고 2D 카메라를 회전해 보면
scissor영역은 스크린 기반이라서
이상하게 됨.
(고도 4.0.1이었던걸로 기억함)
그러나?
-> GUI 를 쓸 때에는,
GUI 오브젝트 자체가 회전하거나,
카메라가 회전한다는 상황 자체를 만들지 않는게 맞음.
위에서 구현했던 world clipping rect를 FS에 넘기는 방식이
왜 좋냐면,
Rect는 교집합 연산을 쓰면
내 엔진에 구현된 parent-child 구조에 따라서
"여러 개의 콘테이너"와 그 자식에 대한
콜리젼 감지 영역을 쉽게 추출할 수 있기 때문이다.
(당연히 push / pop 이 있는 stack 기반이며
이는 부모가 콘테이너일때 update / draw에서
push_clipping_area -> 자식 update / draw -> pop_clipping_area 하는 식이다.)
왜 어렵게 생각했을까?
문득 떠오른 생각이 가장 적절하고
내 엔진에도 잘 맞다니.
또한 2D에디터에 스케일도 바꿀 수 있게 함.