Touch device camera pinch zoom, pan and rotate

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
cegprakash
Posts: 41
Joined: Thu Feb 27, 2014 10:55 am

Touch device camera pinch zoom, pan and rotate

Post by cegprakash »

I'm working on a multi-touch device where user can adjust the camera by two touches. I want to implement PinchZoom, Pan and Rotate when the user makes two touches on the screen.

I've four 2D points touch1.start, touch1.end, touch2.start and touch2.end.

I can identify the zoom action by finding whether the direction of touch1 and touch2 are opposite to each other.

But I need the screen to behave exactly as how human brain thinks. i.e. it should rotate, pan and zoom along with the finger movements if you know what I mean.. Any help will be appreciated.
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: Touch device camera pinch zoom, pan and rotate

Post by Foaly »

What's your problem exactly? Do you just want to know how to find out how big the rotaton, zoom and move is or do you want to know how to transform the camera with these values?

You can easily read out the rotation, zoom and movement using basic maths.
I assume that all the 2D points are floats. You may have to convert them first.

//ROTATION
//assuming that atan2 takes first the y and then the x value
f32 startRotation = atan2(touch2.start.Y - touch1.start.Y, touch2.start.X - touch1.start.X);
f32 endRotation = atan2(touch2.end.Y - touch1.end.Y, touch2.end.X - touch1.end.X);
f32 rotationDif = endRotation - startRotation; //the actual rotation around the view axis in radians i think. you may have to convert it to degrees

//ZOOM
f32 startDist = touch1.start.getDistanceFrom(touch2.start);
f32 endDist = touch1.end.getDistanceFrom(touch2.end);
f32 zoomDif = endDist / startDist; //Zoom factor. less than 1 for zoom in, more than one to zoom out.

//MOVE
vector2df centerStart = (touch1.start + touch2.start) / 2;
vector2df centerEnd = (touch1.end + touch2.end) / 2;
vector2df moveDif = centerEnd - centerStart; //Movement on view plane
Last edited by Foaly on Thu Aug 07, 2014 8:14 pm, edited 1 time in total.
cegprakash
Posts: 41
Joined: Thu Feb 27, 2014 10:55 am

Re: Touch device camera pinch zoom, pan and rotate

Post by cegprakash »

The trouble is I've to update the viewCamera's position, rotation and Target position in 3D to apply Pan, Zoom and Rotation simultaneously.
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: Touch device camera pinch zoom, pan and rotate

Post by Foaly »

Sorry, I did a mistake in the last post. The zoom factor is "endDist / startDist".

So you want all that for a 3D application. Then what do you actually want to do?
Do you want to orbit aroud something, or just rotate around the view axis and move on the view plane?
Do you have an orthographic or a perspective camera?
Do your want to actually "zoom" like a camera, or just move forward and backward?

We can't help you, if you don't explain what you need.
cegprakash
Posts: 41
Joined: Thu Feb 27, 2014 10:55 am

Re: Touch device camera pinch zoom, pan and rotate

Post by cegprakash »

I've done the swipe action as moving the camera around the target in a fixed radius(spherical movement). Zooming in or out should decrease/increase the radius. Pan should move the target and rotation should rotate the camera.

Swipe is a 1 touch event and Zoom, Pan and Rotate are two touch events.

It's a perspective camera like an eye.
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: Touch device camera pinch zoom, pan and rotate

Post by Foaly »

Did you already implement the swipe action?
Then I think I'd know how to do the others.

You'll have to calculate rotationDif, zoomDif and moveDif first.
Code is untested!!! Maybe you have to invert some vectors etc.

Code: Select all

 
ICameraSceneNode* cam;  //This has to be the camera you want to move. I'm not sure if you have to bind rotation and target.
 
vector3df camStartUpVector;
vector3df camStartPosition;
vector3df camStartTarget;
bool isTwoTouchEvent;
 
//Call this every time when event starts, stores initial values
void startTwoTouchEvent()
{
  isTwoTouchEvent = true;
  camStartUpVector = cam.getUpVector();
  camStartPosition = cam.getPosition();
  camStartTarget = cam.getTarget();
}
 
void endTwoTouchEvent()
{
  isTwoTouchEvent = false;
}
 
 

Code: Select all

 
//Every frame
if (isTwoTouchEvent)
{
  //ROTATION
  //assuming that atan2 takes first the y and then the x value
  f32 startRotation = atan2(touch2.start.Y - touch1.start.Y, touch2.start.X - touch1.start.X);
  f32 endRotation = atan2(touch2.end.Y - touch1.end.Y, touch2.end.X - touch1.end.X);
  f32 rotationDif = endRotation - startRotation; //the actual rotation around the view axis in radians i think.
 
  //ZOOM
  f32 startDist = touch1.start.getDistanceFrom(touch2.start);
  f32 endDist = touch1.end.getDistanceFrom(touch2.end);
  f32 zoomDif = endDist / startDist; //Zoom factor. less than 1 for zoom in, more than one to zoom out.
 
  //MOVE
  vector2df centerStart = (touch1.start + touch2.start) / 2;
  vector2df centerEnd = (touch1.end + touch2.end) / 2;
  vector2df moveDif = centerEnd - centerStart; //Movement on view plane
 
  vector3df camForward = (camStartTarget - camStartPosition).normalize();
  vector3df camRight = camForward.crossProduct(camStartUpVecor).normalize();
  vector3df camUpReal = camRight.crossProduct(camForward).normalize();  //Actually, it should be 1 unit long, normalize shouldn't be needed...
  
  //Apply rotation
  core::quaternion quat;
  quat.fromAngleAxis(rotationDif, camForward);  //This takes rotation in rad, so it's already right
  core::matrix4 mat = quat.getMatrix();
  mat.rotateVect(camUpReal);
  mat.rotateVect(camRight);
  cam.setUpVector(camUpReal);
 
  //Apply scale
  f32 targetDist = camStartPosition.getDistanceFrom(camStartTarget);
  f32 moveDist = targetDist - targetDist * zoomDif;
  cam.setPosition(camStartPosition + camForward * moveDist);
 
  //Apply movement
  vector3df movement = camRight*moveDif.X + camUpReal*moveDif.Y;
  cam.setPosition(cam.getPosition() + movement);
  cam.setTarget(camStartTarget + movement);
}
 
