Raytracer is not working

Started by
14 comments, last by Wyrframe 8 years, 3 months ago

Hello,

i spent the last 24h finding out why my code is not working (image is just black).

I am especially confused by the way of generating rays from the camera into the scene because there are a lot of ways how it can be done (at least it looks like that for me) and i don't know which way is right for me.

So my ray generation looks like this:


double imageAspectRatio = cast(double)width / cast(double)height;
double Px = (2.0*((cast(double)x+0.5) / cast(double)width) - 1) * tan(45.0 / 2.0 * PI / 180.0) * imageAspectRatio;
double Py = (1.0 - 2.0 * ((cast(double)y + 0.5) / cast(double)height) * tan(45.0 / 2.0 * PI / 180.0));
Vector3D direction = new Vector3D(Px,Py,-1).normalize();
Ray r = new Ray(this.camera, direction);

I debugged my program and no ray hits a sphere in my scene ever! So i think the problem has to be correlated with the ray generation code (i am pretty sure my sphere intersection code is correct).

Advertisement

What's the range that `x` and `y` sweep?

The 2*(x-0.5) construct turns x values from 0..1 into -1..+1... but here you appear to be doing 2*(x+0.5) which will turn an `x` in -1..0 into a value in the -1..+1 range.

RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.

What's the range that `x` and `y` sweep?

x and y sweep both between 0 and 250 (size of the image)

On the formula i read online the '0.5' would be the 'u' and 'v' coordinates but i don't know how to calculate them...

Fiddling with your equations a bit, I see the problem. Let's break it down a bit.


// For W=H=250, pixelX/Y will be 0 to 249 inclusive, and that's why the +0.5; to center each
// ray on a pixel, instead of casting through the top-left corner of each pixel.
double pixelX, pixelY; // In the range [0,w/h), respectively.
double w, h, fov;      // Also inputs; FOV is in Radians (for 45°, that's PI*0.25).

// Calculate common terms.
double aspect = w / h;
double fovFactor = TAN(fov*0.5);

// Turn each [0,w/h) pixel coordinate into a [-1,+1] proportional term,
// which will pass through the middle of each cell in a WxH axis-centered
// square grid of cells, at any given fixed distance from the camera.
double rayX = (2.0 * (pixelX+0.5) / w) - 1.0;
double rayY = (2.0 * (pixelY+0.5) / h) - 1.0;

// Turn each proportional term into a ray component, correcting for the
// desired FOV and the actual aspect ratio of the grid.
rayX *= fovFactor * aspect;
rayY *= fovFactor;  // If you must use pixelY=0 as the bottom of your screen, negate rayY here.

// This generated vector is in camera space, so make sure to either transform your scene
// into camera space, or transform the ray into scene space, before you cast it!
Vector3D direction = new Vector3D(rayX, rayY, -1).normalize();
RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.

Thank you very much for your help, i really appreciate it!

So i changed my Ray-generation code accordingly:


double fov = PI*0.25;
double aspect = cast(double)width / cast(double)height;
double fovFactor = tan(fov*0.5);
double rayX = (2.0*(cast(double)x+0.5)/cast(double)width) - 1.0;
double rayY = (2.0*(cast(double)y+0.5)/cast(double)height) - 1.0;
rayX *= fovFactor*aspect;
rayY *= fovFactor;
Vector3D direction = new Vector3D(rayX, rayY, -1).normalize();
Ray r = new Ray(this.camera, direction);

transform the ray into scene space, before you cast it!

How is this done?

You'll presumably have a camera rotation (or look-at coordinate)? You'll need to generate a matrix from that, and transform the ray direction before casting it. That's a pretty big topic on its own, and it should have come up in whatever source material you've been consulting so far for raytracing basics. Either that, or the raytracer you're reading uses a fixed camera; looking down the -Z axis from the world origin (0,0,0).

As it stands in your code, if the Ray constructor takes an origin position and a direction vector (as opposed to an origin position and a "towards" position), your camera will only look down the -Z axis from wherever the camera origin is placed. If it takes a "towards" position, your view frustrum will be a trapezoid floating near the world origin as viewed from the camera position, and it'll look really wierd; the only place your view will be correct then is when your camera origin is at the world origin.

Also, stop using all those pointless mid-expression conversions. Converting an integer to a floating-point is not always a cheap operation; do it as little as possible. That's why I structured my sample code the way I did. If you're writing a module which is fed the x/y/w/h in integer format, and you don't have any control of the source which calls it, then convert them all just once, instead of re-converting over and over throughout your source.

RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.

The problem is that i don't have any raytracing source material because either i don't understand it (weird math signs) or it doesn't cover all aspects of the topic or it just doesn't work. Currently my camera is just the "world origin", so (0,0,0).

if the Ray constructor takes an origin position and a direction vector (as opposed to an origin position and a "towards" position)

I don't understand what the differences between those two are. But:

and it'll look really wierd

makes me assume that i should at least get an image if the ray-creation-code is correct? But it's still black and i don't get to the point where a ray intersects with a sphere. But what else could be wrong besides the part of ray-creation? I mean, this is my code for the sphere-intersection and it should be correct:


		Vector3D v = ray.origin.sub(this.center);
		double a = ray.direction.dot(ray.direction);
		double b = 2.0 * ray.direction.dot(v);
		double c = v.dot(v) - (this.radius * this.radius);
		double discriminant = (b*b) - (4.0*a*c);
		if(discriminant > 0.0){
			double x1 = (-b - sqrt(discriminant)) / (2.0*a);
			double x2 = (-b + sqrt(discriminant)) / (2.0*a);
			if((x1 >= 0.0) && (x2 >= 0.0)){
				return x1;
			}
			if((x1 < 0.0) && (x2 >= 0.0)){
				return x2;
			}
			return -1.0;
		} else{
			return -1.0;
		}

Also, stop using all those pointless mid-expression conversions.

Okay. I just want to make sure it is not rounded up.

If you fire a ray directly at the sphere (0,0,-1), can you make it work then?

If not, problem is probably in sphere intersection.

Is the sphere positioned so that camera is not inside it, and its not behind camera (position should have negative z, further than radius)

o3o

If you fire a ray directly at the sphere (0,0,-1), can you make it work then?

Yes but obviously the whole image is one single color, here is my sphere:


Sphere(new Color(20,255,125), true, new Vector3D(0,0,-2), .5),

The Vector is the center and the '.5' is the radius.

Ray:


Ray r = new Ray(this.camera, new Vector3D(0,0,-1));

where 'this.camera' is the Vector(0,0,0)

What kind of vectors does the raycasting function produce (just grab some random examples)?

Does it produce something close to (0,0,-1)?

Maybe the sphere intersection only works when it passes directly through (assuming the rays themselves are not complete garbage)

o3o

This topic is closed to new replies.

Advertisement