Strange behavior with rotation matrices

2019-05-21 08:40发布

I am trying to render a spaceship directly in front of a camera, with the model rotating with the camera's view. This works, as long as the player only yaws or rolls. If he does both, it goes into a tumble. A video of the problem is here: http://youtu.be/voKTsdy5TFY

The relevant code follows, edited for clarity:

D3DXMatrixRotationAxis(&playeryaw, &up, yawangle);
D3DXMatrixRotationAxis(&playerpitch, &right, pitchangle);

playerrot =  playeryaw * playerpitch;
D3DXMatrixTranslation(&playertrans, pos.x, pos.y, pos.z);
D3DXMatrixScaling(&playerscale, 0.05 / ((float)i + 1),  0.05 / ((float)i + 1),  0.05 / ((float)i + 1));
playercom = playerscale * playerrot *  playertrans;
device->SetTransform(D3DTS_WORLD, &playercom);
playermesh.render();

EDIT: Expanded code at the behest of Optillect Team.

3条回答
劳资没心,怎么记你
2楼-- · 2019-05-21 08:51

That looks like Gimbol lock, which is a known limitation of using Euler angles for representing three-dimensional rotations. You might want to use matrices or quaternions instead to represent your spaceship's rotation.

查看更多
淡お忘
3楼-- · 2019-05-21 08:53

Na7coldwater may be right on the gimbal lock. The 2 angles you use, yawangle and pitchangle are euler angles and hence susceptible to gimble lock.

You could avoid gimbal lock by either using quaternions or by storing the current rotation and then build a delta rotation matrix and multiply to the previous rotation matrix.

ie where you build your rotation matrix you will be storing the delta from the previous rotation rather than the absoloute rotation from the model's origin state.

e.g

D3DXMatrixRotationAxis(&playeryaw, &up, yawanglethisframe);
D3DXMatrixRotationAxis(&playerpitch, &right, pitchanglethisframe);

playerrot =  playerrot * (playeryaw * playerpitch); // This line has changed!!
D3DXMatrixTranslation(&playertrans, pos.x, pos.y, pos.z);
D3DXMatrixScaling(&playerscale, 0.05 / ((float)i + 1),  0.05 / ((float)i + 1),  0.05 / ((float)i + 1));
playercom = playerscale * playerrot *  playertrans;
device->SetTransform(D3DTS_WORLD, &playercom);
playermesh.render();

where playerrot is stored from frame to frame.

查看更多
ら.Afraid
4楼-- · 2019-05-21 09:02

It seems you apply the same transform to the spaceship. You should:

  1. Apply rotation matricies to the spaceship, then translation matrix (position of the spaceship).
  2. Apply those matricies for up and right vectors.
  3. Build view (camera) matrix based on up and right vectors (first translate back of the spaceship, then rotate, then translate to the position of the spaceship)

Something like this:

    D3DXMatrixRotationAxis(&shipyaw, &up, yawangle);
    D3DXMatrixRotationAxis(&shippitch, &right, pitchangle);
    D3DXMatrixTranslate(&shippos, x, y, z);
    shipmatrix = shippitch * shipyaw * shippos;

    D3DXMatrixTranslate(&viewoffset, 0, 0, -10);
    D3DXMatrixRotationAxis(&viewyaw, &up, -yawangle);
    D3DXMatrixRotationAxis(&viewpitch, &right, -pitchangle);
    D3DXMatrixTranslate(&viewpos, -x, -y, -z);
    viewmatrix = viewoffset * viewpitch * viewyaw * viewpos;
查看更多
登录 后发表回答