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