Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Simple Ray Tracing in C# Part IV (Anti-Aliasing)

0.00/5 (No votes)
15 Jul 2016 1  
Simple Ray Tracing in C# Part IV (Anti-Aliasing)

Screenshot - aliasedB.png
Aliased

Screenshot - oneshotB.png
Anti-aliased

Introduction

Anti-aliasing is the name for techniques designed to reduce or eliminate the jagged effect of square pixels attempting to approximate curved shapes.

Screenshot - aliasedcurve.png

Aliased curve

Here we focus on shading the pixels using an averaging algorithm, adding anti-aliasing to our basic ray tracing. For this, instead of only one ray per pixel, we will fire 4 extra rays around each pixel, calculate the color average between the 5 results, and then plot the pixel with the resulting value.

Screenshot - px2.png

Background

I recommend a quick reading of the previous articles:

Using the Code

At first, let's calculate the distance between 2 adjacent pixels in our model coordinates:

double deltaP = Math.Abs(tAlgebra.GetCoord(rect.Left, rect.Right, 
    -fMax, fMax, rect.Left+1)+fMax);

Now for each original ray, we will fire 4 extra rays as a bounding square around the main original ray:

...
ray.x1 = x - deltaP; ray.y1 = y - deltaP; ray.z1 = 0.0;
tPoint colorA = ray.trace_ray(ray);
normalizeColor(ref colorA);

ray.x1 = x - deltaP; ray.y1 = y + deltaP; ray.z1 = 0.0;
tPoint colorB = ray.trace_ray(ray);
normalizeColor(ref colorB);

ray.x1 = x + deltaP; ray.y1 = y - deltaP; ray.z1 = 0.0;
tPoint colorC = ray.trace_ray(ray);
normalizeColor(ref colorC);

ray.x1 = x + deltaP ; ray.y1 = y + deltaP; ray.z1 = 0.0;
tPoint colorD = ray.trace_ray(ray);
normalizeColor(ref colorD);

ray.x1 = x; ray.y1 = y; ray.z1 = 0.0;
tPoint colorE = ray.trace_ray(ray);
normalizeColor(ref colorE); 
 
// calculate the average 
color.x = (colorA.x + colorB.x + colorC.x + colorD.x + colorE.x) / 5.0;
color.y = (colorA.y + colorB.y + colorC.y + colorD.y + colorE.y) / 5.0;
color.z = (colorA.z + colorB.z + colorC.z + colorD.z + colorE.z) / 5.0;
normalizeColor(ref color);
 
// plot the pixel 
Color colorpx = Color.FromArgb((int)color.x, (int)color.y, (int)color.z);
newBitmap.SetPixel(i, j, colorpx); 
...
// a helper function to normalize colors
public void normalizeColor(ref tPoint color)
{
    color.x = Math.Min(color.x, 255);
    color.y = Math.Min(color.y, 255);
    color.z = Math.Min(color.z, 255);
    color.x = Math.Max(color.x, 0);
    color.y = Math.Max(color.y, 0);
    color.z = Math.Max(color.z, 0);
}

Algebra Class

