Example #1
0
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;
}