13,151,912 members (45,998 online)
Add your own
alternative version

#### Stats

52.2K views
68 bookmarked
Posted 24 Jul 2007

# Simple Ray Tracing with Texture Mapping in C#

, 15 Jul 2016
 Rate this:
Please Sign up or sign in to vote.
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 *
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

 Engineer Brazil
Senior Analyst

Linkedin Profile

 Pro

## Comments and Discussions

 View All Threads First Prev Next
 My vote of 5 manoj kumar choubey26-Feb-12 21:45 manoj kumar choubey 26-Feb-12 21:45
 Last Visit: 31-Dec-99 18:00     Last Update: 26-Sep-17 4:24 Refresh 1

General    News    Suggestion    Question    Bug    Answer    Joke    Praise    Rant    Admin

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

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.170924.2 | Last Updated 15 Jul 2016
Article Copyright 2007 by andalmeida
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid