위 Gizmo 구현에서는 RayTrace 를 통해 Gizmo Picking 및 Gizmo Manipulating 을 구현한다. 이에 관한 수식은 위 블로그에 잘 정리되어 있어 따로 기록하진 않는다.(단 closest_distance_between_lines() 의 6번째 줄은 오타로 보인다. v1v2 * v1v2 - v12 * v22 부분은 빼기 순서가 잘못되어 부호가 반대로 나온다.) 여기선 이를 이용한 구현에 대해서 설명해보려고 한다.
설명
Cache
Gizmo 조작 시 저장할 데이터들이다.
Gizmo 조작 시작 시 기준이 되는 SRT 와 Axis 정보를 저장하고, 시작 지점의 RayTrace 결과를 저장한다. World 공간에서 조작할 건지 Local 공간에서 조작할 건지는 이때 저장하는 정보로 결정된다.
추가로 다음의 변수가 중요하게 사용된다.
Gizmo Model 의 Scale 값인 screen_scl 은 약간의 설명이 필요하다.
Gizmo 의 크기가 항상 동일하게 보이기 위해선 Gizmo 위치를 Camera 의 View 행렬로 곱해서 얻은 깊이 값을 Gizmo Model 의 Scale 에 곱하면 된다. ViewProj 과정에서 이 깊이 값으로 (X, Y, Z) 을 나누기 때문에 미리 곱해놓으면 좌표가 깊이와 상관없이 일정한 값이 되기 때문이다. 이러한 깊이 값과 화면 상의 크기 비율인 SCREENED_SIZE 를 곱한 값이 screen_scl 에 저장된다.
Update
위 코드는 마우스를 클릭해 Gizmo 조작을 시작할 때 수행된다.
재미있는 부분은 ClosestDistanceBetweenRays() 의 결과로 나오는 t2 의 성질이다.
이 함수는 (ray1.pos + ray1.dir * t1) - (ray2.pos + ray2.dir * t2) 의 절댓값을 최솟값으로 만드는 미지수 t1, t2 를 구한다. ray2.dir 은 Gizmo 의 Axis 중 하나이므로 t2 는 Gizmo 의 축 상의 위치가 된다.
그래서 0 <= t2 && t2 <= screen_scl 은 화면 상에서 SCREENED_SIZE = 0.1f 길이에 해당되는 범위가 된다. Gizmo Model 의 크기가 1 이면 이는 곧 Gizmo 의 길이가 된다.
구해진 최소거리인 min_dist 는 MAX_DIST * screen_scl 보자 작아야한다. 이유는 위와 비슷하다. Axis 에 닿았다고 판정할 거리가 화면 상에서 균등토록 하기 위함이다.
Rotate 의 경우는 위와 비슷하게 구현했다. 원은 직선과 달리 크기에 한계가 있어서 min_dist < MAX_DIST * screen_scl 만 체크해주면 되므로 더 간단하다.
위 코드는 초기값을 저장한 후 Gizmo 조작 중에 매 틱마다 호출된다. RayTrace 를 수행하여 그 결과값을 초기값과 비교해 Target 의 Transform 을 업데이트하는 역할을 한다.
위와 달리 매 틱마다 Delta 를 구하는 방식을 쓸 수도 있다. 하지만 틱이 너무 빠르면 Delta 가 항상 0 이 되어 이를 또 처리해줘야하고, 만약 훗날에 Command 패턴으로 Redo/Undo 를 구현한다면 구현이 난해해질 수가 있어 이쪽이 더 바람직할 것이다.
댓글남기기