14,698,691 members
Articles » Multimedia » General Graphics » Graphics
Article
Posted 5 Sep 2007

105.3K views
117 bookmarked

Simple Ray Tracing in C# Part VII (Shadows)

Rate me:
15 Jul 2016GPL3

 Fig. 1 - Basic sample of shadows Fig. 2 - Basic sample of shadows

Introduction

In this article we will add shadows to our ray tracing. This will give a bit more of a realistic appearance to our final images, and at this point in our implementation if you have patience the results can be amazing.

Background

At first I recommend a previous reading in the last ray tracing articles.

The process of adding shadows used here is simple: for each object intersection point, which I call hitpoint, we trace a ray toward the light, and if this ray hits another object so we have shadow at hitpoint, and them we reduce the rgb color at the hitpoint by a percentage.

```...
tRay ltShot = new tRay();
ltShot.origin = (tPoint)lightsArrayList[0];
ltShot.target = obj.hitpoint;
tElementBase objS = get_first_intersection(ltShot);
if (objS != null && objS != obj && objS.hitscalar>0)
{
clraux.x *= 0.9;
clraux.y *= 0.9;
clraux.z *= 0.9;
}```

Some Results

Here are some results of the current step of our ray tracing.

Fig. - Hi-Res NY on Mirror sphere

Fig. 3 - Basic sample of shadows

Fig. 4 - Basic sample of shadows

Fig. 5 - Parallel mirrors effect

Fig. 6 - After fixing sphere intersection for internal viewing

Fig. 7 - Testing a glass wrapper

The classes

Algebra

```using System;
using System.Collections.Generic;
using System.Text;

namespace ssAlgebra
{
public class tPoint
{
public tPoint(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}

public double x, y, z;
}

public class tAlgebra
{
public tAlgebra()
{
}
public static double GetCoord(double i1, double i2, double w1,
double w2, double p)
{
double eps = 1.0E-10;
if (Math.Abs(i2 - i1) < eps) return 0;
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));
}
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-10;

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;
}
}
}```

Geometry

