누적 행렬 변환을 사용하여 짐벌 잠금 문제를 어떻게 해결합니까?


12

Jason L. McKesson의 온라인 "Learning Modern 3D Graphics Programming"책을 읽고 있습니다

현재 짐벌 잠금 문제와 쿼터니언을 사용하여 해결하는 방법에 달려 있습니다.

그러나 바로 여기, Quaternions 페이지에서 .

문제의 일부는 방향을 일련의 3 축 축 회전으로 저장하려고한다는 것입니다. 방향은 회전이 아니라 방향입니다. 그리고 방향은 확실히 일련의 회전이 아닙니다. 따라서 우리는 선박의 방향을 특정 수량으로 방향으로 취급해야합니다.

나는 이것이 혼란스러워지기 시작한 첫 번째 지점이라고 생각합니다. 왜냐하면 방향과 회전의 극적인 차이를 보지 못하기 때문입니다. 또한 방향을 일련의 회전으로 나타낼 수없는 이유를 이해하지 못합니다 ...

또한:

이 목적을 향한 첫 번째 생각은 방향을 행렬로 유지하는 것입니다. 방향을 수정해야 할 때이 행렬에 변환을 적용하여 결과를 새로운 현재 방향으로 저장합니다.

즉, 현재 방향에 적용된 모든 요, 피치 및 롤은 해당 현재 방향에 상대적입니다. 정확히 우리가 필요로하는 것입니다. 사용자가 양의 요를 적용하는 경우 일부 고정 좌표계가 아니라 현재의 위치를 ​​기준으로 요를 회전 시키려고합니다.

개념은 이해하지만 매트릭스 변환을 축적하는 것이이 문제에 대한 해결책인지 , 이전 페이지에 제공된 코드 가 그렇게 단순한 지 이해하지 못합니다.

코드는 다음과 같습니다.

void display()
{
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClearDepth(1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutil::MatrixStack currMatrix;
    currMatrix.Translate(glm::vec3(0.0f, 0.0f, -200.0f));
    currMatrix.RotateX(g_angles.fAngleX);
    DrawGimbal(currMatrix, GIMBAL_X_AXIS, glm::vec4(0.4f, 0.4f, 1.0f, 1.0f));
    currMatrix.RotateY(g_angles.fAngleY);
    DrawGimbal(currMatrix, GIMBAL_Y_AXIS, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
    currMatrix.RotateZ(g_angles.fAngleZ);
    DrawGimbal(currMatrix, GIMBAL_Z_AXIS, glm::vec4(1.0f, 0.3f, 0.3f, 1.0f));

    glUseProgram(theProgram);
    currMatrix.Scale(3.0, 3.0, 3.0);
    currMatrix.RotateX(-90);
    //Set the base color for this object.
    glUniform4f(baseColorUnif, 1.0, 1.0, 1.0, 1.0);
    glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));

    g_pObject->Render("tint");

    glUseProgram(0);

    glutSwapBuffers();
}

필자가 이해할 수있는 것은 (스택에서 행렬 수정) 행렬 누적을 고려한 것이 아닙니다. 작성자가 모든 개별 회전 변환을 스택 맨 위에 저장되는 하나의 행렬로 결합했기 때문입니다.

매트릭스에 대한 나의 이해는 그것들이 원점을 기준으로 한 점을 취하고 (모델이라고 말합시다) 다른 원점 (카메라)을 기준으로 만드는 데 사용된다는 것입니다. 나는 이것이 안전한 정의라고 확신하지만,이 짐벌 잠금 문제를 이해하지 못하게하는 무언가가 빠진 것처럼 느낍니다.

나에게 이해가되지 않는 한 가지는 : 행렬이 두 "공간"사이의 상대적인 차이를 결정하는 경우 롤에 대해 Y 축을 중심으로 회전하는 방법은 롤입니다. "이 롤과 관련하여 다시 한 번 변형 될 수 있습니다. 다시 말해서이 지점에 대한 추가 변환이이 새로운"롤 공간 "과 관련되어 있지 않으므로 회전이 이전" 짐벌 잠금을 일으키는 모델 공간 "

그것이 짐벌 잠금이 올바르게 발생하는 이유입니다. 자체 상대 축을 중심 으로 개체를 회전시키는 대신 설정된 X, Y 및 Z 축을 중심으로 개체를 회전시키기 때문 입니다. 아니면 내가 틀렸어?

분명히 내가 링크 한이 코드는 행렬 변환의 축적이 아니기 때문에이 방법을 사용하는 솔루션의 예를 제시 할 수 있습니다.

