void RayTracer::DoRayTrace( Scene* pScene ) { Camera* cam = pScene->GetSceneCamera(); Vector3 camRightVector = cam->GetRightVector(); Vector3 camUpVector = cam->GetUpVector(); Vector3 camViewVector = cam->GetViewVector(); Vector3 centre = cam->GetViewCentre(); Vector3 camPosition = cam->GetPosition(); double sceneWidth = pScene->GetSceneWidth(); double sceneHeight = pScene->GetSceneHeight(); // Orthographic //double pixelDX = (sceneWidth / m_buffWidth) * 15; //double pixelDY = (sceneHeight / m_buffHeight) * 15; // Perspective - uncomment code in scene too double pixelDX = sceneWidth / m_buffWidth; double pixelDY = sceneHeight / m_buffHeight; int total = m_buffHeight*m_buffWidth; int done_count = 0; Vector3 start; start[0] = centre[0] - ((sceneWidth * camRightVector[0]) + (sceneHeight * camUpVector[0])) / 2.0; start[1] = centre[1] - ((sceneWidth * camRightVector[1]) + (sceneHeight * camUpVector[1])) / 2.0; start[2] = centre[2] - ((sceneWidth * camRightVector[2]) + (sceneHeight * camUpVector[2])) / 2.0; Colour scenebg = pScene->GetBackgroundColour(); if (m_renderCount == 0) { fprintf(stdout, "Trace start.\n"); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); for (int i = 0; i < m_buffHeight; i++) { for (int j = 0; j < m_buffWidth; j++) { //calculate the metric size of a pixel in the view plane (e.g. framebuffer) Vector3 pixel; Colour colour; // Anti-Aliasing WOOHOO - 16 total samples per pixel for (float x = 0.25f; x <= 1.f; x += 0.25f) { for (float y = 0.25; y <= 1.f; y += 0.25f) { pixel[0] = start[0] + (i + x) * camUpVector[0] * pixelDY + (j + y) * camRightVector[0] * pixelDX; pixel[1] = start[1] + (i + x) * camUpVector[1] * pixelDY + (j + y) * camRightVector[1] * pixelDX; pixel[2] = start[2] + (i + x) * camUpVector[2] * pixelDY + (j + y) * camRightVector[2] * pixelDX; /* * setup view ray * In perspective projection, each view ray originates from the eye (camera) position * and pierces through a pixel in the view plane * * TODO: For a little extra credit, set up the view rays to produce orthographic projection */ // PERSPECTIVE Ray viewray; viewray.SetRay(camPosition, (pixel - camPosition).Normalise()); // Orthographic attempt //viewray.SetRay(pixel, camViewVector.Normalise()); m_isReflecting = m_isRefracting = false; //trace the scene using the view ray //the default colour is the background colour, unless something is hit along the way colour+= this->TraceScene(pScene, viewray, scenebg, m_traceLevel); } } colour.red /= 16.f; colour.green /= 16.f; colour.blue /= 16.f; /* * The only OpenGL code we need * Draw the pixel as a coloured rectangle */ glColor3f(colour.red, colour.green, colour.blue); glRecti(j, i, j + 1, i + 1); } glFlush(); } fprintf(stdout, "Done!!!\n"); m_renderCount++; } glFlush(); }
Colour RayTracer::TraceScene(Scene* pScene, Ray& ray, Colour incolour, int tracelevel, bool shadowray) { RayHitResult result; Colour outcolour = incolour; Colour reflectColour; Colour refractColour; std::vector<Light*>* light_list = pScene->GetLightList(); if (tracelevel <= 0) // reach the MAX depth of the recursion. { return outcolour; } result = pScene->IntersectByRay(ray, shadowray); if (result.data) //the ray has hit something { Vector3 start = ray.GetRayStart(); if (!shadowray) { outcolour = CalculateLighting(light_list,&start, &result); } else { return outcolour * 0.3f; } if(m_traceflag & TRACE_REFLECTION) { //Only consider reflection for spheres and boxes if (((Primitive*)result.data)->m_primtype == Primitive::PRIMTYPE_Sphere || ((Primitive*)result.data)->m_primtype == Primitive::PRIMTYPE_Box) { //TODO: Calculate reflection ray based on the current intersection result //Recursively call TraceScene with the reflection ray //Combine the returned colour with the current surface colour // DONE m_isReflecting = true; ray.SetRay(result.point, ray.GetRay().Reflect(result.normal)); outcolour *= TraceScene(pScene, ray, outcolour, --tracelevel, shadowray); } } if (m_traceflag & TRACE_REFRACTION) { //Only consider refraction for spheres and boxes if (((Primitive*)result.data)->m_primtype == Primitive::PRIMTYPE_Sphere || ((Primitive*)result.data)->m_primtype == Primitive::PRIMTYPE_Box) { //TODO: Calculate refraction ray based on the current intersection result //Recursively call TraceScene with the reflection ray //Combine the returned colour with the current surface colour // DONE double refractionIndex = 1; // Better refraction that using a constant if (m_isRefracting) { refractionIndex = ((Primitive*)result.data)->GetMaterial()->GetRefractiveIndex() / AIR_REFRACTIVE_INDEX; } else { refractionIndex = AIR_REFRACTIVE_INDEX / ((Primitive*)result.data)->GetMaterial()->GetRefractiveIndex(); } m_isRefracting = true; ray.SetRay(result.point + (result.normal * -0.0001), ray.GetRay().Refract((result.normal), 1)); outcolour += TraceScene(pScene, ray, outcolour, --tracelevel, shadowray) * ((Primitive*)result.data)->GetMaterial()->GetTransparency(); } } //Check if this is in shadow if ( m_traceflag & TRACE_SHADOW ) { std::vector<Light*>::iterator lit_iter = light_list->begin(); while (lit_iter != light_list->end()) { //TODO: Calculate the shadow ray using the current intersection result and the light position //Recursively call TraceScene with the shadow ray // DONE Vector3 l_normal = ((*lit_iter)->GetLightPosition() - result.point).Normalise(); Vector3 l = result.point + (l_normal * 0.0001); ray.SetRay(l, l_normal); outcolour = TraceScene(pScene, ray, outcolour, --tracelevel, true); lit_iter++; } } } return outcolour; }