# Camera zoomin/out

## Recommended Posts

Hi, what kind of algorithm do you use when zooming your camera class, i am using the following code but when you do it 20 times back and forth it becomes "wrong". I think it is because the small data losses.but anyway what should I do ?

void Camera::zoomin(float units)//units doesnt mean anything for now
{
// pos = position vector;
// look = lookat vector;

if(zoom <= -5)
return;

pos.x = (pos.x-look.x)-((pos.x-look.x)/5)+look.x;
pos.y = (pos.y-look.y)-((pos.y-look.y)/5)+look.y;
pos.z = (pos.z-look.z)-((pos.z-look.z)/5)+look.z;
zoom--;
}

void Camera::zoomout(float units)//units doesnt mean anything for now
{
if(zoom >= 5)
return;

pos.x = (pos.x-look.x)+((pos.x-look.x)/5)+look.x;
pos.y = (pos.y-look.y)+((pos.y-look.y)/5)+look.y;
pos.z = (pos.z-look.z)+((pos.z-look.z)/5)+look.z;
zoom++;
}



##### Share on other sites
You're translating the camera, which is bad in this case.

What you want to do is modify the camera's fov. A smaller fov will "zoom in" and a larger fov will "zoom out".

##### Share on other sites
As a note:
pos.x = (pos.x-look.x)-((pos.x-look.x)/5)+look.x;
is equivalent to
pos.x = 0.8*pos.x + 0.2*look.x

Anyways, you have three options if you want to make something look bigger:

#1 Get closer to it by repositioning the camera. This is what you're doing now.
#2 Apply a scaling transformation to the camera
#3 Adjust the field-of-view (as _fastcall said)

I think any of these are alright, but it doesn't seem that your zoom-in and zoom-out functions are inverted. Consider this:

Px1 = 0.8*Px0 + 0.2*Lx // zooming out, reduced
Px2 = 1.2*Px1 - 0.2*Lx // zooming in, reduced
Px2 = 1.2*(0.8*Px0 + 0.2*Lx) + 0.2*Lx
Px2 = 0.96*Px0 + 0.24*Lx + 0.2*Lx
Px2 = 0.96*Px0 + 0.44*Lx
Px2 != Px0

So you can see, zooming out and zooming back in does not result in the same values. This is where you're losing information.

##### Share on other sites
From what I see, what if your walking up against a wall or object and you zoom in? It looks like your camera will go inside the wall/object rather than enlarging the view from where your standing. I'm not 100% sure how to solve this though =\

##### Share on other sites
I've just implemented the same sort of thing. Heres how I done it.

pos is a vector representing the camera's position.
target is the object the camera is looking at.
z is the number of units to zoom. passing -z as a param to the function will zoom out.

I don't know if you are using a 3d vector class, but I think it makes thing easier, so i've included the source for my vector class below if you want to use it, although it's probably not perfect.

