2016-08-23 6 views
0

OpenGL에서 제어 가능한 공을 만들려고합니다. 내 자신의 행렬 클래스를 사용하여 객체 행렬을 변환하지만 Rotation 권한을 얻을 수없는 것 같습니다. 나는 항상 로컬 축을 중심으로 회전하는 공으로 끝납니다. 이것은 지금 보이는 방법입니다. https://gfycat.com/LongKindBassethound. 긴 선은 로컬 축입니다.세계 축을 중심으로 한 물체의 회전 OpenGL

그래서 공이 앞으로 움직이면 다음 사이드 운동이 잘못 될 것입니다.

Matrix& Matrix::rotationAxis(const Vector& Axis, float Angle) { 
const float Si = sin(Angle); 
const float Co = cos(Angle); 
const float OMCo = 1 - Co; 
Vector Ax = Axis; 
Ax.normalize(); 

m00= (Ax.X * Ax.X) * OMCo + Co; 
m01= (Ax.X * Ax.Y) * OMCo - (Ax.Z * Si); 
m02= (Ax.X * Ax.Z) * OMCo + (Ax.Y * Si); 
m03= 0; 

m10= (Ax.Y * Ax.X) * OMCo + (Ax.Z * Si); 
m11= (Ax.Y * Ax.Y) * OMCo + Co; 
m12= (Ax.Y * Ax.Z) * OMCo - (Ax.X * Si); 
m13= 0; 

m20= (Ax.Z * Ax.X) * OMCo - (Ax.Y * Si); 
m21= (Ax.Z * Ax.Y) * OMCo + (Ax.X * Si); 
m22= (Ax.Z * Ax.Z) * OMCo + Co; 
m23= 0; 

m30= 0; 
m31= 0; 
m32= 0; 
m33= 1; 

return *this; 
} 

나는 결과를 중심으로 회전 한 후 나는 세상의 방향 벡터를 가지고 객체의 로컬 공간을 변형 할 수있다이 함께 생각하고 : 어떤 축을 중심으로 회전 할 수 있습니다 매트릭스 클래스에서 함수를 프로그래머. 나는 그것을하는 방법을 정말로 모르지만 (공의 행렬 * 월드 벡터? 작동하지 않는다). 나는 쿼터니언을 피하고 싶습니다.하지만 그렇게 할 수 없다면 나는 그 방향으로 제안을 높이 평가할 것입니다.

편집 : 추가 정보

트랜스 포메이션 코드. 당신이 볼 수 있듯이 나는 모두 똑같이하는 다른 방법을 시도했다. 그래서 놀랄 일은 없다. 내 이전 시도가 glRotatef를 사용하려고 시도와

Matrix transM, rotX, rotZ; 
rotationX = straight; 
rotationZ = side; 
if (velocity != Vector(0, 0, 0)) { 
    velocity.X = -0.0005 * DeltaTime; 
    velocity.X = clamp(velocity.X, 0, FLT_MAX); 

    velocity.Z = -0.0005 * DeltaTime; 
    velocity.Z = clamp(velocity.Z, 0, FLT_MAX); 
} 

velocity.X += speed * -side * DeltaTime; 
velocity.Z += speed * straight * DeltaTime; 
transM.translation(velocity.X, 0, velocity.Z); 

if (velocity.Z != 0 || velocity.X != 0) { 
    //http://mathworld.wolfram.com/EulerAngles.html 
    //http://gamedev.stackexchange.com/questions/67199/how-to-rotate-an-object-around-world-aligned-axes 

    Vector localAxisX = m_Ball * Vector(1, 0, 0); 
    Vector localAxisZ = m_Ball * Vector(0, 0, 1); 
    rotX.rotationAxis(Vector(1, 0, 0), 0.5* M_PI * straight * DeltaTime); 
    rotZ.rotationAxis(Vector(0, 0, 1), 0.5* M_PI * side * DeltaTime); 
    //rotX.rotationX(0.5* M_PI * straight * DeltaTime * 3); 
    //rotZ.rotationZ(0.5* M_PI * side * DeltaTime * 3); 
    //Matrix fullRotation.rotationYawPitchRoll(Vector(0, 0.5* M_PI * straight * DeltaTime, 0.5* M_PI * side * DeltaTime)); 
    m_Ball = transM * m_Ball * (rotX*rotZ); 
} 
else { 
    m_Ball = transM * m_Ball; 
} 

그리기 코드는

void Ball::draw(float DeltaTime) { 
    glPushMatrix(); 
    glMultMatrixf(m_Ball); 
    if(rotationX) 
    glRotatef(0.5* M_PI * rotationX * DeltaTime, 1.0, 0.0, 0.0); 
    if(rotationZ) 
    glRotatef(0.5* M_PI * rotationZ * DeltaTime, 0.0, 0.0, 1.0); 
    g_Model_ball.drawTriangles(); 
    glPopMatrix(); 
    drawAxis(); 
} 
+1

