Simple Ray Tracing with Texture Mapping in C#

, 9 Apr 2013 GPL3
 Rate this:
Simple Ray Tracing with texture mapping in C#

Source image1

Source image 2

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 *
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;

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,
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 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;

{
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,
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,
lpx, lpy, lpz, itx - lpx,
ity - lpy, itz - lpz);
if (tauxlb > 0 && tauxla < tauxlb)
{
break;
}
}
}
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.

Share

Engineer IBM
Brazil
Senior Analyst

Founder of TIHunter Vagas de TI

 First Prev Next
 It's nice looking, but HaBiX 6-Jan-14 1:23
 My vote of 5 manoj kumar choubey 26-Feb-12 22:45
 Great article! Marcelo Ricardo de Oliveira 25-Mar-10 9:49
 I can't believe I'm the first to put a comment here! Great work!   meus parabéns marcelo Take a look at XNA Snooker Club game here in Code Project.
 Re: Great article! andalmeida 25-Mar-10 9:56
 Re: Great article! Marcelo Ricardo de Oliveira 25-Mar-10 10:10
 Re: Great article! andalmeida 25-Mar-10 10:11
 Last Visit: 31-Dec-99 19:00     Last Update: 31-Mar-15 19:48 Refresh 1