요약하면 다음과 같습니다.

  • 회전과 방향의 차이는 무엇입니까?
  • 코드가 행렬 변환 누적의 예가 아닌 이유는 무엇입니까?
  • 내가 잘못했다면 매트릭스의 실제적이고 구체적인 목적은 무엇입니까?
  • 행렬 변환 누적을 사용하여 짐벌 잠금 문제에 대한 솔루션을 어떻게 구현할 수 있습니까?
  • 또한 보너스로서 : 왜 회전 이후의 변환이 여전히 "모델 공간"과 관련이 있습니까?
  • 또 다른 보너스 : 변환 후 전류와 관련하여 추가 변환이 발생한다는 가정에서 틀린 것입니까?

또한 암시되지 않은 경우 OpenGL, GLSL, C ++ 및 GLM을 사용하고 있으므로 필요하지 않은 경우 이러한 관점에서 예제와 설명을 높이 평가합니다.

세부 사항이 많을수록 좋습니다!

미리 감사드립니다.

답변:


11

나는 그것이 머리말이 잘 어울리기를 희망하는 것 외에는, 이것을 서두르는 좋은 방법을 확신하지 못한다. 즉, 잠수하자 :

전자는 변환을 설명하고 후자는 상태를 설명하기 때문에 회전과 방향이 다릅니다. 회전은 객체가 방향 으로 향하는 방식이며 방향은 객체의 로컬 회전 공간입니다 . 이것은 수학적으로 두 좌표가 표현되는 방식과 직접 관련 될 수 있습니다. 행렬은 한 좌표 공간에서 다른 좌표 공간으로의 변환을 저장하고 (올바른 것을 가짐) 쿼터니언은 방향을 직접 설명합니다. 따라서이 행렬 은 일련의 회전을 통해 객체가 방향을 얻는 방법 만 설명 할 수 있습니다 . 그러나 이것의 문제는 짐벌 락입니다.

짐벌 잠금은 일련의 회전을 사용하여 객체를 방향으로 가져 오는 것이 어렵다는 것을 보여줍니다. 적어도 두 개의 회전축이 정렬 될 때 문제가 발생합니다.

deepmesh3d.com 제공 이미지
위의 왼쪽 이미지에서 파란색과 주황색 축은 같은 회전을합니다! 이것은 3 자유도 중 하나가 손실되었음을 의미하고이 지점에서 추가 회전하면 예기치 않은 결과가 발생할 수 있기 때문에 문제가됩니다. 쿼터니언을 사용하면 쿼터니언을 적용하여 객체의 방향을 변형하여 롤, 피치 및 요 작업으로 변환하지 않고 객체를 새로운 방향 (즉, 내가 말할 수있는 가장 좋은 방법)으로 직접 전환하기 때문에이 문제가 해결됩니다.

이제 행렬을 누적하는 것 (따라서 회전을 누적하는 것)이 짐벌 잠금 문제를 처음에 일으킬 수 있기 때문에 매트릭스에 대한 완전한 솔루션이되는 것에 대해 회의적입니다. 쿼터니언에 의한 변환을 처리하는 올바른 방법은 점에서 쿼터니언 곱셈을 수행하는 것입니다.

pTransformed = q * pAsQuaternion * qConjugate

또는 쿼터니언을 행렬로 변환하고 해당 행렬을 사용하여 점을 변환합니다.

일반 행렬 회전 (예 : 45도 요)은 항상 전역 공간에서 정의됩니다. 로컬 공간에서 변환을 적용하려면 변환을 해당 오브젝트 로컬 공간으로 변환해야합니다. 이상하게 들리므로 자세히 설명하겠습니다. 이것은 회전 순서의 중요성이 들어오는 곳입니다. 변형을 따라갈 수 있도록 여기에서 책을 가져가는 것이 좋습니다.

책을 평평한 상태에서 시작하여 덮개가 천장을 향하게하여 마치 책을 열거 나 읽는 것처럼 보이도록합니다. 이제 책의 앞면을 45도 기울입니다 (앞면 덮개가 사용자를 향해야합니다).

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(45);

이제 책의 요를 45도 조정하고 싶다고 가정 해 봅시다 (오른쪽 좌표계를 가정하고 있기 때문에 왼쪽으로 향하고 있다고 생각합니다). 책 표지가 여전히 당신을 향하도록 공간을 조정하십시오.

bookMatrix.RotateY(45);

