Sign in to follow this  
Eralp

Camera zoomin/out

Recommended Posts

Eralp    142
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 this post


Link to post
Share on other sites
erissian    727
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 this post


Link to post
Share on other sites
Tenac    124
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 this post


Link to post
Share on other sites
DaveMS    187
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 this post


Link to post
Share on other sites
haegarr    7372
Quote:
Original post by Tenac
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.

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 this post


Link to post
Share on other sites
Zahlman    1682
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 this post


Link to post
Share on other sites
Eralp    142
Quote:
Original post by Zahlman
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. :)


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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this