Click here to Skip to main content
Click here to Skip to main content

Simple Ray Tracing with Texture Mapping in C#

, 9 Apr 2013
Rate this:
Please Sign up or sign in to vote.
Simple Ray Tracing with texture mapping in C#

Screenshot - lune-p.gif
Source image1

Screenshot - worldmap4.gif
Source image 2

Screenshot - rtmapping.png
Resulting image

Introduction

In my previous articles Mapping Images on Spherical Surfaces Using C# and Simple Ray Tracing in C# we have seen how to map textures onto spheres and as well as a simple ray tracing algorithm. But what combining ray tracing and image mapping?

Background

I recommend at first you read my previous articles, Mapping Images on Spherical Surfaces Using C# and Simple Ray Tracing in C#.

Previously we got the formula below, representing the intersection between a 3D line and a sphere:

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;  // we choose the nearest t from the first point
     }

where

  • r is the sphere radius
  • (cx,cy,cz) is the center of the sphere
  • (vx,vy,vz) is the line direction vector
  • (px,py,pz) is the viewer position

Also, the mapping equation between two different scales image pixels(integer) and floating points (latitudes and longitudes):

public static double MapCoordinate(double i1, double i2, double w1,
                                   double w2, double p)
{
return ((p - i1) / (i2 - i1)) * (w2 - w1) + w1;
}

Now, from each intersection we will get the mapped color from the image.