void Camera::zoom(float z){        // get the vector between the camera and target	Vector3D lineVector = pos - target->getPosition();         // if the camera is zoomed in the max amount, exit function	if(lineVector.magnitude() < MIN_CAM_DIST && z < 0)		return;        // if the camera is zoomed out the maximum amount, exit function	if(lineVector.magnitude() > MAX_CAM_DIST && z > 0)		return;// get the directional vector of lineVector, and multiply by the number of units// to zoom (z), then add to the camera's positional vector(pos)	 pos += z * lineVector.direction();}

Vector3D.h

#ifndef VECTOR3D_H#define VECTOR3D_H#include <math.h>class Vector3D{private:	float x_val;	float y_val;	float z_val;public:	Vector3D();	Vector3D(float x, float y, float z);	~Vector3D();	float x();	void x(float x);	float y();	void y(float y);	float z();	void z(float z);	Vector3D direction();	float magnitude();	Vector3D normalize();	float dotProduct(const Vector3D &vec);	Vector3D operator=(const Vector3D &u);	Vector3D operator+=(const Vector3D &u);	Vector3D operator-=(const Vector3D &u);	Vector3D operator*=(float f);	Vector3D operator/=(float f);	friend Vector3D operator*(const Vector3D &u, float f);	friend Vector3D operator*(float f, const Vector3D &u);	friend Vector3D operator+(const Vector3D &u, const Vector3D &v);	friend Vector3D operator-(const Vector3D &u, const Vector3D &v);	friend Vector3D operator/(const Vector3D &u, float f);};

Vector3D.cpp

#include "Vector3D.h"Vector3D::Vector3D(){	x_val = 0.0f;	y_val = 0.0f;	z_val = 0.0f;}Vector3D::Vector3D(float x, float y, float z){	x_val = x;	y_val = y;	z_val = z;}Vector3D::~Vector3D(){}float Vector3D::x(){	return x_val;}float Vector3D::y(){	return y_val;}float Vector3D::z(){	return z_val;}void Vector3D::x(float x){	x_val = x;}void Vector3D::y(float y){	y_val = y;}void Vector3D::z(float z){	z_val = z;}float Vector3D::magnitude(){	return sqrt(x_val*x_val + y_val * y_val + z_val * z_val);}Vector3D Vector3D::direction(){	float m = magnitude();	Vector3D dir = *this;     if (m < 0.0001)     {           dir.x_val = 1.0;           dir.y_val = 0;		   dir.z_val = 0;     }     else     {           dir.x_val /= m;           dir.y_val /= m;		   dir.z_val /= m;     }     return dir;}Vector3D Vector3D::normalize(){	//Make the Vector a unit Vector, and return self	float m = magnitude();    if(m < 0.000001)    {		x_val = 1.0;        y_val = 0;		z_val = 0;        m = 0.0;	}else{		x_val /= m;        y_val /= m;		z_val /= m;	}    return *this;}float Vector3D::dotProduct(const Vector3D &vec){	//a.b = ax*bx + ay*by    Vector3D dotProd = *this;    return (dotProd.x_val * vec.x_val) + (dotProd.y_val * vec.y_val) + (dotProd.z_val * vec.z_val);}Vector3D Vector3D::operator =(const Vector3D &u){	x_val = u.x_val;	y_val = u.y_val;	z_val = u.z_val;	return *this;}Vector3D Vector3D::operator +=(const Vector3D &u){	x_val += u.x_val;	y_val += u.y_val;	z_val += u.z_val;	return *this;}Vector3D Vector3D::operator -=(const Vector3D &u){	x_val -= u.x_val;	y_val -= u.y_val;	z_val -= u.z_val;	return *this;}Vector3D Vector3D::operator *=(float f){	x_val *= f;	y_val *= f;	z_val *= f;	return *this;}Vector3D Vector3D::operator /=(float f){	x_val /= f;	y_val /= f;	z_val /= f;	return *this;}Vector3D operator*(const Vector3D &u, float f) {	 return Vector3D (u.x_val * f, u.y_val * f, u.z_val * f);}Vector3D operator*(float f, const Vector3D &u) {	 return Vector3D(u.x_val * f, u.y_val * f, u.z_val * f);}Vector3D operator/(const Vector3D &u, float f) {	 return Vector3D(u.x_val / f, u.y_val / f, u.z_val / f);}Vector3D operator+(const Vector3D &u, const Vector3D &v){	 return Vector3D (u.x_val + v.x_val, u.y_val + v.y_val, u.z_val + v.z_val);} Vector3D operator-(const Vector3D &u, const Vector3D &v){	 return Vector3D(u.x_val - v.x_val, u.y_val - v.y_val, u.z_val - v.z_val);}

[Edited by - DaveMS on May 13, 2008 3:52:36 AM]

##### Share on other sites
Quote:
 Original post by TenacFrom what I see, what if your walking up against a wall or object and you zoom in? It looks like your camera will go inside the wall/object rather than enlarging the view from where your standing.

Right you are. AFAIK this kind of camera manipulation is named "dolly in". Due to translating the near (and far) clipping plane with the camera, unwanted side effects may occur.

IMHO, the best solution w.r.t. a "perfect" zoom would be erissian's #2: incorporating it into the view matrix by doing a scale. On the other hand, changing the FoV is possible, too, but may make big differences in the distortion by perspective projection.

##### Share on other sites
Go stand 100m away from a tree. Now move closer to it by 1/5 of your current distance from it. 1/5 of 100 is 20, so now you are 80 m away. Now move further away from it by 1/5 of your current distance from it. You are 80m away right now, and 1/5 of 80 is 16, so you move to 96m away. That's not where you started. And that's the problem. :)

Consider storing some separate value for "distance", which you increase or decrease by a fixed amount for the zoom in/out calls. Then translate that into an actual camera position. (You'll need a reference vector for the "direction" of the camera to the look point.) You don't even need a linear mapping. It could look like, for example:

void Camera::zoomin() {  ++dist;  _recalcPos();}void Camera::zoomout() {  --dist;  _recalcPos();}void Camera::_recalcPos() { // a private helper function  dist = std::min(std::max(-5, dist), 5); // set limits  pos.x = look.x + ref.x * std::pow(1.2, dist); // just for an example  // similarly for y and z - but you should really use or make a vector class for this :)}

##### Share on other sites
Quote:
 Original post by ZahlmanGo stand 100m away from a tree. Now move closer to it by 1/5 of your current distance from it. 1/5 of 100 is 20, so now you are 80 m away. Now move further away from it by 1/5 of your current distance from it. You are 80m away right now, and 1/5 of 80 is 16, so you move to 96m away. That's not where you started. And that's the problem. :)

Geez, why couldn't I think of it !? :D thanks codewise it is not that hard but I always thought that this "loss" occurs because of variable-type changes.Anyway it helped.