0130
2026년 1월 30일
카테고리 : 게임엔진, 3D기즈모

3D 기즈모를 만들어 보았다.
완벽하지는 않지만,
상태가 Pos / Rot 로 된 각 경우
마우스에 따라서 위치 / 회전을 바꿀 수 있다.
그거, 물체 주변에 축 기즈모랑
¼ 원 3개 띄우는거를 만들어야 한다.
물론 오브젝트 피킹으로 끝나는 게 아니라
기즈모 자체도 피킹 검사를 해야한다.
위치 조정은 이렇게 시작한다.
if (dragging) {
pos_offset_deferred.x = ComputeTranslationAlongAxis(
cam3d->get_world_position(),
cam3d->get_view_matrix().get_matrix(),
cam3d->get_projection_matrix().get_matrix(),
cursor_start,
get_screen_mouse_position(),
cube->get_world_position(),
{ 1.0f, 0.0f, 0.0f },
cam3d->get_projection_size()
).x;
// z축도 함께.
pos_offset_deferred.z = ComputeTranslationAlongAxis(
cam3d->get_world_position(),
cam3d->get_view_matrix().get_matrix(),
cam3d->get_projection_matrix().get_matrix(),
cursor_start,
get_screen_mouse_position(),
cube->get_world_position(),
{ 0.0f, 0.0f, 1.0f },
cam3d->get_projection_size()
).z;
}
어딘가에서 긁어온 ComputeTranslationAlongAxis 함수를 설명해보겠다.
glm::vec3 ComputeTranslationAlongAxis(
const glm::vec3& cameraPos,
const glm::mat4& viewMatrix,
const glm::mat4& projectionMatrix,
const glm::vec2& mousePosStart,
const glm::vec2& mousePosEnd,
const glm::vec3& objectPos,
const glm::vec3& axis,
const glm::vec2& viewportSize)
{
glm::vec3 rayStartDir = ScreenToWorldRay(mousePosStart, viewMatrix, projectionMatrix, viewportSize);
glm::vec3 rayEndDir = ScreenToWorldRay(mousePosEnd, viewMatrix, projectionMatrix, viewportSize);
glm::vec3 p1 = cameraPos;
glm::vec3 p2 = cameraPos + rayStartDir * 1000.0f;
glm::vec3 q1 = cameraPos;
glm::vec3 q2 = cameraPos + rayEndDir * 1000.0f;
glm::vec3 delta = q2 - p2;
float projected = glm::dot(delta, axis);
return axis * projected;
}
먼저, 뷰 행렬과 투영 행렬을 받기 때문에
스크린 공간의 '마우스 시작위치', '마우스 끝 위치' 를 가지고,
3차원 월드 공간에서의
광선 2개를 정의한다.
월드 카메라 위치를 기준으로,
'처음 드래그를 시작한 커서위치 기반 광선' 하나와
'현재 드래그하면서 실시간으로 갱신된 커서위치 기반 광선' 하나를 만든다.
그리고 (후자 - 전자) 해서 delta 만들고,
걍 이걸 단위 벡터에다가 투영하면 된다.
별거 없다.
시각화하면 밑에처럼 된다.
참고로 X축 (1, 0, 0) 에다가 투영하는 상황이고,
XZ 평면을 위에서 바라본 시점이다.
