Created
January 18, 2013 23:25
-
-
Save wridgers/4569550 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Tracer::trace() | |
{ | |
// camera setup | |
Vector3 cameraLocation(0, 0, -800); | |
// light setup | |
double lightIntensity = 100.0; | |
Vector3 lightLocation(0, 500, 0); | |
for (int screenIndex = 0; screenIndex < Tracer::screenBufferSize; ++screenIndex ) { | |
// find which pixel this screen cell is for | |
int x = screenIndex % Tracer::renderWidth; | |
int y = (screenIndex - x) / Tracer::renderWidth; | |
// find location of pixel, and get a ray projecting through pixel into scene | |
Vector3 pixelLocation((double)(x-(Tracer::renderWidth/2)), (double)((Tracer::renderHeight/2)-y), 0.0f); | |
// direction of ray | |
Vector3 rayDirection(cameraLocation, pixelLocation); | |
rayDirection.normalise(); | |
// create ray to trace | |
Ray ray(cameraLocation, rayDirection); | |
// find closest point of intersection and object | |
bool intersectionFound = false; | |
Vector3 intersection; | |
Sphere* sphere; | |
double bestT = 0.0f; | |
// for every sphere | |
for (unsigned int sphereIndex = 0; sphereIndex < Tracer::spheres.size(); ++sphereIndex) { | |
// now, check if ray intersects the sphere | |
// get important sphere values | |
Vector3 spherePosition = Tracer::spheres[sphereIndex]->getPosition(); | |
double sphereRadius = Tracer::spheres[sphereIndex]->getRadius(); | |
// make calculation a bit easier | |
Vector3 oMinusC = cameraLocation - spherePosition; | |
// find a,b,c for quadratic formula | |
// double a = rayDirection.dot(rayDirection); | |
// = 1 | |
double b = 2*rayDirection.dot(oMinusC); | |
double c = oMinusC.dot(oMinusC) - (sphereRadius*sphereRadius); | |
// we check the discriminant to see if there is an intersection | |
double discriminant = (b*b) - 4*c; | |
if (discriminant > 0) { | |
// yes! intersection! | |
// find the two solutions (we know there are two, because discriminant > 0) | |
double t1 = (- b + sqrt(discriminant)) * 0.5; | |
double t2 = (- b - sqrt(discriminant)) * 0.5; | |
// we find the closest (smallest) one | |
double t = t1; | |
if (t2 < t1) t = t2; | |
// now find out if this is the closest. | |
if ((!intersectionFound || t < bestT) && t > 0.0) { | |
// we've found at least one intersection | |
intersectionFound = true; | |
// the coordinates of intersection | |
intersection = ray.at(t); | |
// how far away it is | |
bestT = t; | |
// the object ray intersects with | |
sphere = Tracer::spheres[sphereIndex]; | |
} | |
} | |
} | |
// if we found an intersection | |
if (intersectionFound) { | |
// we calculate the direction of the normal at this intersection | |
Vector3 surfaceNormal(sphere->getPosition(), intersection); | |
surfaceNormal.normalise(); | |
// this will be the eventual pixel colour | |
Colour pixelColour; | |
// get sphere's material | |
Material *material = sphere->getMaterial(); | |
Colour sC = material->getColour(); | |
// ADD AMBIENT LIGHTING | |
pixelColour += sC * (material->getAmbientReflectionCoeff() * Tracer::ambientLightingIntensity); | |
// TODO: multiple lights | |
// calculate phong attenuation | |
double lightDistance = Vector3(intersection, lightLocation).magnitude(); | |
double lightAttenuation = lightIntensity / (pow(lightDistance, 0.5) + 0.01); | |
// get direction from intersection to lightLocation | |
Vector3 lightNormal(intersection, lightLocation); | |
lightNormal.normalise(); | |
// if the dot product is negative, it is in shadow | |
double shadowCheck = surfaceNormal.dot(lightNormal); | |
// ADD DIFFUSE LIGHTING | |
if (shadowCheck > 0.0f) { | |
// not in shadow | |
// we 'add' the light from the current light to the screen | |
// pixelColour += sC*shadowCheck; | |
pixelColour += sC * (lightAttenuation * material->getDiffuseReflectionCoeff() * shadowCheck); | |
// normal to camera | |
Vector3 cameraNormal(intersection, cameraLocation); | |
cameraNormal.normalise(); | |
// normal to light | |
// NOTE: we can just use shadowCheck here because it's | |
// surfaceNormal.dot(lightNormal) | |
// also, this is already normalise, don't normalise again! | |
Vector3 lightNormalReflection = (surfaceNormal * shadowCheck * 2) - lightNormal; | |
// now find the angle between these normal vectors | |
// note, these are unit so the magnitude is 1 ;) | |
double cosAlpha = lightNormalReflection.dot(cameraNormal); | |
// TODO: get n value from material ;) | |
double specular = pow(cosAlpha, 5); | |
// occasionally it's negative, why? | |
if (specular < 0) | |
specular = 0; | |
// add to pixel | |
pixelColour += (255 * lightAttenuation * material->getSpecularReflectionCoeff() * specular); | |
} | |
// TODO: ADD REFLECTION RAY | |
// TODO: ADD REFRACTION RAY | |
// set it | |
Tracer::screenBuffer[screenIndex] = pixelColour; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment