All pastes #2053869 Raw Edit

Triangle class

public text v1 · immutable
#2053869 ·published 2011-05-04 16:10 UTC
rendered paste body
using System;
using Sharp3D.Math.Core;

namespace PathTracer
{
	public class Triangle:Intersectable
	{
		Vector3F pointA, pointB, pointC;
		Vector3F normA, normB, normC;
		float xmin, ymin, zmin, xmax, ymax, zmax;
		Plane surfacePlane;
		Material surfaceMaterial;
		bool isLightSource;

		public Triangle (Vector3F pointA, Vector3F pointB, Vector3F pointC)
		{
			this.pointA = pointA;
			this.pointB = pointB;
			this.pointC = pointC;
			Vector3F normal = getNormal ();
			surfacePlane = new Plane (normal, pointA);
			computeBoundaries ();
		}

		public Triangle (Vector3F pointA, Vector3F pointB, Vector3F pointC, Material mat)
		{
			this.pointA = pointA;
			this.pointB = pointB;
			this.pointC = pointC;
			surfaceMaterial = mat;
			Vector3F normal = getNormal ();
			surfacePlane = new Plane (normal, pointA);
		}

		public Triangle (Vector3F a, Vector3F b, Vector3F c, Vector3F normA,
			Vector3F normB, Vector3F normC)
		{
			this.pointA = a;
			this.pointB = b;
			this.pointC = c;
			this.normA = normA;
			this.normB = normB;
			this.normC = normC;
			normA.Normalize ();
			normB.Normalize ();
			normC.Normalize ();
			Vector3F normal = getNormal ();
			surfacePlane = new Plane (normal, a);
			computeBoundaries ();
		}

		public Triangle (Vector3F a, Vector3F b, Vector3F c, Vector3F normA,
			Vector3F normB, Vector3F normC, Material mat)
		{
			this.pointA = a;
			this.pointB = b;
			this.pointC = c;
			this.normA = normA;
			this.normB = normB;
			this.normC = normC;
			normA.Normalize ();
			normB.Normalize ();
			normC.Normalize ();
			Vector3F normal = getNormal ();
			surfacePlane = new Plane (normal, a);
			computeBoundaries ();
			surfaceMaterial = mat;
		}

		private Vector3F getNormal ()
		{
			Vector3F ab = Vector3F.Subtract (pointB, pointA);
			ab.Normalize ();
			Vector3F ac = Vector3F.Subtract (pointC, pointA);
			ac.Normalize ();
			Vector3F normal = Vector3F.CrossProduct (ab, ac);
			return normal;
		}
		
		public Vector3F getNormal(float beta, float gamma) {
		// if the vertex normals have not been set, return the triangle plane's
		// normal
		Vector3F ret;
		if (normA == null) {
			return surfacePlane.getNormal();
		} else { // we return the linear interpolation based on the beta and
			// gamma factors of the normals.
			Vector3F Bfactor = new Vector3F(normB);
			Bfactor = Vector3F.Multiply(Bfactor,beta);
			Vector3F Cfactor = new Vector3F(normC);
			Cfactor = Vector3F.Multiply(Cfactor,gamma);
			Vector3F Afactor = new Vector3F(normA);
			Afactor = Vector3F.Multiply(Afactor,1 - beta - gamma);
			ret = new Vector3F(Afactor);
			ret = Vector3F.Add(ret,Bfactor);
			ret = Vector3F.Add(ret,Cfactor);
			ret.Normalize();
		}
		return ret;
	}

		public void computeBoundaries ()
		{
			xmin = pointA.X;
			ymin = pointA.Y;
			zmin = pointA.Z;
			xmax = pointA.X;
			ymax = pointA.Y;
			zmax = pointA.Z;
			if (pointB.X < xmin) {
				xmin = pointB.X;
			} else if (pointC.X < xmin) {
				xmin = pointC.X;
			}
			if (pointB.Y < ymin) {
				ymin = pointB.Y;
			} else if (pointC.Y < ymin) {
				ymin = pointC.Y;
			}
			if (pointB.Z < zmin) {
				zmin = pointB.Z;
			} else if (pointC.Z < zmin) {
				zmin = pointC.Z;
			}
			if (pointB.X > xmax) {
				xmax = pointB.X;
			} else if (pointC.X > xmax) {
				xmax = pointC.X;
			}
			if (pointB.Y > ymax) {
				ymax = pointB.Y;
			} else if (pointC.Y > ymax) {
				ymax = pointC.Y;
			}
			if (pointB.Z > zmax) {
				zmax = pointB.Z;
			} else if (pointC.Z > zmax) {
				zmax = pointC.Z;
			}
		}

		#region Intersectable implementation
		
		Hitrecord Intersectable.Intersect (Ray r)
		{
			Matrix3F A, Ax;
			float beta, gamma, t;
			Hitrecord hit;
			Vector3F hitPoint;
			Vector3F sol = new Vector3F (pointA.X - r.getOrigin ().X, pointA.Y
				- r.getOrigin ().Y, pointA.Z - r.getOrigin ().Z);

			A = new Matrix3F ();
			A.M11 = pointA.X - pointB.X; A.M12 = pointA.X - pointC.X; A.M13 = r.getDir().X;
			A.M21 = pointA.Y - pointB.Y; A.M22 = pointA.Y - pointC.Y; A.M23 = r.getDir().Z;
			A.M31 = pointA.Z - pointB.Z; A.M32 = pointA.Z - pointC.Z; A.M33 = r.getDir().Z;
			
			if (A.Determinant() < -Material.EPSILON
				|| A.Determinant () > Material.EPSILON) { // solving using
				// Cramer's rule
				float Adet = A.Determinant ();
				Ax = new Matrix3F (A);
				Ax.M11  = sol.X; Ax.M21 = sol.Y; Ax.M31 = sol.Z;
				beta = Ax.Determinant () / Adet;
				Ax = new Matrix3F (A);
				Ax.M21 = sol.X; Ax.M22=sol.Y; Ax.M23 = sol.Z;
				gamma = Ax.Determinant () / Adet;
				Ax = new Matrix3F (A);
				Ax.M31 = sol.X; Ax.M32 = sol.Y; Ax.M33 = sol.Z;
				t = Ax.Determinant () / Adet; // if beta + gamma are
				// between 0 and 1, we're in
				// the triangle.
				if (beta + gamma < 1 + Material.EPSILON && beta > -Material.EPSILON
					&& gamma > -Material.EPSILON) {
					hitPoint = new Vector3F (r.getDir ());
					hitPoint = Vector3F.Multiply (hitPoint, t);
					hitPoint = Vector3F.Add (hitPoint, r.getOrigin ());
					hit = new Hitrecord (hitPoint, t, getNormal (beta, gamma),
						((Intersectable)this).getMaterial (), this);
					return hit;
				}
			}
			return null;
		}

		public Vector3F getA ()
		{
			return pointA;
		}

		public Vector3F getB ()
		{
			return pointB;
		}

		public Vector3F getC ()
		{
			return pointC;
		}

		public Vector3F getNormA ()
		{
			return normA;
		}

		public Vector3F getNormB ()
		{
			return normB;
		}

		public Vector3F getNormC ()
		{
			return normC;
		}

		public float getXmax ()
		{
			return xmax;
		}

		public float getXmin ()
		{
			return xmin;
		}

		public float getYmax ()
		{
			return ymax;
		}

		public float getYmin ()
		{
			return ymin;
		}

		public float getZmax ()
		{
			return zmax;
		}

		public float getZmin ()
		{
			return zmin;
		}

		public bool isAggregate ()
		{
			return false;
		}

		Material Intersectable.getMaterial ()
		{
			return surfaceMaterial;
		}

		bool Intersectable.isLightSource ()
		{
			return isLightSource;
		}

		#endregion
	}
}