public class tAlgebra
{
    public tAlgebra()
    {
    }
    public static double GetCoord(double i1, double i2, double w1, 
        double w2, double p)
    {
        return ((p - i1) / (i2 - i1)) * (w2 - w1) + w1;
    }
    public static void Cross3(double ax, double ay, double az,
        double bx, double by, double bz,
        ref double outx, ref double outy, ref double outz)
    {
        outx = ay * bz - az * by;
        outy = az * bx - ax * bz;
        outz = ax * by - ay * bx;
    }
    public static void Refract(double n1, double n2, 
        double inx, double iny, double inz,
        double mirrorx, double mirrory, 
        double mirrorz,
        ref double outx, ref double outy, 
        ref double outz)
    {
        double c1 = -Dot3(mirrorx, mirrory, mirrorz, inx, iny, inz);
        double n = n1 / n2;

        double c2 = Math.Sqrt(1.0 - n * n * (1.0 - c1 * c1));
        outx = (n * inx) + (n * c1 - c2) * mirrorx;
        outy = (n * iny) + (n * c1 - c2) * mirrory;
        outz = (n * inz) + (n * c1 - c2) * mirrorz;
    }
    public static void Reflect(double inx, double iny, double inz,
        double mirrorx, double mirrory, double mirrorz,
        ref double outx, ref double outy, ref double outz)
    {
        double c1 = -Dot3(mirrorx, mirrory, mirrorz, inx, iny, inz);

        //Rl = V + (2 * N * c1 )
        outx = -(inx + (2 * mirrorx * c1));
        outy = -(iny + (2 * mirrory * c1));
        outz = -(inz + (2 * mirrorz * c1));
    }
    public static double Dot3(double x1, double y1, double z1, 
        double x2, double y2, double z2)
    {
        return ((x1 * x2) + (y1 * y2) + (z1 * z2));
    } 
    // * note: use normalized vectors here!
    public static double GetCosAngleV1V2(double v1x, double v1y, 
        double v1z, double v2x, double v2y, double v2z)
    {
        // cos(t) = (v.w) / (|v|.|w|) = (v.w) / 1
        return Dot3(v1x, v1y, v1z, v2x, v2y, v2z);
    }
    public static double modv(double vx, double vy, double vz)
    {
        return System.Math.Sqrt(vx * vx + vy * vy + vz * vz);
    }
    public static bool Normalize(ref double vx, ref double vy, 
        ref double vz)
    {
        double mod_v = tAlgebra.modv(vx, vy, vz);
        double eps = 1.0E-20;
        if (Math.Abs(mod_v) < eps)
            return true;

        vx = vx / mod_v;
        vy = vy / mod_v;
        vz = vz / mod_v;
        return false;
    }
    public static void RotX(double angle, ref double y, ref double z)
    {
        double y1 = y * System.Math.Cos(angle) - z * 
            System.Math.Sin(angle);
        double z1 = y * System.Math.Sin(angle) + z * 
            System.Math.Cos(angle);
        y = y1;
        z = z1;
    }
    public static void RotY(double angle, ref double x, ref double z)
    {
        double x1 = x * System.Math.Cos(angle) - z * 
            System.Math.Sin(angle);
        double z1 = x * System.Math.Sin(angle) + z * 
            System.Math.Cos(angle);
        x = x1;
        z = z1;
    }
    public static void RotZ(double angle, ref double x, ref double y)
    {
        double x1 = x * System.Math.Cos(angle) - y * 
            System.Math.Sin(angle);
        double y1 = x * System.Math.Sin(angle) + y * 
            System.Math.Cos(angle);
        x = x1;
        y = y1;
    }
}

Now, as seen before, we need a class to define materials in terms of ambient, diffuse and specular parameters:

Material Class

public class tMaterial
{
    public double ambientR, ambientG, ambientB, ambientA;
    public double diffuseR, diffuseG, diffuseB, diffuseA;
    public double specularR, specularG, specularB, specularA;
    public double shininess;
    public double alpha;
}

R3 Point Class

public class tPoint
{
    public double x = 0, y = 0, z = 0;
}

In order to create the objects, spheres and triangles, I have created a base abstract class called tObject, and the derived tSphere and tTriangle:

Object Class