cegprakash
Posts: 41
Joined: Thu Feb 27, 2014 10:55 am

Re: Touch device camera pinch zoom, pan and rotate

Post by cegprakash »

Yeah. Thank you so much.. I'll test it and let you know how it behaves :)
cegprakash
Posts: 41
Joined: Thu Feb 27, 2014 10:55 am

Re: Touch device camera pinch zoom, pan and rotate

Post by cegprakash »

There are problems with rotation.

Also zoom should be startDist / endDist
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: Touch device camera pinch zoom, pan and rotate

Post by Foaly »

What are the problems with rotation?
Move and zoom work as they should?
cegprakash
Posts: 41
Joined: Thu Feb 27, 2014 10:55 am

Re: Touch device camera pinch zoom, pan and rotate

Post by cegprakash »

Only problem I have now is swipe.

Code: Select all

vector3df   cameraAngle, cameraTarget;
float cameraRadius;
 
void updateCamera()
{
    vector3df newCameraPosition;
    newCameraPosition.Y = cameraTarget.Y + cameraRadius * sin(cameraAngle.Y * 3.1415 / 180.0f);
    newCameraPosition.X = cameraTarget.X + cameraRadius * cos(cameraAngle.Y * 3.1415 / 180.0f) * cos(cameraAngle.X * 3.1415 / 180.0f);
    newCameraPosition.Z = cameraTarget.Z + cameraRadius * cos(cameraAngle.Y * 3.1415 / 180.0f) * sin(cameraAngle.X * 3.1415 / 180.0f);
    
    viewCamera->setPosition(newCameraPosition);
    viewCamera->updateAbsolutePosition();
    viewCamera->setTarget(cameraTarget);
}
 
void swipeProgress(vector2df touch)
{    
    vector2df moveDif = (prevTouchPoints[0]-touch);
    
    //Have to find the value of cameraAngle here
 
    updateCamera();    
    prevTouchPoints[0] = touch;
}
 
void panProgress(vector2df touch1, vector2df touch2){
 
    //ZOOM
    f32 startDist = prevTouchPoints[0].getDistanceFrom(prevTouchPoints[1]);
    f32 endDist = touch1.getDistanceFrom(touch2);
    f32 zoomDif = startDist / endDist;
    cameraRadius = max(0.01f, cameraRadius*zoomDif);
    
    //MOVE
    vector2df centerStart = (prevTouchPoints[0] + prevTouchPoints[1]) / 2.0;
    vector2df centerEnd = (touch1 + touch2) / 2.0;
    vector2df moveDif = (centerEnd - centerStart) / 10.0;           //Divided by 10.0 to reduce pan movement speed.
    vector3df camForward = (viewCamera->getTarget() - viewCamera->getPosition()).normalize();
    vector3df camRight = camForward.crossProduct(viewCamera->getUpVector()).normalize();
    vector3df camUpReal = camRight.crossProduct(camForward).normalize();
    cameraTarget = viewCamera->getTarget() + camRight*moveDif.X + camUpReal*moveDif.Y;
    
    //ROTATION
    f32 startRotation = atan2(prevTouchPoints[1].Y - prevTouchPoints[0].Y, prevTouchPoints[1].X - prevTouchPoints[0].X);
    f32 endRotation = atan2(touch2.Y - touch1.Y, touch2.X - touch1.X);
    f32 rotationDif = endRotation - startRotation;
    core::quaternion quat;
    quat.fromAngleAxis(rotationDif, camForward); 
    core::matrix4 mat = quat.getMatrix();
    mat.rotateVect(camUpReal);
    mat.rotateVect(camRight);
    viewCamera->setUpVector(camUpReal);
    
 
    updateCamera();
    
    prevTouchPoints[0] = touch1; prevTouchPoints[1] = touch2;
}
 
 
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: Touch device camera pinch zoom, pan and rotate

Post by Foaly »

So all two touch actions work?

How do you actually want the "swipe" to behave? Do you want to rotate around the target or do you want a look motion like in a first person shooter?
cegprakash
Posts: 41
Joined: Thu Feb 27, 2014 10:55 am

Re: Touch device camera pinch zoom, pan and rotate

Post by cegprakash »

Rotate around the target!
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: Touch device camera pinch zoom, pan and rotate

Post by Foaly »

Well, there are different possibilities to do that...

I think the best is to remember the distance to the target.
Then get the current direction to the target: (targetPos - camerapos).Normalize()
Then you rotate that direction using quaternions and matrices. (Just look at the two touch rotation, there you already use this kind of rotation).
You have to rotate it around the camera up axis and the camera right axis (camera up axis for y movement of the touch, right axis for x movement).
After that you multiply this new direction with the distance and add it to the target position.

I hope this helps you. (And I hope it's correct)
Please try to figure it out yourself before you ask again. It will help you more for future projects if you learn to find out things yourself.
But if you really don't make any progress, you can ask again.
Post Reply