Simple screen panning easy solution?

Started by
11 comments, last by Juliean 11 years ago

Hello,

so I wanted screen panning for my editor. Hope thats even the right term, I click my mouse and the camera moves parallel to the screen as I drag the mouse. So thats what I've got so far:


D3DXVECTOR3 vDist3(0.0f, (float)vDist.y, -(float)vDist.x);
m_pCamera->Pan(vDist3);

Yeah, so if I look straight on the X-Axis this works fine, but as you can quess, as soon as I rotate the camera it doesn't work as expected.

Now I could use the law of sine to calculate two components of rotation along the x and z-axis, make a rotation matrix and transfer the vector with it, then somehow take into consideration the up-vector, etc... but I quess there is an easier solution using the view-matrix, isn't there? If so, how could this be done (I tried multiplying both the normal and inverse view matrix, but that just makes causes the camera to "zoom" out of the scene in huge steps)?

Advertisement

You should have a direction (where the camera is pointing) and an up vector associated with your camera. Crossing the direction vector with the up vector should yield a vector that you can use for panning your camera side to side (e.g. scale it by the amount you need to pan, and add it to your camera's position).

Ah, cross product, how comes i missed that. This does indeed work, thanks a lot, here is the solution:


        //access camerea attributes
        D3DXVECTOR3 vDir =     m_pCamera->GetDirection();
        D3DXVECTOR3 vUp = m_pCamera->GetUp();
        //Dir x Up - for horizontal panning
        D3DXVec3Cross(&vDir, &vDir, &vUp);
        //horizontal scale
        D3DXMATRIX mScale;
        D3DXMatrixScaling(&mScale, (float)vDist.x, (float)vDist.x, (float)vDist.x);
        D3DXVec3TransformCoord(&vDir, &vDir, &mScale);
        //vertical scale
        vUp.y *= (float)vDist.y;
        m_pCamera->Move(vDir + vUp);
 

Oh, while I am at it, what about rotation? I got it to work somehow, but...


        //access camera position
        D3DXVECTOR3 vPos(m_pCamera->GetPosition());
        D3DXMATRIX mRotation;
        D3DXMatrixIdentity(&mRotation);
        //rotation
        D3DXMatrixRotationYawPitchRoll(&mRotation, DEGTORAD(-vDist.x), 0.0f, DEGTORAD(vDist.y));
        D3DXVec3TransformCoord(&vPos, &vPos, &mRotation);
        m_pCamera->SetPosition(vPos);

Now it rotates but it really behaves weird, e.g. when the rotation radius gets smaller the nearer I get to one of the axis... any advice on that too?

What kind of rotation are you talking about? The camera spinning around on its up-axis? Or around its direction axis?

What I'd like to have is the camera circeling around its look-at position. Aside from the problem I described (thats really hard to describe in great detail, though if you'd try for yourself you'd notice it within a second) there is also the issue that if I e.g. rotate the camera to be at (0, Y, 0) it will make first a sharp turn around the y axis. What I'd like to have is a camera rotation like in maya or autodesk 3d where the camera smoothly rotates around its viewing point, if I make e.g. a 180° turn the camera will switch orientation and the scene will be viewed upside down. Any clue how to make something with the "built in" tools or do I have to get my pen and paper for some pages of sine-calculations with awkward corner-case handling (like the first camera I made...)?

No, it should be relatively straightforward.

- Use a vector that points in the opposite direction of your camera's GetDirection,

- Now rotate that vector around the y-axis (or the z-axis, if z is up) by transforming it with the matrix from D3DXMatrixRotationY (or Z, etc...), which lets you say how many degrees you want it rotated

- Now negate that again and you have your camera's new direction

(note: you could probably skip the whole negate negate thing, and just rotate the direction vector in the opposite rotational direction that you want)

- And then determine the camera's new position based on the look-at position, that direction, and the camera distance

Ok, using the direction vector at least makes it *theoretically* work for each camera position, but that still doesn't solve my issue. As long as I rotate it along one axis, everything is fine, say the z-axis. But as soon as I want to add another axis of movement, everything crashes and burns. It doesn't matter if I want to rotate x-y, y-z, or x-z, it will eigther way behave oddly:


        //access camera position
        D3DXVECTOR3 vDir(m_pCamera->GetDirection()), vLookAt(m_pCamera->GetLookAt());
        vDir = -vDir;
        D3DXMATRIX mRotation;
        //rotation
        D3DXMatrixRotationYawPitchRoll(&mRotation, DEGTORAD(vDist.x/10.0f), 0.0f, DEGTORAD(vDist.y/10.0f));
        D3DXVec3TransformCoord(&vDir, &vDir, &mRotation);
        m_pCamera->SetPosition(vLookAt += vDir*10.0f); //hard coded camera distance
 

The problem obviously is related to this (though I can't really put together why). If I look straigth along the x axis and want to rotate around it, no rotation happens. Otherwise, if I look straigth along the z axis and want to rotate around it, there is again no rotation at all. This seems to be the reason for the weird behaviour, since if I rotate around one axis I get closer/further away from the other, which overall changes the uhm rotation stiffness factor (don't know how else to call it) to change for this axis and so on. Obviously I can't simply rotate the direction, since I'd need to do a rotation based on the how far the camera is away from the certain axis... that can't be necessary, can it? oO

Edit: To give a better picture of the actual issue, I've uploaded a short video to my youtube channel:

">
. You should see what I meant..

Ah, I see, you're making a 3d editor type thing. I didn't get that you wanted to rotate the camera about an arbitrary axis.

I've never done this, but my first guess at how to implement it would be the following:

1) Create a 3d vector that corresponds to the direction you are dragging the mouse

