Color traceRay(Ray* ray, Scene* scene, int objectCount, int lightCount, int maxBounces, double ambientLighting) { Color shaderResult (0,0,0); Ray* shadowRay = new Ray(); Ray* reflectionRay = new Ray(); RayIntersection primaryObjectHit = testRayIntersection(ray, scene, objectCount, 0, MINIMAL_DISTANCE); if(primaryObjectHit.objectId >= 0) { Object* sceneObject = scene->getObjectList().at(primaryObjectHit.objectId); // calulate brightness and specularity Color specular (0,0,0); Color diffuse (0,0,0); Color reflection (0,0,0); Vect intersectionPoint = primaryObjectHit.location; Color ambient = sceneObject->getColorAt(intersectionPoint).scale(ambientLighting); shadowRay->setOrigin(intersectionPoint); Vect normalAtIntersection = sceneObject->getNormalAt(intersectionPoint); Vect reflectionDirection = ray->getReflectingDirection(normalAtIntersection); double lightImportance = 1; if(lightCount > 1) { lightImportance = 1.0 / lightCount; } for(int lightIndex = 0; lightIndex < lightCount; lightIndex++) { Light *lightSource = scene->getLightList().at(lightIndex); Vect pointToLightVect = lightSource->getPosition().subtract(intersectionPoint); Vect lightDirection = pointToLightVect.normalize(); // Test if light is visible or hidden to render shadows double diffuseFactor = normalAtIntersection.dot(lightDirection); double specularFactor = reflectionDirection.dot(lightDirection); bool shadowed = false; if(diffuseFactor > 0) // object is facing the light source - add diffuse { // check if it is shadowed; shadowRay->setDirection(lightDirection); double lightDistance = pointToLightVect.magnitude(); shadowed = (testRayIntersection(shadowRay, scene, objectCount, lightDistance, MINIMAL_DISTANCE).objectId > -1); } if(!shadowed && diffuseFactor > 0) { diffuse = diffuse.add(sceneObject->getColorAt(intersectionPoint).scale(diffuseFactor)); } if(!shadowed && specularFactor > 0 && sceneObject->getMaterial().getRoughness() > 0) { specular = specular.add(lightSource->getColor().scale(pow(specularFactor, 10) * sceneObject->getMaterial().getRoughness())); } } if(maxBounces > 0 && sceneObject->getMaterial().getReflectivity() > 0) { reflectionRay->setOrigin(intersectionPoint); reflectionRay->setDirection(reflectionDirection); reflection = traceRay(reflectionRay, scene, objectCount, lightCount, --maxBounces, ambientLighting).scale(sceneObject->getMaterial().getReflectivity() * 0.25); } shaderResult = ambient.add(diffuse).add(specular).add(reflection).normalize(); } else { shaderResult = scene->getBackgroundColor(); } delete shadowRay; delete reflectionRay; return shaderResult; }