이 함수를 호출하는 위치에서 드라이버 코드를 게시하십시오. 둘째, 자신의 회전 함수를 수정하기위한 요구 사항이 있습니까? –

+0

추가 정보로 편집 – lega

+0

OpenGL 변환이 어떻게 작동하는지 이해하려면이 기사를 참조하십시오. –

답변

1

내가보기 엔 쉽게 복합 회전을 처리하고 짐벌 잠금을 방지하기 위해 사원 수를 사용하는 것이 좋습니다 (분명 지금 주석). 여러분의 의견과 비디오에 관해서 확인

https://en.wikipedia.org/wiki/Gimbal_lock

는, 당신은 볼의 중심을 회전합니다. m_Ball에 회전을 축적 한 것 같지만 이상한 transM 곱셈을 수행합니다. 또한 transM에 번역이 누적되어 있습니다.

번역본과 회전을 섞지 말고 m_Ball에 누적되지 않도록하십시오. 이런 식으로 할 수 있습니다.

//transformation matrix 
transM.translation(velocity.X, 0, velocity.Z); 

//accumulate translations in m_BallT 
m_BallT = transM * m_BallT; 

//final Rotation 
Matrix rotation = rotX * rotZ; 

//accumulate rotations in m_BallR 
m_BallR = rotation * m_BallR; 

//now compute your final transformation matrix from accumulated rotations and translation 
m_Ball = m_BallT * m_BallR; 

참고 어떻게 m_BallR이 누적 된 회전인지 만 확인하십시오. 곱셈 후 m_BallR에 누적 된 회전 후에 새로운 rotation이 적용됩니다. 마지막으로 m_BallT에 누적 된 최종 포지션으로 변환됩니다. 공은 센터를 중심으로 회전하고 m_BallT에 따라 이동합니다.

여분의 행렬 곱셈을 피하기 위해 m_BallR의 변환 구성 요소를 간단히 바꿀 수도 있습니다.

+0

내 게시물을 편집했습니다. 내가 너를 정확하게 이해한다면 나는 이미 그렇게하고 있다고 확신한다. – lega

+0

나는 당신이 그렇게 생각하지 않는다. 공에서 세계 공간 위치를 추출하고, 회전 행렬로 그 위치 벡터를 회전시킨 다음 공을 새로운 위치로 이동시킨다. 복합 회전 행렬에 볼의 행렬을 곱하지 마십시오. – Harish

+0

https://gfycat.com/BowedCaringArkshell 귀하의 접근 방식을 사용할 때 이것이 결과입니다. 내 목표는 다음과 같습니다. https://gfycat.com/LongKindBassethound with appropriate rotation – lega

0
Vector newPos(m_Ball.translation().X + velocity.X, terrainNoise.GetHeight(m_Ball.translation().X, m_Ball.translation().Z) + 0.5, m_Ball.translation().Z + velocity.Z); 

rotX.rotationAxis(Vector(1, 0, 0), 0.5* M_PI * straight * DeltaTime * abs(velocity.Z) * 100); 
rotZ.rotationAxis(Vector(0, 0, 1), 0.5* M_PI * side * DeltaTime * abs(velocity.X) * 100); 

m_Rotation = (rotX*rotZ); 

m_Ball = (m_Ball.invert() * m_Rotation).invert(); 


m_Ball.m03 = newPos.X; 
m_Ball.m13 = newPos.Y; 
m_Ball.m23 = newPos.Z; 

@Spektre가 제공 한 this 링크를 읽은 후 생각해 낸 해결책입니다. 기본적으로 공의 ModelMatrix를 반전하여 세계 위치로 가져 와서 회전 한 다음 다시 로컬 공간으로 변환합니다.

회전하기 전에 newPos Vector를 설정해야합니다. 그렇지 않으면 향후 변형에 영향을 미칩니다.

+0

회전과 번역을 별도로 누적하면 행렬 역전을 피할 수 있습니다. 더 효율적입니다. 번역 벡터를 덮어 쓰기 때문에 실제로는 회전과 크기 만 반전합니다. – Harish

+0

@ 하리 쉬 (Harish)는 실제로 많은면에서 반대입니다. 그런 식으로 임의의 변형을 쌓을 수는 없습니다. btw 역변환은 직교 homogenouos 변환 행렬이 'transpose()'처럼 쉽습니다 ... – Spektre

+0

@Spektre A = (A 'x B)'라고하면 A = B x A보다 더 효율적입니다. 내가 여기서 무엇을 놓치고 있니? 첫 번째 경우에 어떻게 누적되지 않습니까? A '= transpose (A)가 아닌지 여부에 관계없이 여전히 다른 방식으로 회전을 누적하고 있습니다. – Harish

관련 문제