2) Cross this vector with the camera view direction

3) Use the result as the rotation axis for D3DXMatrixRotationAxis

4) transform the camera direction with this matrix, and recalculate camera position

To calculate (1), I would guess you can make a screenspace vector (dx, dy, 0) and transform by the inverse view matrix to get it in worldspace.

Yeah, it worked as you described it, thanks!

Well, there still is one issue. When the camera moves to look along the y-axis, therefore in the moment where the camera should "flip", it simply dead-locks and spins around the y-axis like mad when I drag the mouse further in the same direction. I quess I'd need to flip the up-vector of the camera here, can you think of an easy solution here too? Thats the currect code:


        D3DXVECTOR3 vDir(m_pCamera->GetDirection()), vLookAt(m_pCamera->GetLookAt());
        D3DXVECTOR3 vDrag(vDist.x, vDist.y, 0.0f);

        D3DXMATRIX mRotation, mView(m_pCamera->GetViewMatrix());
        //inverse view
        D3DXMatrixInverse(&mView, NULL, &mView);
        //transform mouse drag vector to object space
        D3DXVec3TransformCoord(&vDrag, &vDrag, &mView);

        D3DXVECTOR3 vAxis;
        //create axis from drag an direction vector
        D3DXVec3Cross(&vAxis, &vDrag, &vDir);

        //rotate around axis
        D3DXMatrixRotationAxis(&mRotation, &vAxis, DEGTORAD(1.0f));
        //transform direction
        D3DXVec3TransformCoord(&vDir, &vDir, &mRotation);
        //recalculate position
        m_pCamera->SetPosition(vLookAt - vDir*10.0f);
 

EDIT: It also appears that it only works when the lookat-position is in the origin. As soon as translate the camera and try to rotate afterwards, I get weird locking behaviour, again. Any help there would also be great...

A couple of notes:

- I think you should be normalizing some of your vectors (like vDrag).

- You need to be adjusting your camera's up vector as things are rotating (I guess apply the same matrix to it that you apply to the direction).

This topic is closed to new replies.

Advertisement