```using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using ssAlgebra;
using System.Collections;

namespace ssGeometry
{

public class tMaterial
{
public double ambientR, ambientG, ambientB, ambientA;
public double diffuseR, diffuseG, diffuseB, diffuseA;
public double specularR, specularG, specularB, specularA;
public double emissionR, emissionG, emissionB, emissionA;
public double shininess;
public double reflectance;
public double alpha;

public tMaterial(double alpha, double reflectance,
double ambientR, double ambientG, double ambientB,
double specularR, double specularG, double specularB,
double shininess,
double diffuseR, double diffuseG, double diffuseB)
{
this.alpha = alpha;
this.reflectance = reflectance;
this.ambientR = ambientR;
this.ambientG = ambientG;
this.ambientB = ambientB;
this.specularR = specularR;
this.specularG = specularG;
this.specularB = specularB;
this.shininess = shininess;
this.diffuseR = diffuseR;
this.diffuseG = diffuseG;
this.diffuseB = diffuseB;
}

}
public abstract class tElementBase
{
public tElementBase()
{
tHitPoint = new tPoint(0, 0, 0);
}

public abstract tPoint getMapColor(double px, double py, double pz);
public tPoint get_point_color(System.Collections.ArrayList lights,
tPoint rayV)
{
tPoint color = new tPoint(0, 0, 0);

tPoint normal = new tPoint(0, 0, 0);

//foreach light
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);

if (imgBitmap != null)
{
tPoint colorPt = getMapColor(hitpoint.x, hitpoint.y,
hitpoint.z);

double sz = tAlgebra.modv(colorPt.x, colorPt.y, colorPt.z);
result1 = Math.Max(0, cost) * sz;
result2 = Math.Pow(Math.Max(0, cosf), material.shininess) *
sz;

rgbR = (material.ambientR * colorPt.x) +
(material.diffuseR * result1) +
(material.specularR * result2);
rgbG = (material.ambientG * colorPt.y) +
(material.diffuseG * result1) +
(material.specularG * result2);
rgbB = (material.ambientB * colorPt.z) +
(material.diffuseB * result1) +
(material.specularB * result2);

}

color.x = rgbR;
color.y = rgbG;
color.z = rgbB;

return color;
}

public tRay get_reflected_ray(tRay shot)
{
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 = shot.getRay().x;
iny = shot.getRay().y;
inz = shot.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.origin.x = hitpoint.x;
ray.origin.y = hitpoint.y;
ray.origin.z = hitpoint.z;
ray.target.x = (hitpoint.x + rx);
ray.target.y = (hitpoint.y + ry);
ray.target.z = (hitpoint.z + rz);

return ray;

}

public tMaterial material
{
get
{
return tmaterial;
}
set
{
tmaterial = value;
}
}
public tPoint hitpoint
{
get
{
return tHitPoint;
}
set
{
tHitPoint = value;
}
}
public double hitscalar
{
get
{
return tHitScalar;
}
set
{
tHitScalar = value;
}
}
protected Bitmap imgBitmap = null;
private tMaterial tmaterial;
private tPoint tHitPoint;
private double tHitScalar;

public bool interpolate = false;
private double vReflX = 0, vReflY = 0, vReflZ = 0;
public abstract void RotateXYZ(double rx, double ry, double rz);
public abstract void RotateZYX(double rx, double ry, double rz);
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 shot)
{
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 = shot.getRay().x;
iny = shot.getRay().y;
inz = shot.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.33;

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.origin.x = hitpoint.x;
ray.origin.y = hitpoint.y;
ray.origin.z = hitpoint.z;
ray.target.x = (hitpoint.x + rx);
ray.target.y = (hitpoint.y + ry);
ray.target.z = (hitpoint.z + rz);

return ray;
}

}
public class tSphere : tElementBase
{
public tSphere(double x, double y, double z, double r, string txmap)
{
cx = x;
cy = y;
cz = z;
if (txmap != null)
{
System.Drawing.Image image1 = new Bitmap(txmap);
imgBitmap = new Bitmap(image1);
}
}

public override tPoint getMapColor(double px, double py, double pz)
{
tPoint color = new tPoint(0, 0, 0);

//double rtx =0, rty = 0, rtz = 0;
//getNormal(px,py,pz,ref rtx, ref rty, ref rtz);
px = px - cx;
py = py - cy;
pz = pz - cz;

tAlgebra.RotX(1.5, ref py, ref pz);
tAlgebra.RotZ(-2.5, ref px, ref py);

double phi = Math.Acos(pz / radius);
double S = Math.Sqrt(px * px + py * py);
double theta;

if (px > 0)
theta = Math.Asin(py / S);//Atan(py/px);
else
theta = Math.PI - Math.Asin(py / S);// Math.Atan(py / px);

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

double x1 = tAlgebra.GetCoord(0.0, Math.PI * 2.0, 0.0,
imgBitmap.Width - 1, theta);
double y1 = tAlgebra.GetCoord(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)
{
Color clr = imgBitmap.GetPixel(i1, j1);
color.x = clr.R;
color.y = clr.G;
color.z = clr.B;
}

return color;
}

public override void RotateXYZ(double rx, double ry, double rz)
{
tAlgebra.RotX(rx, ref cy, ref cz);
tAlgebra.RotY(ry, ref cx, ref cz);
tAlgebra.RotZ(rz, ref cx, ref cy);
}

public override void RotateZYX(double rx, double ry, double rz)
{
tAlgebra.RotZ(rz, ref cx, ref cy);
tAlgebra.RotY(ry, ref cx, ref cz);
tAlgebra.RotX(rx, ref cy, ref cz);
}

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 +
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 && t1 > -1.0E-6) t = t1; else t = t2;

hitpoint.x = px + t * vx;
hitpoint.y = py + t * vy;
hitpoint.z = pz + t * vz;

hitscalar = t;
}

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;

}
public class tTriangle : tElementBase
{
private tObjectBase objbase;
public tTriangle(tObjectBase objbase, int va, int vb, int vc,
int ta, int tb, int tc, int na, int nb, int nc,
tMaterial mat, string txmap, bool interpolate)
{
this.objbase = objbase;

if (txmap != null)
{
System.Drawing.Image image1 = new Bitmap(txmap);
imgBitmap = new Bitmap(image1);
}
this.va = va;
this.vb = vb;
this.vc = vc;
this.ta = ta;
this.tb = tb;
this.tc = tc;
this.na = na;
this.nb = nb;
this.nc = nc;
this.interpolate = interpolate;

this.material = mat;
}

public override void RotateXYZ(double rx, double ry, double rz)
{
Init();
}
public override void RotateZYX(double rx, double ry, double rz)
{
Init();
}
public void Init()
{
tnormal = new tPoint(0, 0, 0);
GetNormal(ref tnormal.x, ref tnormal.y, ref tnormal.z);
}
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 eps = -1.0E-10; // must be negative
// for boundary merge on aliasing
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) > eps)
return true;
else
return false;
}
public bool PointInTriangle(double px, double py, double pz)
{
if (SameSide(px, py, pz, objbase.point(va).x,
objbase.point(va).y, objbase.point(va).z,
objbase.point(vb).x, objbase.point(vb).y,
objbase.point(vb).z, objbase.point(vc).x,
objbase.point(vc).y, objbase.point(vc).z) &&
SameSide(px, py, pz, objbase.point(vb).x,
objbase.point(vb).y, objbase.point(vb).z,
objbase.point(va).x, objbase.point(va).y,
objbase.point(va).z, objbase.point(vc).x,
objbase.point(vc).y, objbase.point(vc).z) &&
SameSide(px, py, pz, objbase.point(vc).x,
objbase.point(vc).y, objbase.point(vc).z,
objbase.point(va).x, objbase.point(va).y,
objbase.point(va).z, objbase.point(vb).x,
objbase.point(vb).y, objbase.point(vb).z))
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 u = 0;
double v1x = objbase.point(vc).x - p1x;
double v1y = objbase.point(vc).y - p1y;
double v1z = objbase.point(vc).z - p1z;
double v2x = p2x - p1x;
double v2y = p2y - p1y;
double v2z = p2z - p1z;
double dot1 = tAlgebra.Dot3(tnormal.x, tnormal.y, tnormal.z,
v1x, v1y, v1z);
double dot2 = tAlgebra.Dot3(tnormal.x, tnormal.y, tnormal.z,
v2x, v2y, v2z);
if (Math.Abs(dot2) < 1.0E-10)
return -1; // division by 0 means parallel
u = dot1 / dot2;
// point in triangle?
if (!PointInTriangle(p1x + u * (p2x - p1x),
p1y + u * (p2y - p1y), p1z + u * (p2z - p1z)))
return -1;

hitpoint.x = p1x + u * v2x;
hitpoint.y = p1y + u * v2y;
hitpoint.z = p1z + u * v2z;

hitscalar = u;

return u;
}
private void GetNormal(ref double nx, ref double ny, ref double nz)
{
double ux = objbase.point(vc).x - objbase.point(va).x,
uy = objbase.point(vc).y - objbase.point(va).y,
uz = objbase.point(vc).z - objbase.point(va).z;
double wx = objbase.point(vb).x - objbase.point(va).x,
wy = objbase.point(vb).y - objbase.point(va).y,
wz = objbase.point(vb).z - objbase.point(va).z;

// u x w
nx = wz * uy - wy * uz;
ny = wx * uz - wz * ux;
nz = wy * ux - wx * uy;
tAlgebra.Normalize(ref nx, ref ny, ref nz);

}
public override void getNormal(double x, double y, double z,
ref double nx, ref double ny, ref double nz)
{
if (!interpolate)
{
nx = -tnormal.x;
ny = -tnormal.y;
nz = -tnormal.z;
return;
}

tPoint U = new tPoint(objbase.point(va).x -
objbase.point(vb).x, objbase.point(va).y -
objbase.point(vb).y, objbase.point(va).z -
objbase.point(vb).z);
tPoint V = new tPoint(objbase.point(vc).x -
objbase.point(vb).x,
objbase.point(vc).y - objbase.point(vb).y,
objbase.point(vc).z - objbase.point(vb).z);

tPoint N = new tPoint(x - objbase.point(vb).x,y -
objbase.point(vb).y,z - objbase.point(vb).z);

double dU = tAlgebra.modv(U.x, U.y, U.z);
double dV = tAlgebra.modv(V.x, V.y, V.z);
double dN = tAlgebra.modv(N.x, N.y, N.z);

tAlgebra.Normalize(ref N.x, ref N.y, ref N.z);
tAlgebra.Normalize(ref U.x, ref U.y, ref U.z);

double cost = tAlgebra.Dot3(N.x, N.y, N.z, U.x, U.y, U.z);
if (cost < 0) cost = 0;
if (cost > 1) cost = 1;

double t = Math.Acos(cost);

double distY = 0, distX = 0;
distX = dN * Math.Cos(t);
distY = dN * Math.Sin(t);

double u = distX/ dU;
double v = distY/ dV;

tAlgebra.Normalize(ref objbase.normalVector(na).x,
ref objbase.normalVector(na).y,
ref objbase.normalVector(na).z);
tAlgebra.Normalize(ref objbase.normalVector(nb).x,
ref objbase.normalVector(nb).y,
ref objbase.normalVector(nb).z);
tAlgebra.Normalize(ref objbase.normalVector(nc).x,
ref objbase.normalVector(nc).y,
ref objbase.normalVector(nc).z);

nx = -( (1.0 - (u + v)) * objbase.normalVector(nb).x +
objbase.normalVector(na).x * u +
objbase.normalVector(nc).x * v);
ny = -( (1.0 - (u + v)) * objbase.normalVector(nb).y +
objbase.normalVector(na).y * u +
objbase.normalVector(nc).y * v);
nz = -( (1.0 - (u + v)) * objbase.normalVector(nb).z +
objbase.normalVector(na).z * u +
objbase.normalVector(nc).z * v);
}
public override tPoint getMapColor(double px, double py, double pz)
{
tPoint color = new tPoint(0, 0, 0);

double dx = imgBitmap.Width;
double dy = imgBitmap.Height;

double Ux = 0, Uy = 0, Uz = 0;
double Vx = 0, Vy = 0, Vz = 0;

double v2x = 0, v2y = 0, v2z = 0;
double distp = 0;

Ux = objbase.point(vc).x - objbase.point(vb).x;
Uy = objbase.point(vc).y - objbase.point(vb).y;
Uz = objbase.point(vc).z - objbase.point(vb).z;

v2x = px - objbase.point(vb).x;
v2y = py - objbase.point(vb).y;
v2z = pz - objbase.point(vb).z;
distp = tAlgebra.modv(objbase.point(vb).x - px,
objbase.point(vb).y - py, objbase.point(vb).z - pz);

Vx = objbase.point(va).x - objbase.point(vb).x;
Vy = objbase.point(va).y - objbase.point(vb).y;
Vz = objbase.point(va).z - objbase.point(vb).z;

double dU = tAlgebra.modv(Ux, Uy, Uz);
double dV = tAlgebra.modv(Vx, Vy, Vz);

tAlgebra.Normalize(ref Ux, ref Uy, ref Uz);
tAlgebra.Normalize(ref v2x, ref v2y, ref v2z);
double cost = tAlgebra.Dot3(Ux, Uy, Uz, v2x, v2y, v2z);
double t = Math.Acos(cost);

double distY = 0, distX = 0;
distY = dU - distp * Math.Cos(t);
distX = dV - distp * Math.Sin(t);

double x1 = 0;
double y1 = 0;
y1 = tAlgebra.GetCoord(0, dU, objbase.texturePoint(tc).y * dy,
objbase.texturePoint(tb).y * dy, distY);
x1 = tAlgebra.GetCoord(0, dV, objbase.texturePoint(ta).x * dx,
objbase.texturePoint(tb).x * dx, distX);

int i1 = (int)x1, j1 = (int)y1;
if (i1 >= 0 && j1 >= 0 && i1 < imgBitmap.Width && j1 <
imgBitmap.Height)
{
Color clr = imgBitmap.GetPixel(i1, j1);
color.x = clr.R;
color.y = clr.G;
color.z = clr.B;
}

return color;
}

// Points
public int va, vb, vc;

// Texture
public int ta, tb, tc;  // only x,y counts (discard z)

// Normals
public int na, nb, nc;

public tPoint tnormal;
}
public abstract class tObjectBase
{
public tObjectBase()
{
}

public tPoint texturePoint(int i)
{
return (tPoint)textureArray[i];
}

public tPoint point(int i)
{
return (tPoint)vertexArray[i];
}

public tPoint normalVector(int i)
{
return (tPoint)normalArray[i];
}

public void normalAdd(int i, tPoint v)
{
((tPoint)normalArray[i]).x += v.x;
((tPoint)normalArray[i]).y += v.y;
((tPoint)normalArray[i]).z += v.z;
}

public tTriangle AddTriangle(int a, int b, int c,
int ta, int tb, int tc, int na, int nb, int nc,
tMaterial mat, string txmap, bool interpolate)
{
tTriangle tri = new tTriangle(this, a, b, c, ta, tb, tc,
na, nb, nc, mat, txmap, interpolate);
tri.material = mat;
tri.Init();
return tri;
}
{
}
public void AddSphere(double cx, double cy, double cz,
double radius, tMaterial mat, string txmap)
{
tSphere sph = new tSphere(cx, cy, cz, radius, txmap);
sph.material = mat;
}

public void RotateAllVertices(double rx, double ry, double rz)
{
for (int i = 0; i < vertexArray.Count; i++)
{
tAlgebra.RotX(rx, ref ((tPoint)vertexArray[i]).y,
ref ((tPoint)vertexArray[i]).z);
tAlgebra.RotY(ry, ref ((tPoint)vertexArray[i]).x,
ref ((tPoint)vertexArray[i]).z);
tAlgebra.RotZ(rz, ref ((tPoint)vertexArray[i]).x,
ref ((tPoint)vertexArray[i]).y);
}
}

public ArrayList elementArray = new ArrayList();
public ArrayList vertexArray = new ArrayList();
public ArrayList normalArray = new ArrayList();
public ArrayList textureArray = new ArrayList();
}
public class tObject : tObjectBase
{
// object files are usually formed by a set of triangles
public void LoadOBJFile(string filename, string txfilename,
tMaterial mat, double scale,
double mx, double my, double mz, bool interpolate)
{
System.IO.FileStream file = new System.IO.FileStream(filename,
file.Close();

string[] lines = filebody.Split('\n');

tPoint ta = new tPoint(1, 0, 0);
tPoint tb = new tPoint(0, 0, 0);
tPoint tc = new tPoint(1, 1, 0);

foreach (string line in lines)
{
if (line.Length < 1) continue;
string auxline = line.Replace("  ", " ");
auxline = auxline.Replace("\r", "");
auxline = auxline.Replace("\n", "");
auxline = auxline.TrimEnd();
if (auxline.Length == 0) continue;
if (auxline.IndexOf("mtllib") >= 0)
{
auxline = auxline.Replace("mtllib", "");
}
else
//we do not read the vertex normals,
//they are calculated below
if ((auxline[0] == 'v') && (auxline[1] == ' '))
{
auxline = auxline.Replace("v ", "");
string[] points = auxline.Split(' ');
tPoint pt = new tPoint(0, 0, 0);
pt.x = double.Parse(points[0]) * scale + mx;
pt.y = double.Parse(points[1]) * scale + my;
pt.z = double.Parse(points[2]) * scale + mz;
tPoint nrm = new tPoint(0, 0, 0);
}
else
if (auxline[0] == 'f')
{
auxline = auxline.Replace("f ", "");
string[] auxsub = auxline.Split(' ');

if (auxsub.Length == 3)
{
string[] vx = auxsub[0].Split('/');
string[] vy = auxsub[1].Split('/');
string[] vz = auxsub[2].Split('/');

int va = int.Parse(vx[0]) - 1;
int vb = int.Parse(vy[0]) - 1;
int vc = int.Parse(vz[0]) - 1;

tPoint A = (tPoint)vertexArray[va];
tPoint B = (tPoint)vertexArray[vb];
tPoint C = (tPoint)vertexArray[vc];

int na = va, nb = vb, nc = vc;
if (vx.Length == 3)
{
na = int.Parse(vx[2]) - 1;
nb = int.Parse(vy[2]) - 1;
nc = int.Parse(vz[2]) - 1;
tPoint nA = (tPoint)normalArray[na];
tPoint nB = (tPoint)normalArray[nb];
tPoint nC = (tPoint)normalArray[nc];
AddTriangle(va, vb, vc, 0, 1, 2,
na, nb, nc, mat, txfilename, interpolate);
}
else
{
tTriangle tri = new tTriangle(this,
va, vb, vc, 0, 1, 2,
na, nb, nc, mat,
txfilename, interpolate);
tri.Init();
// update normals
// vertex normals are initially 0,0,0
// each reached vertex makes
// normal to sum its triangle normal
}
}
}
}
}

}

public class tRay
{
public tPoint origin;
public tPoint target;

public tRay()
{
origin = new tPoint(0, 0, 0);
target = new tPoint(0, 0, 0);
}

public tPoint getRay()
{
return new tPoint((target.x - origin.x), (target.y - origin.y),
(target.z - origin.z));
}
}

public class tRayTracer
{
// rotation
public int levels = 3;
int level = 0;
System.Collections.ArrayList objectList;
System.Collections.ArrayList lightsArrayList;

public tRayTracer(int levels)
{
this.levels = levels;
objectList = new System.Collections.ArrayList();
lightsArrayList = new System.Collections.ArrayList();
}

{
}

private tElementBase get_first_intersection(tRay shot)
{
double eps = 1.0E-10;
double t = 1.0E10;

tElementBase objhit = null;

for (int p = 0; p < (int)objectList.Count; p++)
{
tObjectBase objBase = (tObjectBase)objectList[p];

for (int k = 0; k < (int)objBase.elementArray.Count; k++)
{
tElementBase objn =
(tElementBase)objBase.elementArray[k];

double taux = objn.GetIntersect(shot.origin.x,
shot.origin.y,
shot.origin.z,
shot.target.x,
shot.target.y,
shot.target.z);

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

if (taux > 0 && taux < t)
{
t = taux;
objhit = objn;
}
}
}
return objhit;
}
public tPoint trace_ray(tRay shot)
{
level++;
tPoint point_color = new tPoint(0, 0, 0),
reflect_color = new tPoint(0, 0, 0),
refract_color = new tPoint(0, 0, 0),
clraux = new tPoint(0, 0, 0);

if (level > levels)
{
level--;
point_color.x = 0;
point_color.y = 0;
point_color.z = 0;
return point_color;
}

tElementBase obj = get_first_intersection(shot);

if (obj != null)
{
Type type = obj.GetType();
if (type.Name.CompareTo("tSphere") == 0)
{
int sphere = 0;
sphere++;
}

point_color = obj.get_point_color(lightsArrayList,
shot.getRay());

tRay rfl = null;
tRay rfr = null;

if (obj.material.reflectance > 0)
{
rfl = obj.get_reflected_ray(shot);
reflect_color = trace_ray(rfl);
}
if (obj.material.alpha > 0)
{
rfr = obj.get_refracted_ray(shot);
refract_color = trace_ray(rfr);
}

double refl = obj.material.reflectance;
double refr = obj.material.alpha;
double ownp = 1.0 - refl;

clraux.x = (point_color.x * ownp + reflect_color.x *
refl + refract_color.x * refr);
clraux.y = (point_color.y * ownp + reflect_color.y *
refl + refract_color.y * refr);
clraux.z = (point_color.z * ownp + reflect_color.z *
refl + refract_color.z * refr);

level--;

if (obj != null && level == 0)
{
tRay ltShot = new tRay();
ltShot.origin = (tPoint)lightsArrayList[0];
ltShot.target = obj.hitpoint;
tElementBase objS = get_first_intersection(ltShot);

if (objS != null && objS != obj && objS.hitscalar>0)
{
clraux.x *= 0.9;
clraux.y *= 0.9;
clraux.z *= 0.9;
}
}

return clraux; // combine with other
}
level--;

return point_color;
}

{
}

public void RotateAllObjects(double ax, double ay, double az)
{

for (int p = 0; p < (int)objectList.Count; p++)
{
tObjectBase objBase = (tObjectBase)objectList[p];

objBase.RotateAllVertices(ax, ay, az);

for (int k = 0; k < (int)objBase.elementArray.Count; k++)
{
tElementBase objn =
(tElementBase)objBase.elementArray[k];
objn.RotateXYZ(ax, ay, az);
}
}
}

}

}```

Using the code

Helper funtion (normalizeColor), used to normalize the colors within the valid 0-255 range:

```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);
}
```

One sample:

```int scrsize = 200; // image size in pixels (for width and height)
Bitmap newBitmap = new Bitmap(scrsize, scrsize,
PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(newBitmap);
Rectangle rect = new Rectangle(0, 0, scrsize, scrsize);
double fMax = 4.9; // virtual model size
int rec = 3;  // recursivity
tRayTracer rayTracer = new tRayTracer(rec);
tMaterial mat1 = new tMaterial(0,0,
0.329412,0.223529,0.027451,
0.992157,0.941176,0.807843,27.8974,
0.780392,0.568627,0.113725);

tObject teapot = new tObject();
0, -1, -2, true);
tMaterial mat2 = new tMaterial(0, 0,
0.029412, 0.023529, 0.327451,
0.792157, 0.741176, 0.807843, 27.8974,
0.580392, 0.568627, 0.713725);
tObject sphere1 = new tObject();
sphere1.AddSphere(3, 0, -3, 1, mat2, null);
tMaterial mat3 = new tMaterial(0, 0.1,
0.5, 0.5, 0.5,
0.792157, 0.741176, 0.807843, 7.8974,
0.580392, 0.568627, 0.583725);
tObject box = new tObject();
mat3, 5, 0, 0, 0, false);
tPoint light1 = new tPoint(0,0,4.5);
rayTracer.RotateAllObjects(-0.1, -0.1, 0);
tPoint color = new tPoint(0, 0, 0);
double deltaP = Math.Abs(tAlgebra.GetCoord(rect.Left,
rect.Right,
-fMax, fMax, rect.Left + 1) + fMax) / 2.0;
tRay ray = new tRay();
ray.target.z = 0.0;
ray.origin.x = 0;
ray.origin.y = 0;
ray.origin.z = 4.9;

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.target.x = x; ray.target.y = y;

color.x = 0; color.y = 0; color.z = 0;
ray.target.x = x - deltaP; ray.target.y =
y - deltaP; ray.target.z = 0.0;
tPoint colorA = rayTracer.trace_ray(ray);
normalizeColor(ref colorA);

ray.target.x = x - deltaP; ray.target.y =
y + deltaP; ray.target.z = 0.0;
tPoint colorB = rayTracer.trace_ray(ray);
normalizeColor(ref colorB);

ray.target.x = x + deltaP; ray.target.y =
y - deltaP; ray.target.z = 0.0;
tPoint colorC = rayTracer.trace_ray(ray);
normalizeColor(ref colorC);

ray.target.x = x + deltaP; ray.target.y =
y + deltaP; ray.target.z = 0.0;
tPoint colorD = rayTracer.trace_ray(ray);
normalizeColor(ref colorD);

ray.target.x = x; ray.target.y = y;
ray.target.z = 0.0;
tPoint colorE = rayTracer.trace_ray(ray);
normalizeColor(ref colorE);

ray.target.x = x; ray.target.y = y - deltaP;
ray.target.z = 0.0;
tPoint colorF = rayTracer.trace_ray(ray);
normalizeColor(ref colorF);

ray.target.x = x; ray.target.y = y + deltaP;
ray.target.z = 0.0;
tPoint colorG = rayTracer.trace_ray(ray);
normalizeColor(ref colorG);

ray.target.x = x - deltaP; ray.target.y = y;
ray.target.z = 0.0;
tPoint colorH = rayTracer.trace_ray(ray);
normalizeColor(ref colorH);

ray.target.x = x + deltaP; ray.target.y = y;
ray.target.z = 0.0;
tPoint colorI = rayTracer.trace_ray(ray);
normalizeColor(ref colorI);

color.x = (colorA.x + colorB.x + colorC.x +
colorD.x + colorE.x + colorF.x +
colorG.x + colorH.x + colorI.x) / 9.0;
color.y = (colorA.y + colorB.y + colorC.y +
colorD.y + colorE.y + colorF.y +
colorG.y + colorH.y + colorI.y) / 9.0;
color.z = (colorA.z + colorB.z + colorC.z +
colorD.z + colorE.z + colorF.z +
colorG.z + colorH.z + colorI.z) / 9.0;

normalizeColor(ref color);
Color colorpx = Color.FromArgb((int)color.x,
(int)color.y, (int)color.z);
newBitmap.SetPixel(i, j, colorpx);
}
}
newBitmap.Save("oneshot.bmp");
```