public abstract class tObject
{
    public tObject()
    {
    }
    public tPoint get_point_color(System.Collections.ArrayList lights, 
        tRay ray)
    {
        tPoint color = new tPoint();
        tPoint normal = new tPoint();
        tPoint rayV = ray.getRay();

        //for each light // i leave it to the next article :) 
        tPoint light = (tPoint)lights[0];
        getNormal(hitpoint.x, hitpoint.y, hitpoint.z,
            ref normal.x, ref normal.y, ref normal.z);

        double lvX = light.x - hitpoint.x,
            lvY = light.y - hitpoint.y,
            lvZ = light.z - hitpoint.z;

        tAlgebra.Normalize(ref normal.x, ref normal.y, ref normal.z);
        tAlgebra.Normalize(ref lvX, ref lvY, ref lvZ);

        double cost = tAlgebra.GetCosAngleV1V2(lvX, lvY, lvZ,
            normal.x, normal.y, normal.z);
        double cosf = 0;

        tAlgebra.Reflect(-lvX, -lvY, -lvZ,
            normal.x, normal.y, normal.z,
            ref vReflX, ref vReflY, ref vReflZ);
        tAlgebra.Normalize(ref vReflX, ref vReflY, ref vReflZ);
        tAlgebra.Normalize(ref rayV.x, ref rayV.y, ref rayV.z);

        cosf = tAlgebra.GetCosAngleV1V2(rayV.x, rayV.y, rayV.z, 
            vReflX, vReflY, vReflZ);
        double result1 = Math.Max(0, cost) * 255.0;
        double result2 = Math.Pow(Math.Max(0, cosf), 
            material.shininess) * 255.0;

        double rgbR = (material.ambientR * 255.0) +
            (material.diffuseR * result1) +
            (material.specularR * result2);
        double rgbG = (material.ambientG * 255.0) +
            (material.diffuseG * result1) +
            (material.specularG * result2);
        double rgbB = (material.ambientB * 255.0) +
            (material.diffuseB * result1) +
            (material.specularB * result2);

        color.x = rgbR;
        color.y = rgbG;
        color.z = rgbB;
        return color;
    }
    public tRay get_reflected_ray(tRay original_ray)
    {
        tRay ray = new tRay();
        double inx = 0, iny = 0, inz = 0, nx = 0, ny = 0, nz = 0, 
            rx = 0, ry = 0, rz = 0;

        getNormal(hitpoint.x, hitpoint.y, hitpoint.z, 
            ref nx, ref ny, ref nz);

        inx = original_ray.getRay().x;
        iny = original_ray.getRay().y;
        inz = original_ray.getRay().z;

        tAlgebra.Normalize(ref inx, ref iny, ref inz);
        tAlgebra.Normalize(ref nx, ref ny, ref nz);
        tAlgebra.Reflect(-inx, -iny, -inz, nx, ny, nz, ref rx, 
            ref ry, ref rz);
        tAlgebra.Normalize(ref rx, ref ry, ref rz);

        ray.x0 = hitpoint.x;
        ray.y0 = hitpoint.y;
        ray.z0 = hitpoint.z;
        ray.x1 = (hitpoint.x + rx);
        ray.y1 = (hitpoint.y + ry);
        ray.z1 = (hitpoint.z + rz);
        return ray;
    }
    public tMaterial material
    {
        get
        {
            return tmaterial;
        }
        set
        {
            tmaterial = value;
        }
    }
    public tPoint hitpoint
    {
        get
        {
            return tHitPoint;
        }
        set
        {
            tHitPoint = value;
        }
    }
    private tMaterial tmaterial;
    private tPoint tHitPoint;
    private double vReflX = 0, vReflY = 0, vReflZ = 0;

    public abstract double GetIntersect(double p1x, double p1y, double p1z,
        double p2x, double p2y, double p2z);
    public abstract void getNormal(double x, double y, double z,
        ref double nx, ref double ny, ref double nz);

    public tRay get_refracted_ray(tRay original_ray)
    {
        tRay ray = new tRay();
        double inx = 0, iny = 0, inz = 0, 
            nx = 0, ny = 0, nz = 0, rx = 0, ry = 0, rz = 0;
        getNormal(hitpoint.x, hitpoint.y, hitpoint.z, 
            ref nx, ref ny, ref nz);

        inx = original_ray.getRay().x;
        iny = original_ray.getRay().y;
        inz = original_ray.getRay().z;

        tAlgebra.Normalize(ref inx, ref iny, ref inz);
        tAlgebra.Normalize(ref nx, ref ny, ref nz);

        double n1 = 1.00;
        double n2 = 1.50;

        tAlgebra.Refract(n1, n2, -inx, -iny, -inz, nx, ny, nz, 
            ref rx, ref ry, ref rz);
        tAlgebra.Normalize(ref rx, ref ry, ref rz);

        ray.x0 = hitpoint.x;
        ray.y0 = hitpoint.y;
        ray.z0 = hitpoint.z;
        ray.x1 = (hitpoint.x + rx);
        ray.y1 = (hitpoint.y + ry);
        ray.z1 = (hitpoint.z + rz);
        return ray;
    }
}

Sphere Class

public class tSphere : tObject
{
    public tSphere(double x, double y, double z, double r)
    {
        cx = x;
        cy = y;
        cz = z;
        radius = r;
    }

    void Move(double vx, double vy, double vz)
    {
        cx += vx;
        cy += vy;
        cz += vz;
    }

    void MoveTo(double vx, double vy, double vz)
    {
        cx = vx;
        cy = vy;
        cz = vz;
    }

    public override double GetIntersect(double px, double py, double pz, 
        double x, double y, double z)
    {
        // x-xo 2 + y-yo 2 + z-zo 2 = r 2
        // x,y,z = p+tv 
        // At2 + Bt + C = 0
        double vx = x - px;
        double vy = y - py;
        double vz = z - pz;

        double A = (vx * vx + vy * vy + vz * vz);
        double B = 2.0 * (px * vx + py * vy + 
            pz * vz - vx * cx - vy * cy - vz * cz);
        double C = px * px - 2 * px * cx + cx * cx + 
            py * py - 2 * py * cy + cy * cy + pz * pz - 
            2 * pz * cz + cz * cz - radius * radius;
        double D = B * B - 4 * A * C;
        double t = -1.0;

        if (D >= 0)
        {
            double t1 = (-B - System.Math.Sqrt(D)) / (2.0 * A);
            double t2 = (-B + System.Math.Sqrt(D)) / (2.0 * A);
            if (t1 < t2) 
                t = t1; 
            else 
                t = t2;

            tPoint pt = new tPoint();
            pt.x = px + t * vx;
            pt.y = py + t * vy;
            pt.z = pz + t * vz;
            hitpoint = pt;
        }
        return t;
    }

    public override void getNormal(double x, double y, double z, 
        ref double nx, ref double ny, ref double nz)
    {
        nx = x - cx;
        ny = y - cy;
        nz = z - cz;
    }

    public double cx, cy, cz, radius, clR, clG, clB;
}

Triangle Class

public class tTriangle : tObject
{
    public tTriangle()
    {
    }

    public void Init()
    {
        GetNormal(ref tnormalX, ref tnormalY, ref tnormalZ);
    }

    public bool SameSide(double p1x, double p1y, double p1z,
        double p2x, double p2y, double p2z,
        double ax, double ay, double az,
        double bx, double by, double bz)
    {
        double cp1x = 0, cp1y = 0, cp1z = 0, cp2x = 0, cp2y = 0,
            cp2z = 0;
        tAlgebra.Cross3(bx - ax, by - ay, bz - az, p1x - ax,
            p1y - ay, p1z - az, ref cp1x, ref cp1y, ref cp1z);
        tAlgebra.Cross3(bx - ax, by - ay, bz - az, p2x - ax,
            p2y - ay, p2z - az, ref cp2x, ref cp2y, ref cp2z);
        if (tAlgebra.Dot3(cp1x, cp1y, cp1z, cp2x, cp2y, cp2z) >= 0)
            return true;
        else
            return false;
    }

    public bool PointInTriangle(double px, double py, double pz)
    {
        if (SameSide(px, py, pz, tp1x, tp1y, tp1z,
            tp2x, tp2y, tp2z, tp3x, tp3y, tp3z) &&
        SameSide(px, py, pz, tp2x, tp2y, tp2z,
            tp1x, tp1y, tp1z, tp3x, tp3y, tp3z) &&
        SameSide(px, py, pz, tp3x, tp3y, tp3z,
            tp1x, tp1y, tp1z, tp2x, tp2y, tp2z))
            return true;
        else
            return false;
    }

    // ray p1, ray p2
    public override double GetIntersect(double p1x, double p1y, double p1z,
        double p2x, double p2y, double p2z)
    {
        double v1x = tp3x - p1x;
        double v1y = tp3y - p1y;
        double v1z = tp3z - p1z;
        double v2x = p2x - p1x;
        double v2y = p2y - p1y;
        double v2z = p2z - p1z;
        double dot1 = tAlgebra.Dot3(tnormalX, tnormalY, tnormalZ,
            v1x, v1y, v1z);
        double dot2 = tAlgebra.Dot3(tnormalX, tnormalY, tnormalZ,
            v2x, v2y, v2z);
        if (Math.Abs(dot2) < 1.0E-6)
            return -1; // division by 0 means parallel
        double u = dot1 / dot2;
        // point in triangle?
        if (!PointInTriangle(p1x + u * (p2x - p1x),
            p1y + u * (p2y - p1y), p1z + u * (p2z - p1z)))
            return -1;

        tPoint pt = new tPoint();
        pt.x = p1x + u * v2x;
        pt.y = p1y + u * v2y;
        pt.z = p1z + u * v2z;

        hitpoint = pt;
        return u;
    }

    protected void GetNormal(ref double nx, ref double ny, ref double nz)
    {
        double ux = tp3x - tp1x, uy = tp3y - tp1y, uz = tp3z - tp1z;
        double wx = tp2x - tp1x, wy = tp2y - tp1y, wz = tp2z - tp1z;


        // u x w
        nx = wz * uy - wy * uz;
        ny = wx * uz - wz * ux;
        nz = wy * ux - wx * uy;
    }

    public override void getNormal(double x, double y, double z, 
        ref double nx, ref double ny, ref double nz)
    {
        nx = -tnormalX;
        ny = -tnormalY;
        nz = -tnormalZ;
    }

    // should be private with get/set
    public double tp1x, tp1y, tp1z;
    public double tp2x, tp2y, tp2z;
    public double tp3x, tp3y, tp3z;
    public double tnormalX, tnormalY, tnormalZ;
}

Now, Finally, the Ray-tracing Class

public class tRay
{
    // rotation
    public double rx = 0.0, ry = 0.0, rz = 0.0;
    public double x0 = 0, y0 = 0, z0 = 0;
    public double x1 = 0, y1 = 0, z1 = 0;
    public int levels = 3;
    int level = 0;
    System.Collections.ArrayList obj3dArrayList;
    System.Collections.ArrayList lightsArrayList;

