Colour Scene::getColourAtIntersection(const Ray &r, const NodeIntersection &ni, const Colour &cEnvironment, uint8_t rayRecursion) const { /* * Do a simple variation on the phong lighting model. This could be improved. * * In my ray tracer the Colour class is analogous to a spectral distribution. * (ie: light flux) */ /* * Evaluation of material properties at this intersection. */ Colour cDiffuse; Colour cSpecular; double phongCoeff = 0.0; double reflectivity = 0.0; double opacity = 1.0; double indexOfRefraction = 1.0; PrimitivePatch bumpedPatch = ni.pPatch; if (ni.mat) { ni.mat->evaluate(ni.pPatch, &cDiffuse, &cSpecular, &phongCoeff, &reflectivity, &opacity, &indexOfRefraction); ni.mat->evaluateBumpMap(ni.pPatch, &bumpedPatch); } /* * Calculate the lighting. */ // XXX need to calculate light attenuation due to distance. Colour diffuseLight; Colour specularLight; for(std::list<Light*>::const_iterator lightIter = mLights.begin(); lightIter != mLights.end(); lightIter++) { Light &curLight = **lightIter; double intersectionTransmissiveness = 0.0; Ray patchToCurLightRay(bumpedPatch.p, normalize(curLight.getPosition() - bumpedPatch.p)); /* * Check if there are any obstructions. */ if (!intersects(patchToCurLightRay, &intersectionTransmissiveness) || !isZero(intersectionTransmissiveness)) { // Rely on short-circuit || to test intersects && intersectionTransmissiveness > 0.0 // Diffuse - cosine weighted angle between normal and light source double diffuseWeight = dot(bumpedPatch.shadingNorm, patchToCurLightRay.d); if (lessThanZero(diffuseWeight)) { diffuseWeight = 0.0; } diffuseLight += (diffuseWeight //* intersectionTransmissiveness * curLight.getColour()); /* * Specular - exponential of cosine weighted angle between the incoming * ray and the reflected ray from the light source. */ Vector reflected = normalize(computeReflection(-patchToCurLightRay.d, bumpedPatch)); double specularWeight = dot(reflected, normalize(-r.d)); if (lessThanZero(specularWeight)) { specularWeight = 0.0; } specularLight += (pow(specularWeight, phongCoeff) * curLight.getColour()); } } /* * Recursive case. */ if (rayRecursion > 0) { /* * Check to see if the material is reflective or transmissive. If it is * this will directly affect the diffuse Colour before it is used in the * final colour computation. */ Ray recR; NodeIntersection recNI; Colour recColour; if (reflectivity > 0.0) { recR = Ray(bumpedPatch.p, computeReflection(r.d, bumpedPatch)); if (intersect(recR, &recNI)) { recColour = getColourAtIntersection(recR, recNI, cEnvironment, rayRecursion - 1); // Do a simple Alpha composite. cDiffuse = (cDiffuse * (1-reflectivity)) + (recColour * reflectivity); } else { // Didn't intersect with anything so take the env colour. cDiffuse = (cDiffuse * (1-reflectivity)) + (cEnvironment * reflectivity); } } if (opacity < 1.0) { // XXX need to work out the refraction using Snell's law. recR = Ray(bumpedPatch.p, r.d); if (intersect(recR, &recNI)) { recColour = getColourAtIntersection(recR, recNI, cEnvironment, rayRecursion - 1); // Do a simple Alpha composite. cDiffuse = (cDiffuse * opacity) + (recColour * (1 - opacity)); } else { // Didn't intersect with anything so take the env colour. cDiffuse = (cDiffuse * opacity) + (cEnvironment * (1 - opacity)); } } } /* * Base Case. */ /* * Apply lighting calculations onto the diffuse and specular lighting * components of the material evaluated at the curent intersection point. */ Colour c = getAmbient(); // XXX need to multiply emmissive component if the object is a light source. if (!cDiffuse.isBlack()) { c += cDiffuse * diffuseLight; } // Need to calculate attenuation from distance of the light if (!cSpecular.isBlack()) { c += cSpecular * specularLight; } return c; }