15,120,567 members
Articles / Web Development / ASP.NET
Article
Posted 7 Aug 2007

70.8K views
69 bookmarked

# Simple Ray Tracing in C# Part III (Reflection)

Rate me:
Ray tracing in C# part III - implementing reflection

 recursivity level = 10 recursivity level = 2

Center Sphere alpha = 0.2 ( simulating glass refraction )

Other Spheres have alpha = 1.0 (simulating only reflection)

## Introduction

Previously we have seen ray tracing and mapping in spheres and triangles with simple illumination model, now we will extend this with reflections and refractions.

If you need previous background please check it out on the last articles below:

## Background

A background in Linear Algebra is required, related to R3 points and vectors, object equations, intersections, vector reflections, rotations around axis, dot and cross products, angle between vectors and so. For this I created a helper class called tAlgebra as below:

### Algebra class

C#
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

C#
public class tMaterial
{
public double ambientR, ambientG, ambientB, ambientA;
public double specularR, specularG, specularB, specularA;
public double shininess;
public double alpha;
}

### R3 Point Class

C#
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 tObject, and the derived tSphere and tTriangle:

#### Object Class

C#
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

C#
public class tSphere : tObject
{
public tSphere(double x, double y, double z, double r)
{
cx = x;
cy = y;
cz = z;
}
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

C#
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

C#
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();
}
{
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);
}
{
}
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;
}
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;
}
}

## Using the Code

Follows a sample of code usage, I made this to display the resulting image in a web page:

C#
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;

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.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; ray.y1 = y; ray.z1 = 0.0;
color.x = 0; color.y = 0; color.z = 0;
color = ray.trace_ray(ray);
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);

Color colorpx = Color.FromArgb((int)color.x,
(int)color.y, (int)color.z);
Brush brs = new SolidBrush(colorpx);
g.FillRectangle(brs, i, j, 1, 1);
brs.Dispose();
}
}

MemoryStream tempStream = new MemoryStream();
newBitmap.Save(tempStream, ImageFormat.Png);
Response.ClearContent();
Response.ContentType = "image/png";
Response.BinaryWrite(tempStream.ToArray());
Response.Flush();

## Points of Interest

When working with floating points we have computational issues for values near to zero, so in most of formulas we need to work with a small range around 0. Try to remove this from the code and see the results in the image.

For example if we have:

• if(x>0.0) ...

it is required we do this:

• double epsilon = 1.0E-K; // define a nice value for K

if(Math.Abs(x)>epsilon) ...

## Share

 CEO TIHunter Brazil

 First Prev Next
 Good article and series jfriedman21-Jul-16 4:07 jfriedman 21-Jul-16 4:07
 Good Job! Keep up the good work! (Would have liked to see more on lighting methodology and references such as Phong)
 My vote of 5 Manoj Kumar Choubey26-Feb-12 22:43 Manoj Kumar Choubey 26-Feb-12 22:43
 Updated source code and library andalmeida6-Jan-12 6:10 andalmeida 6-Jan-12 6:10
 Small Oddity - Center Sphere Andrew Rissing10-Aug-07 11:28 Andrew Rissing 10-Aug-07 11:28
 Re: Small Oddity - Center Sphere andalmeida10-Aug-07 11:30 andalmeida 10-Aug-07 11:30
 What about anti-aliasing? Lukasz Swiatkowski8-Aug-07 12:52 Lukasz Swiatkowski 8-Aug-07 12:52
 Re: What about anti-aliasing? andalmeida8-Aug-07 13:48 andalmeida 8-Aug-07 13:48
 Re: What about anti-aliasing? chinaQI11-Aug-07 3:12 chinaQI 11-Aug-07 3:12
 Re: What about anti-aliasing? andalmeida12-Aug-07 15:44 andalmeida 12-Aug-07 15:44
 Re: What about anti-aliasing? andalmeida13-Aug-07 2:52 andalmeida 13-Aug-07 2:52
 Re: What about anti-aliasing? Lukasz Swiatkowski16-Aug-07 10:57 Lukasz Swiatkowski 16-Aug-07 10:57
 Last Visit: 31-Dec-99 19:00     Last Update: 3-Dec-21 18:59 Refresh 1