Skip to content

Instantly share code, notes, and snippets.

@wridgers
Created January 18, 2013 23:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wridgers/4569550 to your computer and use it in GitHub Desktop.
Save wridgers/4569550 to your computer and use it in GitHub Desktop.
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