Sign in to follow this  
Radiocreed

Fisheye projection in Raytracer

Recommended Posts

I'm trying to simulate the fisheye projection in my ray tracer, but I'm not getting good results. My fisheye image seems really distorted. Can you check if the following code is right? Thanks in advance // i and j are the coordinates on my virtual screen // Transform the pixel coordinates into normalized coordinates double x = 2*i/(cam.width_-1); double y = 2*j/(cam.height_-1); // Calculate radius double radius = sqrt(x*x + y*y); if ( radius > 1.0 || radius < 0.0 ) { colour = Colour( 0.0, 0.0, 0.0 ); } else { // phi is the polar angle, 0 <= phi <= 2PI double phi = 0.0; // (x,y) are now the polar coordinates if ( radius == 0.0 ) { phi = 0.0; } else if ( x < 0.0 ) { phi =PI - asin(y/radius); } else if ( x >= 0.0 ) { phi = asin(y/radius); } // Angle increases linearly with distance from centre double theta = radius*cam.fov_; // Calculate new ray dir double rx = sin(theta)*cos(phi); double ry = sin(theta)*sin(phi); double rz = cos(theta); Vector3 newDir( rx, ry, rz ); Point3 newEye( 0.0, 0.0, 1.0 ); Ray r( newEye, newDir ); colour = trace( r ); }

Share this post


Link to post
Share on other sites
It seems fine to me, assuming that "cam.fov_" is of the order of "1", and that the average i and j are somewhere near (0, 0).

If you are getting ripple effects cam.fov_ is probably way too high. If not, can you describe the distortion better.

Aside:
IMHO it would be easier to just use normalisation to maintain the screen-direction of the pixel, as opposed to asin(), sin() and cos().

Like


double rx = (x / radius) * sin(theta);
double ry = (y / radius) * sin(theta);
double rz = cos(theta);




(x / radius, y / radius) being the normalised screen-direction

You can then completely remove the calculation of the polar angle, improving speed, clarity and simplicity at the same time.

BTW, use [sourse] and [/sourse] tags. (Replace sourse with source) to define blocks of code. Much easier to read.

Edit:
You also might want to check (not sure whether this matters) that your calculations of x and y aren't being rounded. Try:

double(2 * i) / (cam.width_ - 1);

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Here's my revised piece of code, still the same bad distortion.
Is there a way to attach pictures on this forum? I can show you how bad it the distortion is, for example, the cylinder and cone that I have become a completely different object in the fisheye view.

What do you mean by cam.fov is of order 1? I'm using fov=180, which is then converted to radians.

My i and j each go from 0 to 300. So, cam.width and cam.height both are 300. That's because my final output image is of dimension 300x300.

Any more help please, I really need to get this working.


Vector3D temp = cam.dir(i,j);
i = temp[0];
j = temp[1];

// Transform the pixel coordinates into normalized coordinates
double x = (double)(2*i)/(cam.width_-1);
double y = (double)(2*j)/(cam.height_-1);

// Calculate radius
double radius = sqrt(x*x + y*y);

if ( radius > 1.0 || radius < 0.0 ) {
colour = Colour( 0.0, 0.0, 0.0 );
} else {

// Angle increases linearly with distance from centre
double theta = radius*cam.fov_;

// Calculate new ray dir
double rx = (x/radius)*sin(theta);
double ry = (y/radius)*sin(theta);
double rz = cos(theta);

Vector3D newDir( rx, ry, rz );
Point3D newEye( 0.0, 0.0, 1.0 );
Ray r( newEye, newDir );
root->drawPixel( 0, 0, r, colour );
}

Share this post


Link to post
Share on other sites
Er, just looking again, did you mean this?

((2 * i) / cam.width_) - 1;

That will make the center of the view look straight ahead. What you have makes the center of the view pretty close to the top-left (or bottom-left or wherever the 0-0 is). This might help a bit.


I believe you can attach images, if you host them somewhere else. But look in the faq. If not, just post the URL. Of course if you don;t have hosting you're screwed unless you use something like, IIRC yahoo images or something.



You're doing
theta = radius * cam.fov_;
and then
sin(theta) / cos(theta);

sin(180) is zero, meaning you will be looking straight ahead again when theta=180. This means there will be a ring at theta=180 where all rays point exactly to straight ahead, a pretty extreme fisheye, and when theta = 90, you will be looking directly sideways.

Since, from the divide-by-cam-size radius is max 1, theta's max is cam_fov_ * 1. You probably want to limit this to something more like 45 degrees, and the distortion should be more subtle.

Not sure if sin() / cos() are the right functions to use for proper fish-eye though. But they should give a reasonably consistent image.

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