Share

 CEO TIHunter Brazil

 First PrevNext
 No Source code. The download files are not latest. They are from your article 4. Member 1252384623-Apr-19 3:04 Member 12523846 23-Apr-19 3:04
 My vote of 4 fredatcodeproject9-Apr-13 2:57 fredatcodeproject 9-Apr-13 2:57
 My vote of 5 Hassan Oumar Mahamat15-Mar-13 14:17 Hassan Oumar Mahamat 15-Mar-13 14:17
 Latest source code and library andalmeida6-Jan-12 6:16 andalmeida 6-Jan-12 6:16
 Really nice article! obazavil15-Dec-08 3:18 obazavil 15-Dec-08 3:18
 Re: Really nice article! andalmeida15-Dec-08 3:29 andalmeida 15-Dec-08 3:29
 Re: Really nice article! andalmeida15-Dec-08 3:38 andalmeida 15-Dec-08 3:38
 Re: Really nice article! obazavil15-Dec-08 17:16 obazavil 15-Dec-08 17:16
 project file? elwolv18-Sep-07 19:12 elwolv 18-Sep-07 19:12
 Re: project file? andalmeida19-Sep-07 3:06 andalmeida 19-Sep-07 3:06
 [Message Deleted] R_L_H13-Sep-07 10:46 R_L_H 13-Sep-07 10:46
 Re: Unrelated to shadows... andalmeida13-Sep-07 10:53 andalmeida 13-Sep-07 10:53
 Re: Unrelated to shadows... andalmeida16-Sep-07 6:37 andalmeida 16-Sep-07 6:37
 Great Articles but Dileep.M11-Sep-07 22:14 Dileep.M 11-Sep-07 22:14
 Re: Great Articles but andalmeida12-Sep-07 3:16 andalmeida 12-Sep-07 3:16
 Project files added (compiling) andalmeida11-Sep-07 9:09 andalmeida 11-Sep-07 9:09
 Source code andalmeida6-Sep-07 5:58 andalmeida 6-Sep-07 5:58
 Khazbak asks... Genevieve Sovereign6-Sep-07 5:45 Genevieve Sovereign 6-Sep-07 5:45
 Re: Khazbak asks... andalmeida6-Sep-07 5:50 andalmeida 6-Sep-07 5:50
 Improvements andalmeida6-Sep-07 3:36 andalmeida 6-Sep-07 3:36
 Re: Improvements Pete O'Hanlon6-Sep-07 3:55 Pete O'Hanlon 6-Sep-07 3:55
 Re: Improvements Geeky Monkey Russ11-Sep-07 3:56 Geeky Monkey Russ 11-Sep-07 3:56
 Re: Improvements andalmeida11-Sep-07 7:59 andalmeida 11-Sep-07 7:59
 Ah, i prefer to give you some work all classes and methods are available on the txt file for download, please let me know if it is missing some Anderson J. Almeida Systems Analyst SimSysBr www.simsysbr.com
 Re: Improvements Geeky Monkey Russ11-Sep-07 23:32 Geeky Monkey Russ 11-Sep-07 23:32
 Last Visit: 3-Dec-20 17:40     Last Update: 3-Dec-20 17:40 Refresh 12 Next ᐅ