문제는이 회전이 전체 좌표 공간에서 발생하므로 책의 표지가 오른쪽 어깨를 향하게됩니다. 로컬 좌표 공간에서 이러한 제목 변경이 발생하도록하려면 먼저이를 적용해야합니다!

glutil::MatrixStack bookMatrix;
bookMatrix.RotateY(45);
bookMatrix.RotateX(45);

사용해보십시오! 책이 천장에서 위로 향하게 다시 시작하십시오. 요 (yaw)를 45도 변경 한 다음 글로벌 X 축을 따라 45도 (왼쪽에서 오른쪽으로 실행)로 기울입니다. 책의 로컬 공간에서 피치 45와 요 45의 방향으로 예상 한 방향입니다.

이것은 무엇을 의미 하는가? 실제로 모든 것은 운영 순서가 중요하다는 것입니다. 먼저 수행 된 변환은 이후에 수행되는 변환의 맥락에서 로컬 변환이됩니다. 머리를 감싸는 것이 많이되어 쿼터니언이 많은 문제를 해결하는 방법입니다. 모든 주문 의존적 인 물건을 건너 뜁니다.

쿼터니언이 제공하는 다른 큰 장점은 방향의 보간을 허용한다는 것입니다. 순서 의존성 때문에 오일러 각도 사이의 보간을 시도하는 것은 거의 불가능합니다. 쿼터니언의 수학적 특성은 이들 사이에 잘 ​​정의 된 구형 선형 보간을 허용합니다.

정리하고 원래의 질문을 해결하기 위해 : 누적 행렬 변환은 변환이 신중하게 선택되고 정확한 순서로 적용되지 않는 한 실제로 짐벌 잠금 문제를 해결하지 못합니다. 따라서 항상 쿼터니언을 사용하고 쿼터니언 곱셈을 사용하여 점에 쿼터니언을 적용하십시오.

도움이 되었기를 바랍니다 :)


4
단지 기록을 위해, 쿼터니언은 오일러 각도를 통해 묘사 될 경우 여전히 짐벌 잠금 장치를 도입 할 수 있습니다. 당신은 다른 방식으로 같은 계산을 할 것입니다 (행렬이 아닌 쿼터니언)
concept3d

1
@ concept3d-이것을 언급 한 것을 축하합니다! 짐벌 메커니즘이 자유도를 잃기 쉬운 이유를 이해하는 것이 중요합니다. 본질적으로 과도하게 결정된 방정식 시스템을 설명하는 로봇 조인트와 같습니다. 쿼터니언, 행렬 또는 마술로이 메커니즘을 구축하는 경우에도 여전히 모호함이 생길 수 있습니다.이를 이해하고 실제 솔루션 인 첫 번째 장소에서는 사용하지 않습니다. .
teodron

쿼터니언은 상상하기 어렵습니다. 제가 항상 생각하는 방식은 쿼터니언이 3 구 공간을 나타내므로 어떤 방향이든 나타낼 수 있다는 것입니다. 오일러 각도는 각각 원 / 토르를 나타내는 것으로 이해합니다. 방향을 나타내는 매우 정확한 방법은 아닙니다 (
유러

1

매트릭스 축적은 실제로 짐벌 락을 해결할 수 있습니다. 회전이 누적되면 짐 벌이 추가되어 임의의 회전이 가능합니다. ktodisco가 제공 한 다이어그램은 왼쪽 다이어그램의 짐벌 잠금 장치를 보여줍니다. 이 방향에 대한 행렬은 다음과 같이 정의 할 수 있습니다.

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(90);
bookMatrix.RotateY(90);
bookMatrix.RotateZ(90);

y 짐벌 회전으로 인해 X 및 Z 짐 벌이 잠기므로 1 도의 움직임을 잃었습니다. 이 시점에서이 세 가지 짐벌을 사용하여 요잉 (로컬 y, 글로벌 z)이 없습니다. 그러나 다른 짐벌을 추가하면 y를 중심으로 회전 할 수 있습니다.

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(90);
bookMatrix.RotateY(90);
bookMatrix.RotateZ(90);
bookMatrix.RotateY(90);

모든 새로운 롤, 피치 및 요에 대해 다른 짐벌을 추가하여 하나의 매트릭스에 적용하십시오. 따라서 다른 로컬 회전이 필요할 때마다 회전이 생성되어 누적 행렬에 곱해집니다. 이 장에서 언급했듯이 여전히 문제가 있지만 짐벌 잠금은 그중 하나가 아닙니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.