    public tRay()
    {
        obj3dArrayList = new System.Collections.ArrayList();
        lightsArrayList = new System.Collections.ArrayList();
    }
    public void AddTriangle(double ax, double ay, double az,
        double bx, double by, double bz,
        double cx, double cy, double cz, 
        tMaterial mat)
    {
        tTriangle tri = new tTriangle();
        tri.tp1x = ax;
        tri.tp1y = ay;
        tri.tp1z = az;
        tri.tp2x = bx;
        tri.tp2y = by;
        tri.tp2z = bz;
        tri.tp3x = cx;
        tri.tp3y = cy;
        tri.tp3z = cz;

        tAlgebra.RotX(rx, ref tri.tp1y, ref tri.tp1z);
        tAlgebra.RotX(rx, ref tri.tp2y, ref tri.tp2z);
        tAlgebra.RotX(rx, ref tri.tp3y, ref tri.tp3z);
        tAlgebra.RotY(ry, ref tri.tp1x, ref tri.tp1z);
        tAlgebra.RotY(ry, ref tri.tp2x, ref tri.tp2z);
        tAlgebra.RotY(ry, ref tri.tp3x, ref tri.tp3z);
        tAlgebra.RotZ(rz, ref tri.tp1x, ref tri.tp1y);
        tAlgebra.RotZ(rz, ref tri.tp2x, ref tri.tp2y);
        tAlgebra.RotZ(rz, ref tri.tp3x, ref tri.tp3y);

        tri.material = mat;
        tri.Init();
        AddObject(tri);
    }
    public void AddLight(tPoint light)
    {
        tAlgebra.RotX(rx, ref light.y, ref light.z);
        tAlgebra.RotY(ry, ref light.x, ref light.z);
        tAlgebra.RotZ(rz, ref light.x, ref light.y);
        lightsArrayList.Add(light);
    }
    public void AddObject(tObject obj)
    {
        obj3dArrayList.Add(obj);
    }
    private tObject get_first_intersection(tRay original_ray)
    {
        double eps = 1.0E-4; 
        double t = 1.0E10;

        tObject objhit = null;

        for (int k = 0; k < (int)obj3dArrayList.Count; k++)
        {
            tObject objn = (tObject)obj3dArrayList[k];
            double taux = objn.GetIntersect(original_ray.x0, 
                original_ray.y0, original_ray.z0,
                original_ray.x1, original_ray.y1, 
                original_ray.z1);

            if (Math.Abs(taux) <= eps) continue; 

            if (taux > 0 && taux < t)
            {
                t = taux;
                objhit = objn;
            }
        }
        return objhit;
    }
    public tPoint trace_ray(tRay original_ray)
    {
        level++;
        tPoint point_color = new tPoint(), reflect_color = new tPoint(), 
            refract_color = new tPoint();
        if (level > levels)
        {
            level--;
            point_color.x = 0;
            point_color.y = 0;
            point_color.z = 0; 
            return point_color;
        }
        tObject obj = get_first_intersection(original_ray);
        if (obj != null)
        {
            point_color = obj.get_point_color(lightsArrayList, 
                original_ray);
            tRay rfl = obj.get_reflected_ray(original_ray);
            tRay rfr = obj.get_refracted_ray(original_ray);
            tPoint clraux = new tPoint();
            bool brfl = false, brfr = false;
            reflect_color = trace_ray(rfl);
            if (reflect_color.x > 0 || reflect_color.y > 0 || 
                reflect_color.z > 0)
            {
                brfl = true;
            }
            if (obj.material.alpha < 1.0)
            {
                refract_color = trace_ray(rfr);
                if (refract_color.x > 0 || refract_color.y > 0 || 
                    refract_color.z > 0)
                    brfr = true;
            }
            if (brfl && brfr)
            {
                clraux.x = (3 * point_color.x + reflect_color.x + 5 * 
                    refract_color.x) / 9;
                clraux.y = (3 * point_color.y + reflect_color.y + 5 * 
                    refract_color.y) / 9;
                clraux.z = (3 * point_color.z + reflect_color.z + 5 * 
                    refract_color.z) / 9;
            }
            else
                if (brfl)
                {
                    clraux.x = (point_color.x + reflect_color.x) / 2;
                    clraux.y = (point_color.y + reflect_color.y) / 2;
                    clraux.z = (point_color.z + reflect_color.z) / 2;
                }
                else
                    if (brfr)
                    {
                        clraux.x = (3 * point_color.x + 5 * 
                            refract_color.x) / 8;
                        clraux.y = (3 * point_color.y + 5 * 
                            refract_color.y) / 8;
                        clraux.z = (3 * point_color.z + 5 * 
                            refract_color.z) / 8;
                    }
                    else
                    {
                        clraux.x = point_color.x;
                        clraux.y = point_color.y;
                        clraux.z = point_color.z;
                    }
                    level--;
                    return clraux; // combine with other
        }
        level--;
        return point_color;
    }
    public tPoint getRay()
    {
        tPoint ray = new tPoint();
        ray.x = x1 - x0;
        ray.y = y1 - y0;
        ray.z = z1 - z0;
        return ray;
    }
    public void AddSphere(double cx, double cy, double cz, double radius, 
        tMaterial mat)
    {
        tAlgebra.RotX(rx, ref cy, ref cz);
        tAlgebra.RotY(ry, ref cx, ref cz);
        tAlgebra.RotZ(rz, ref cx, ref cy);
        tSphere sph = new tSphere(cx, cy, cz, radius);
        sph.material = mat;
        AddObject(sph);
    }
}