The Code

        System.Drawing.Image image1 = new Bitmap(Server.
                                      MapPath("./images/worldmap4.gif"));
        Bitmap imgBitmap = new Bitmap(image1);
        System.Drawing.Image image2 = new Bitmap(Server.
                                      MapPath("./images/lune-p.gif"));
        Bitmap imgBitmap2 = new Bitmap(image2);

        Bitmap newBitmap = new Bitmap(200, 200,
                           PixelFormat.Format32bppArgb);
        Graphics g = Graphics.FromImage(newBitmap);

        Color clrBackground = Color.Black;
        g.FillRectangle(new SolidBrush(clrBackground), new Rectangle(0, 0,
                                                           200, 200));
        Rectangle rect = new Rectangle(0, 0, 200, 200);
        ///////////////////////////////////////
        System.Collections.ArrayList obj3dArrayList;
        obj3dArrayList = new System.Collections.ArrayList();

        obj3dArrayList.Add(new Sphere(0.0, 0.0, 90.0, 100.0, 0.0, 0.0,
                               255.0));
        obj3dArrayList.Add(new Sphere(70.0, 70.0, 250.0, 20.0, 255.0,
                               200.0,
                               0.0));
        Graphics graphics = g;

        double px = (double)Session["eyex"],
        py = (double)Session["eyey"],
        pz = (double)Session["eyez"];

        double lpx = (double)Session["lpx"],
        lpy = (double)Session["lpy"],
        lpz = (double)Session["lpz"];

        double lvx = (double)Session["lvx"],
        lvy = (double)Session["lvy"],
        lvz = (double)Session["lvz"];

        double fMax = 200.0;

        // MAP [rect] <-> [-MAX,-MAX, MAX, MAX]
        for (int i = rect.Left; i <= rect.Right; i++)
        {
            double x = Sphere.GetCoord(rect.Left, rect.Right,
                                      -fMax, fMax, i);

            for (int j = rect.Top; j <= rect.Bottom; j++)
            {
                double y = Sphere.GetCoord(rect.Top, rect.Bottom,
                                           fMax, -fMax, j);
                double t = 1.0E10;
                // v (x,y,0) <- p
                double vx = x - px, vy = y - py, vz = -pz;

                double mod_v = Sphere.modv(vx, vy, vz);
                vx = vx / mod_v;
                vy = vy / mod_v;
                vz = vz / mod_v;

                bool bShadow = false;

                Sphere spherehit = null;

                for (int k = 0; k < (int)obj3dArrayList.Count; k++)
                {
                    Sphere sphn = (Sphere)obj3dArrayList[k];
                    double taux = Sphere.GetSphereIntersec(sphn.cx, sphn.cy,
                                  sphn.cz, sphn.radius, px, py, pz,
                                  vx, vy, vz);
                    if (taux < 0) continue;

                    if (taux > 0 && taux < t)
                    {
                        t = taux;
                        spherehit = sphn;
                    }
                }
                Color color = Color.FromArgb(10, 20, 10);

                if (spherehit != null)
                {
                    double itx = px + t * vx, ity = py + t * vy, itz =
                                 pz + t * vz;
                    ////////////////////////////////////
                    //Rotate intersection
                    double rtx=itx-spherehit.cx, rty=ity-spherehit.cy,
                           rtz=itz-spherehit.cz;
                    Algebra.RotX(Math.PI / 2, ref rty, ref rtz);
                    Algebra.RotZ(1.5, ref rtx, ref rty);
                    double phi = Math.Acos(rtz/spherehit.radius);
                    double S = Math.Sqrt(rtx * rtx + rty * rty);
                    double theta;
                    if (rtx >= 0)
                        theta = Math.Asin(rty / S);
                    else
                        theta = Math.PI - Math.Asin(rty / S);

                    if (theta < 0) theta = 2.0 * Math.PI + theta;

                    if (spherehit.radius > 80)
                    {
                        double x1 = Algebra.MapCoordinate(0.0,
                                    Math.PI * 2.0,
                                    imgBitmap.Width - 1, 0.0, theta);
                        double y1 = Algebra.MapCoordinate(0.0, Math.PI, 0.0,
                                    imgBitmap.Height - 1, phi);
                        int i1 = (int)x1, j1 = (int)y1;

                        if (i1 >= 0 && j1 >= 0 && i1 < imgBitmap.Width &&

                            j1 < imgBitmap.Height)
                            color1 = imgBitmap.GetPixel(i1, j1);
                    }
                    else
                    {
                        double x1 = Algebra.MapCoordinate(0.0,
                                    Math.PI * 2.0,
                                    imgBitmap2.Width - 1, 0.0, theta);
                        double y1 = Algebra.MapCoordinate(0.0, Math.PI, 0.0,
                                    imgBitmap2.Height - 1, phi);
                        int i1 = (int)x1, j1 = (int)y1;

                        if (i1 >= 0 && j1 >= 0 && i1 < imgBitmap2.Width
                            && j1 < imgBitmap2.Height)
                            color1 = imgBitmap2.GetPixel(i1, j1);
                    }
                    double tauxla = Sphere.GetSphereIntersec(spherehit.cx,
                                    spherehit.cy, spherehit.cz,
                                    spherehit.radius, lpx, lpy, lpz,
                                    itx - lpx, ity - lpy, itz - lpz);
                    for (int k = 0; k < (int)obj3dArrayList.Count; k++)
                    {
                        Sphere sphnb = (Sphere)(obj3dArrayList[k]);
                        if (sphnb != spherehit)
                        {
                            double tauxlb = Sphere.GetSphereIntersec(
                                            sphnb.cx,
                                            sphnb.cy, sphnb.cz,
                                            sphnb.radius,
                                            lpx, lpy, lpz, itx - lpx,
                                            ity - lpy, itz - lpz);
                            if (tauxlb > 0 && tauxla < tauxlb)
                            {
                                bShadow = true;
                                break;
                            }
                        }
                    }
                    // shadow
                    double cost = Sphere.GetCosAngleV1V2(lvx, lvy, lvz,
                                  itx - spherehit.cx, ity - spherehit.cy,
                                  itz - spherehit.cz);
                    if (cost < 0) cost = 0;
                    double fact = 1.0;
                    if (bShadow == true) fact = 0.5; else fact = 1.0;
                    double rgbR = color1.R * cost * fact;
                    double rgbG = color1.G * cost * fact;
                    double rgbB = color1.B * cost * fact;

                    color = Color.FromArgb((int)rgbR, (int)rgbG, (int)rgbB);
                }
                Brush brs = new SolidBrush(color);
                graphics.FillRectangle(brs, i, j, 1, 1);
                brs.Dispose();
            }// for pixels lines
        }// for pixels columns
        ///////////////////////////////////////
        MemoryStream tempStream = new MemoryStream();
        newBitmap.Save(tempStream, ImageFormat.Png);
        Response.ClearContent();
        Response.ContentType = "image/png";
        Response.BinaryWrite(tempStream.ToArray());
        Response.Flush();

In my next articles I will start to show more complex ray tracing algorithms, using recursive functions, adding transparency, reflection and more reality to the images.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

About the Author

andalmeida
Engineer TIHunter
United States United States
"Full Remote" Senior Analyst at +19547627489 (mobile) - Open for contracts
 
C C++ C# .NET Java Android ASP.NET HTML PHP
 
Founder of TIHunter Vagas de TI
 
Linkedin Profile
Follow on   LinkedIn

Comments and Discussions

 
QuestionIt's nice looking, but PinmemberHaBiX6-Jan-14 0:23 
GeneralMy vote of 5 Pinmembermanoj kumar choubey26-Feb-12 21:45 
GeneralGreat article! PinmemberMarcelo Ricardo de Oliveira25-Mar-10 8:49 
GeneralRe: Great article! Pinmemberandalmeida25-Mar-10 8:56 
GeneralRe: Great article! PinmemberMarcelo Ricardo de Oliveira25-Mar-10 9:10 
GeneralRe: Great article! Pinmemberandalmeida25-Mar-10 9:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 9 Apr 2013
Article Copyright 2007 by andalmeida
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid