/// <summary> /// Creates a rotation matrix of the given parameters. /// </summary> /// <param name="unitVector">Rotation axis.</param> /// <param name="angle">Rotation angle in radians.</param> /// <returns>The rotation matrix.</returns> public static Matrix CreateRotationMatrix(Vect3D unitVector, double angle) { if (unitVector.GetLength() != 1) { return(null); //UNCHECKED this may cause problems } if (angle == 0) { return(CreateMultiplicativeIdentityMatrix(3)); } Matrix m = new Matrix(3, 3); double cos = Math.Cos(angle); double sin = Math.Sin(angle); double XYcos = unitVector.X * unitVector.Y * (1 - cos); double XZcos = unitVector.X * unitVector.Z * (1 - cos); double YZcos = unitVector.Y * unitVector.Z * (1 - cos); double Xsin = unitVector.X * sin; double Ysin = unitVector.Y * sin; double Zsin = unitVector.Z * sin; //https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle m.Mtrx[0, 0] = cos + unitVector.X * unitVector.X * (1 - cos); m.Mtrx[0, 1] = XYcos - Zsin; m.Mtrx[0, 2] = XZcos + Ysin; m.Mtrx[1, 0] = XYcos + Zsin; m.Mtrx[1, 1] = cos + unitVector.Y * unitVector.Y * (1 - cos); m.Mtrx[1, 2] = YZcos - Xsin; m.Mtrx[2, 0] = XZcos - Ysin; m.Mtrx[2, 1] = YZcos + Xsin; m.Mtrx[2, 2] = cos + unitVector.Z * unitVector.Z * (1 - cos); return(m); }
/// <summary> /// Calculates which triangles are within the camera's field of view. /// </summary> public void DetermineTrianglesInRange() { //TODO can be heavly optimized by reading directly from the objects verticies. CREATE BACKUP WHEN EDITING. Vect3D toPointVector; Stack <int> trianglesIndex = new Stack <int>(); foreach (Triangle3D triangle in triangles) { foreach (Point3D point in triangle.coordinates) { toPointVector = new Vect3D(CameraPosition, point); if (Relation3D.AngleBetween(toPointVector, cameraLeftPlaneNormalVector) > Math.PI / 2) { continue; } if (Relation3D.AngleBetween(toPointVector, cameraRightPlaneNormalVector) > Math.PI / 2) { continue; } if (Relation3D.AngleBetween(toPointVector, cameraTopPlaneNormalVector) > Math.PI / 2) { continue; } if (Relation3D.AngleBetween(toPointVector, cameraBottomPlaneNormalVector) > Math.PI / 2) { continue; } trianglesIndex.Push(Array.IndexOf(triangles, triangle)); break; } } trianglesOnScreenIndex = trianglesIndex.ToArray(); }
/// <summary> /// Calculate the normal vectors used for angle calculation. /// </summary> private void CreatePlaneNormalVectors() { cameraLeftPlaneNormalVector = cameraDirectionUnitVector.RotateVector(cameraVerticalUnitVector, CameraFieldOfView / 2 - Math.PI / 2, true); cameraRightPlaneNormalVector = cameraDirectionUnitVector.RotateVector(cameraVerticalUnitVector, -(CameraFieldOfView / 2 - Math.PI / 2), true); cameraTopPlaneNormalVector = cameraDirectionUnitVector.RotateVector(cameraHorizontalUnitVector, (CameraFieldOfView / AspectRatio) / 2 - Math.PI / 2, true); cameraBottomPlaneNormalVector = cameraDirectionUnitVector.RotateVector(cameraHorizontalUnitVector, -((CameraFieldOfView / AspectRatio) / 2 - Math.PI / 2), true); }
/// <summary> /// Moves the camera along an axis. /// </summary> /// <param name="direction">Direction of movement.</param> /// <param name="distance">Distance of movement.</param> public void MoveOnAxis(char direction, double distance = 0.1) { Vect3D CurrentPosition = new Vect3D(CameraPosition); switch (direction) { case 'r': CameraPosition = (CurrentPosition + cameraHorizontalUnitVector * distance).ToPoint(); break; case 'l': CameraPosition = (CurrentPosition - cameraHorizontalUnitVector * distance).ToPoint(); break; case 'u': CameraPosition = (CurrentPosition + cameraVerticalUnitVector * distance).ToPoint(); break; case 'd': CameraPosition = (CurrentPosition - cameraVerticalUnitVector * distance).ToPoint(); break; case 'f': CameraPosition = (CurrentPosition + cameraDirectionUnitVector * distance).ToPoint(); break; case 'b': CameraPosition = (CurrentPosition - cameraDirectionUnitVector * distance).ToPoint(); break; } DetermineTrianglesInRange(); ProjectToScreen(); }
/// <summary> /// Rotates the camera around an axis. /// </summary> /// <param name="axis">Rotationaxis</param> /// <param name="angle">Angle of rotation in degrees.</param> public void RotateAroundAxis(char axis, double angle = 1.5) { angle /= Relation3D.radianToDegreeConst; Vect3D rotationAxis = new Vect3D(); switch (axis) { case 'x': rotationAxis = cameraHorizontalUnitVector; break; case 'y': rotationAxis = cameraDirectionUnitVector; break; case 'z': rotationAxis = cameraVerticalUnitVector; break; } Matrix rotationMatrix = Matrix.CreateRotationMatrix(rotationAxis, angle); cameraDirectionUnitVector = rotationMatrix * cameraDirectionUnitVector; cameraVerticalUnitVector = rotationMatrix * cameraVerticalUnitVector; cameraHorizontalUnitVector = rotationMatrix * cameraHorizontalUnitVector; cameraLeftPlaneNormalVector = rotationMatrix * cameraLeftPlaneNormalVector; cameraRightPlaneNormalVector = rotationMatrix * cameraRightPlaneNormalVector; cameraTopPlaneNormalVector = rotationMatrix * cameraTopPlaneNormalVector; cameraBottomPlaneNormalVector = rotationMatrix * cameraBottomPlaneNormalVector; DetermineTrianglesInRange(); ProjectToScreen(); }
/// <summary> /// Creates a 3x1 matrix from a vector. /// </summary> /// <param name="v">A vector.</param> public Matrix(Vect3D v) { Mtrx = new double[3, 1]; Rows = 3; Columns = 1; Mtrx[0, 0] = v.X; Mtrx[1, 0] = v.Y; Mtrx[2, 0] = v.Z; }
/// <summary> /// Resets the camera's position and direction. /// </summary> public void Reset() { CameraPosition = new Point3D(1, -10, 1); cameraDirectionUnitVector = new Vect3D(0, 1, 0); cameraVerticalUnitVector = new Vect3D(0, 0, 1); cameraHorizontalUnitVector = new Vect3D(1, 0, 0); CreatePlaneNormalVectors(); DetermineTrianglesInRange(); ProjectToScreen(); }
/// <summary> /// Turns a 3x1 matrix into a vector. /// </summary> /// <returns>Vector represented by the matrix.</returns> public Vect3D ToVector() { Vect3D v = new Vect3D(); if (Rows == 3 && Columns == 1) { v.X = Mtrx[0, 0]; v.Y = Mtrx[1, 0]; v.Z = Mtrx[2, 0]; } return(v); }
public override RGBColor Shade(ShadeRec sr) { RGBColor L = base.Shade(sr); //Factor in all direct illumination Vect3D reflectedDirection = -sr.Ray.Direction; //Vector pointing towards camera Vect3D perfectReflection = new Vect3D(1.0f,1.0f,1.0f); //Vector equivalent to perfect reflection RGBColor fr = reflectiveBRDF.SampleF(sr, ref perfectReflection, ref reflectedDirection); //Set vectors for reflection to correct values Point3D hitPoint = sr.HitPoint + (perfectReflection * GlobalVars.SHAD_K_EPSILON); //Avoid salt+pepper noise Ray reflectedRay = new Ray(hitPoint, perfectReflection); //Cast ray from point of incidence L += fr * sr.WorldPointer.CurrentTracer.TraceRay(reflectedRay, sr.RecursionDepth + 1) * (sr.Normal * perfectReflection); //Recurse! return L; }
/// <summary> /// Calculates the triangles position on the screen and adds them to the screens collection of triangles. /// </summary> public void ProjectToScreen() { screen.ClearTriangles(); //Used for angle calculation. Vect3D toPointVector; Vect3D toPointVerticalPlaneNormalVector; Vect3D toPointHorizontalPlaneNormalVector; //Angles. double angleLeft; double angleTop; //Position on screen: 0 = left/top, 1 = right/bottom. double screenScalar; Point[] triangleCoordinatesOnScreen; BackFaceCulling(); foreach (int triangleIndex in trianglesOnScreenIndex) { triangleCoordinatesOnScreen = new Point[3]; for (int i = 0; i < 3; i++) { toPointVector = new Vect3D(CameraPosition, triangles[triangleIndex].coordinates[i]); toPointVerticalPlaneNormalVector = Vect3D.VectorProduct(toPointVector, cameraVerticalUnitVector); toPointHorizontalPlaneNormalVector = Vect3D.VectorProduct(toPointVector, cameraHorizontalUnitVector); angleLeft = Relation3D.AngleBetween(toPointVerticalPlaneNormalVector, cameraLeftPlaneNormalVector); angleTop = Relation3D.AngleBetween(toPointHorizontalPlaneNormalVector, cameraTopPlaneNormalVector); toPointVerticalPlaneNormalVector.SwitchOrientation(); toPointHorizontalPlaneNormalVector.SwitchOrientation(); screenScalar = widthScalar * Math.Sin(angleLeft) / Math.Sin(Math.PI - angleLeft - (Math.PI - CameraFieldOfView) / 2); if (Relation3D.AngleBetween(toPointVerticalPlaneNormalVector, cameraRightPlaneNormalVector) > CameraFieldOfView) { screenScalar *= -1; } triangleCoordinatesOnScreen[i].X = Math.Round(screenScalar * screen.Width, 0); screenScalar = heightScalar * Math.Sin(angleTop) / Math.Sin(Math.PI - angleTop - (Math.PI - (CameraFieldOfView / AspectRatio)) / 2); if (Relation3D.AngleBetween(toPointHorizontalPlaneNormalVector, cameraBottomPlaneNormalVector) > CameraFieldOfView / AspectRatio) { screenScalar *= -1; } triangleCoordinatesOnScreen[i].Y = Math.Round(screenScalar * screen.Height, 0); } screen.AddTriangleToScreen(triangleCoordinatesOnScreen); } }
//Copy constructor public ShadeRec(ShadeRec shadeRec) { HitAnObject = shadeRec.HitAnObject; ObjectMaterial = shadeRec.ObjectMaterial; HitPoint = shadeRec.HitPoint; HitPointLocal = shadeRec.HitPointLocal; Normal = shadeRec.Normal; Color = shadeRec.Color; WorldPointer = shadeRec.WorldPointer; Ray = shadeRec.Ray; RecursionDepth = shadeRec.RecursionDepth; Direction = shadeRec.Direction; TMinimum = shadeRec.TMinimum; U = shadeRec.U; V = shadeRec.V; }
//Constructor public ShadeRec(World worldRef) { HitAnObject = false; ObjectMaterial = null; RecursionDepth = 0; WorldPointer = worldRef; HitPoint = new Point3D(0, 0, 0); HitPointLocal = new Point3D(0, 0, 0); Normal = new Normal(0, 0, 0); Color = new RGBColor(0, 0, 0); TMinimum = GlobalVars.K_HUGE_VALUE; Ray = new Ray(new Point3D(0, 0, 0), new Vect3D(0, 0, 0)); Direction = new Vect3D(0, 0, 0); U = 0; V = 0; }
public void BackFaceCulling() { Stack <int> trianglesIndex = new Stack <int>(); Vect3D camToCorner; Vect3D cornerVector1; Vect3D cornerVector2; foreach (int index in trianglesOnScreenIndex) { cornerVector1 = new Vect3D(triangles[index].coordinates[0], triangles[index].coordinates[1]); cornerVector2 = new Vect3D(triangles[index].coordinates[0], triangles[index].coordinates[2]); camToCorner = new Vect3D(CameraPosition, triangles[index].coordinates[0]); if (Vect3D.VectorProduct(cornerVector1, cornerVector2) * camToCorner >= 0.0) { trianglesIndex.Push(index); } } trianglesOnScreenIndex = trianglesIndex.ToArray(); }
//Constructors public Ray(Point3D origin, Vect3D direction) { _origin = new Point3D(origin); _direction = new Vect3D(direction.Hat()); }
/// <summary> /// Creates the a plane in three dimensional space using three points in three dimensional space. /// </summary> /// <param name="point1">First point.</param> /// <param name="point2">Second point.</param> /// <param name="point3">Third point.</param> public Plane3D(Point3D point1, Point3D point2, Point3D point3) { SupportVector = new Vect3D(point1); DirectionVectors[0] = new Vect3D(point1, point2); DirectionVectors[1] = new Vect3D(point1, point3); }
/// <summary> /// /// </summary> /// <param name="triangle"></param> public Plane3D(Triangle3D triangle) { SupportVector = new Vect3D(triangle.coordinates[0]); DirectionVectors[0] = new Vect3D(triangle.coordinates[0], triangle.coordinates[1]); DirectionVectors[1] = new Vect3D(triangle.coordinates[0], triangle.coordinates[2]); }
/// <summary> /// Creates a line from two points in three dimensional space. /// </summary> /// <param name="p1">First point.</param> /// <param name="p2">Second point.</param> public Line3D(Point3D p1, Point3D p2) { SupportVector = new Vect3D(p1); DirectionVector = new Vect3D(p1, p2); }
/// <summary> /// Creates a line from a point on the line and a direction vector. /// </summary> /// <param name="point">Point on the line.</param> /// <param name="directionVector">Direction of the line.</param> public Line3D(Point3D point, Vect3D directionVector) { SupportVector = new Vect3D(point); DirectionVector = directionVector; }
/// <summary> /// Creates a line from a support vector and a direction vector. /// </summary> /// <param name="supportVector">The support vector.</param> /// <param name="directionVector">The direction vector.</param> public Line3D(Vect3D supportVector, Vect3D directionVector) { SupportVector = supportVector; DirectionVector = directionVector; }
public virtual RGBColor SampleF(ShadeRec sr, ref Vect3D incomingDirection, ref Vect3D reflectedDirection) { return GlobalVars.COLOR_BLACK; }
public virtual RGBColor Rho(ShadeRec sr, Vect3D reflectedDirection) { return GlobalVars.COLOR_BLACK; }
//Copy constructor public Ray(Ray ray) { _origin = new Point3D(ray.Origin); _direction = new Vect3D(ray.Direction); }