Code Usage Samples

Follow these samples of code usage.

Bitmap newBitmap = new Bitmap(300, 300, PixelFormat.Format32bppArgb);

Graphics g = Graphics.FromImage(newBitmap);
Rectangle rect = new Rectangle(0, 0, 300, 300);
double fMax = 610.0;

tRay ray = new tRay();
ray.rx = 0.0; ray.ry = 0.0; ray.rz = 0.0;
ray.levels = 10;

tPoint pt = new tPoint();
pt.x = 250;
pt.y = 250;
pt.z = 630;
ray.AddLight(pt);

tMaterial mat1 = new tMaterial();
mat1.alpha = 1.0;
mat1.ambientR = 0.1324;
mat1.ambientG = 0.0324;
mat1.ambientB = 0.0236;
mat1.specularR = 0.651;
mat1.specularG = 0.351;
mat1.specularB = 0.351;
mat1.shininess = 20;
mat1.diffuseR = 0.4775;
mat1.diffuseG = 0.2775;
mat1.diffuseB = 0.2775;

tMaterial mat2 = new tMaterial();
mat2.alpha = 0.20;
mat2.ambientR = 0.00000;
mat2.ambientG = 0.00000;
mat2.ambientB = 0.00000;
mat2.specularR = 0.35;
mat2.specularG = 0.35;
mat2.specularB = 0.35;
mat2.shininess = 200.0;
mat2.diffuseR = 0.00;
mat2.diffuseG = 0.00;
mat2.diffuseB = 0.00;

tMaterial mat3 = new tMaterial();
mat3.alpha = 1.0;
mat3.ambientR = 0.2324;
mat3.ambientG = 0.2324;
mat3.ambientB = 0.3236;
mat3.specularR = 0.351;
mat3.specularG = 0.351;
mat3.specularB = 0.851;
mat3.shininess = 20;
mat3.diffuseR = 0.3775;
mat3.diffuseG = 0.3775;
mat3.diffuseB = 0.6775;

tMaterial mat4 = new tMaterial();
mat4.alpha = 1.0;
mat4.ambientR = 0.0124;
mat4.ambientG = 0.0124;
mat4.ambientB = 0.0136;
mat4.specularR = 0.451;
mat4.specularG = 0.451;
mat4.specularB = 0.451;
mat4.shininess = 2;
mat4.diffuseR = 0.0775;
mat4.diffuseG = 0.0775;
mat4.diffuseB = 0.0775;

tMaterial mat5 = new tMaterial();
mat5.alpha = 1.0;
mat5.ambientR = 0.39124;
mat5.ambientG = 0.39124;
mat5.ambientB = 0.39136;
mat5.specularR = 0.251;
mat5.specularG = 0.251;
mat5.specularB = 0.251;
mat5.shininess = 2;
mat5.diffuseR = 0.5775;
mat5.diffuseG = 0.5775;
mat5.diffuseB = 0.5775;

tMaterial mat6 = new tMaterial();
mat6.alpha = 1.0;
mat6.ambientR = 0.11124;
mat6.ambientG = 0.49124;
mat6.ambientB = 0.11136;
mat6.specularR = 0.151;
mat6.specularG = 0.651;
mat6.specularB = 0.151;
mat6.shininess = 35;
mat6.diffuseR = 0.1775;
mat6.diffuseG = 0.3775;
mat6.diffuseB = 0.1775;

