Wednesday, June 25, 2014

The Case of the Missing Sphere

 Hi, it's been awhile. I've been working on ray tracing, and I have something new to teach you. Have you ever looked at a really realistic movie made out of computer graphics, or a really good video game and wondered how they made it ? They might have used ray tracing. Ray tracing is using rays and vectors to make a picture.  I've been working on it and I'm going to teach you what I know so far.  We are going
to put a sphere in the middle of a picture and use rays to color it so we can see it. First off we're going to need to place the sphere, and since we need to place it in the middle first we need to figure out how big our screen is. We're not going to use the entire screen, instead we're going to use a smaller 300*300 pixels screen. That means to place the sphere in the middle of the screen we need to place it's origin at -150 y,  150 x, and -300 z, and make it's radius 150. So we have our sphere. Now we need our rays. We need to hit every single pixel with a ray. So that means we need to put a ray at every single pixel. Doing them individually would take forever, so instead we're going to use a loop.

 This loop is going to create new rays and place them at different points.

for(int row = 0 ; row < NUM_PIXELS_Y ; row++)
for(int col = 0; col < NUM_PIXELS_X ; col++)
{
Ray explorer;
explorer.origin.x = -149.5 + col;
explorer.origin.y = -149.5 + row;
explorer.direction.z =-1;
   

Notice that I didn't close it off with a curly brace. That's because this is only the 1st 1/2 of the loop.  We'll get into the second 1/2 later but for now let's focus on this.

Our ray is called explorer, and what's nice about this loop is that after it does explorer it automatically does all the other rays, so we don't have to do another loop along with it. When we say col we mean columns, and obviously row means rows. The "for" part up there is the 1st part of the loop, they're the actions we do to determine if we go into the 2nd part of the loop. So there's int row = 0; which creates row and then makes it 0, then we compare row to NUM_PIXELS_Y;, row++ means increment row(if you don't know what increment means it means add 1) and the next line is the same except col replaces row and  NUM_PIXELS_X; replaces NUM_PIXELS_Y;. Then we have all this stuff about rays' origin. Origin.x is -149.5 + col, and origin.y is -149.5 + row, so as columns goes across and rows goes up and down we end up with rays at every single pixle of our 300*300 screen. And direction.z is the direction of the rays.


glm::vec3 hipotenoose = sphere.origin - explorer.origin;
 float adjacentLength = glm::dot(explorer.direction,hipotenoose);
 glm::vec3 adjacent = explorer.direction * adjacentLength; glm::vec3 opposite = hipotenoose - adjacent; if(glm::length(opposite) < sphere.radius) { 



qimage.setPixel(col,row,qRgb(0xFF,0,0)); }

Now for the 2nd 1/2 of the loop.

We've got our sphere and our rays, and now we have to figure out what rays hit the sphere and what rays don't and what to do if the ray hits the sphere. Here's the math.
                                                       
I know, it looks ridiculous but this is what we do. See we've got our ray which we can tell just by looking at this picture is going to hit the sphere. But the computer doesn't know that, so we need to do some math to figure it out. We've got our sphere, the spheres' origin,the spheres' radius, and our point of the world ( the + ). So 1st we draw a line from the spheres' origin to the rays' origin ( hypotenuse ), a line coming off of the ray ( adjacent ), a line coming off the point of the world to the rays' origin,and a line coming off the point of the world to the spheres' origin. The reason we're drawing these lines from the point of the world is so we can figure out hypotenuse, and how we do that is we say: ray origin - sphere origin = hypotenuse. So now we've got one side but we need the others to. So on to adjacent !!! To figure out adjacent we need to do hypotenuse, dot, rays' direction. Dot sort of means multiplication but you end up with the magnitudes of the vectors you're using and cos theta. So this is what we got from dotting those 2 together: |hypotenuse| |rays ' direction| cos theta. Now we scale it off of the ray's direction and we've got our adjacent! The next part is easy since we've got our hypotenuse and our adjacent now we need to get our opposite. All we have to do is subtract one from the other and we've got our opposite. Then we compare it to the spheres' radius and if it's longer the ray didn't hit  the sphere but if it's shorter the ray did hit the sphere. And the last line of code colors the pixels and you can fiddle around with the numbers to change the color of the sphere.

Detective, case solved!