tMaterial mat7 = new tMaterial();
mat7.alpha = 1.0;
mat7.ambientR = 0.23735;
mat7.ambientG = 0.23735;
mat7.ambientB = 0.23735;
mat7.specularR = 0.773911;
mat7.specularG = 0.773911;
mat7.specularB = 0.773911;
mat7.shininess = 89;
mat7.diffuseR = 0.2775;
mat7.diffuseG = 0.2775;
mat7.diffuseB = 0.2775;

ray.AddSphere(300, 300, 150, 150, mat1);
ray.AddSphere(0, 0, 150, 150, mat2);
ray.AddSphere(-300, 300, 150, 150, mat3);
ray.AddSphere(300, -300, 150, 150, mat6);
ray.AddSphere(-300, -300, 150, 150, mat7);

ray.AddTriangle(0, 500, 0, -500, 500, 0, -500, 0, 0, mat4);
ray.AddTriangle(0, 500, 0, -500, 0, 0, 0, 0, 0, mat4);
ray.AddTriangle(0, 0, 0, 0, -500, 0, 500, 0, 0, mat4);
ray.AddTriangle(500, 0, 0, 0, -500, 0, 500, -500, 0, mat4);
ray.AddTriangle(500, 500, 0, 0, 500, 0, 0, 0, 0, mat5);
ray.AddTriangle(500, 500, 0, 0, 0, 0, 500, 0, 0, mat5);
ray.AddTriangle(-500, 0, 0, -500, -500, 0, 0, 0, 0, mat5);
ray.AddTriangle(0, 0, 0, -500, -500, 0, 0, -500, 0, mat5);

ray.x0 = 0; ray.y0 = 0; ray.z0 = 2000;

tPoint color = new tPoint();
for (int i = rect.Left; i <= rect.Right; i++)
{
    double x = tAlgebra.GetCoord(rect.Left, rect.Right, 
        -fMax, fMax, i);
    for (int j = rect.Top; j <= rect.Bottom; j++)
    {
        double y = tAlgebra.GetCoord(rect.Top, rect.Bottom, 
            fMax, -fMax, j);
        ray.x1 = x - deltaP; ray.y1 = y - deltaP; ray.z1 = 0.0;
        tPoint colorA = ray.trace_ray(ray);
        normalizeColor(ref colorA);

        ray.x1 = x - deltaP; ray.y1 = y + deltaP; ray.z1 = 0.0;
        tPoint colorB = ray.trace_ray(ray);
        normalizeColor(ref colorB);

        ray.x1 = x + deltaP; ray.y1 = y - deltaP; ray.z1 = 0.0;
        tPoint colorC = ray.trace_ray(ray);
        normalizeColor(ref colorC);

        ray.x1 = x + deltaP ; ray.y1 = y + deltaP; ray.z1 = 0.0;
        tPoint colorD = ray.trace_ray(ray);
        normalizeColor(ref colorD);

        ray.x1 = x; ray.y1 = y; ray.z1 = 0.0;
        tPoint colorE = ray.trace_ray(ray);
        normalizeColor(ref colorE); 

        // calculate the average 
        color.x = (colorA.x + colorB.x + colorC.x + colorD.x + 
            colorE.x) / 5.0;
        color.y = (colorA.y + colorB.y + colorC.y + colorD.y + 
            colorE.y) / 5.0;
        color.z = (colorA.z + colorB.z + colorC.z + colorD.z + 
            colorE.z) / 5.0;
        normalizeColor(ref color);

        // plot the pixel 
        Color colorpx = Color.FromArgb((int)color.x, (int)color.y, 
            (int)color.z);
        newBitmap.SetPixel(i, j, colorpx); 
    }
}
...

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here