public static TVertex CrossProduct(TVertex P1, TVertex P2) { TVertex Result = new TVertex(P1.Y * P2.Z - P1.Z * P2.Y, P1.Z * P2.X - P1.X * P2.Z, P1.X * P2.Y - P1.Y * P2.X); return(Result); }
public void AddChildObject(CObject3D ChildObj, TVertex AxisPointA, TVertex AxisPointB) { Children.Add(ChildObj); ChildObj.Father = this; ChildObj.OriginalAxisPointA = AxisPointA; ChildObj.TransformedAxisPointA = AxisPointA; ChildObj.OriginalAxisPointB = AxisPointB; ChildObj.TransformedAxisPointB = AxisPointB; }
public void SetPos(TVertex NewPos) { CurrentPos = NewPos; TMat4x4 TransMat = TMat4x4.ZeroMat(); TransMat.SetTrans(NewPos.X, NewPos.Y, NewPos.Z); SetMatrix(TransMat); }
public TVertex MulVertex(TVertex v) { TVertex Result; Result.X = v.X * m00 + v.Y * m10 + v.Z * m20 + m30; Result.Y = v.X * m01 + v.Y * m11 + v.Z * m21 + m31; Result.Z = v.X * m02 + v.Y * m12 + v.Z * m22 + m32; return(Result); }
public TVertex FindNewPosXZ(float DeltaStep) { float AngleInRad = Math3D.Deg2Rad(Orientation); TVertex Result = new TVertex(CurrentPos.X + (float)Math.Sin(AngleInRad) * DeltaStep, CurrentPos.Y, CurrentPos.Z + (float)Math.Cos(AngleInRad) * DeltaStep); return(Result); }
// Return a normalized vector public static TVertex CalcNormalizedVec(TVertex p1, TVertex p2) { float Mag; TVertex Result; Mag = (float)Math.Sqrt(Sqr(p1.X - p2.X) + Sqr(p1.Y - p2.Y) + Sqr(p1.Z - p2.Z)); Result.X = (p2.X - p1.X) / Mag; Result.Y = (p2.Y - p1.Y) / Mag; Result.Z = (p2.Z - p1.Z) / Mag; return(Result); }
public void GotoNewPosXZ(TVertex NewPos) { TMat4x4 TransMat = TMat4x4.ZeroMat(); TMat4x4 RotMatY = TMat4x4.ZeroMat(); CurrentPos = NewPos; TransMat.SetTrans(NewPos.X, NewPos.Y, NewPos.Z); RotMatY.SetRotateY(Math3D.Deg2Rad(Orientation + OrientationOffset)); SetMatrix(RotMatY.MulMat(TransMat)); }
public static TVertex CalcFaceNormal(TVertex P1, TVertex P2, TVertex P3) { P2.X = P2.X - P1.X; P2.Y = P2.Y - P1.Y; P2.Z = P2.Z - P1.Z; P3.X = P3.X - P1.X; P3.Y = P3.Y - P1.Y; P3.Z = P3.Z - P1.Z; return(CrossProduct(P2, P3)); }
public void Assign(CObject3D CopyFrom) { ObjectMat = CopyFrom.ObjectMat; VertexTable = new TVertex[CopyFrom.VertexTable.Length]; Array.Copy(CopyFrom.VertexTable, VertexTable, VertexTable.Length); FaceTable = new TFace3D[CopyFrom.FaceTable.Length]; Array.Copy(CopyFrom.FaceTable, FaceTable, FaceTable.Length); ObjectMat = CopyFrom.ObjectMat; CombinedMatrix = CopyFrom.CombinedMatrix; Children = CopyFrom.Children; ChildrenAxes = CopyFrom.ChildrenAxes; Father = CopyFrom.Father; OriginalAxisPointA = CopyFrom.OriginalAxisPointA; OriginalAxisPointB = CopyFrom.OriginalAxisPointB; }
private void CalculatePolygonFactors(TVertex Normal, TVertex PointOnPlane, float PerspFactor, out float M, out float N, out float K) { float A, B, C, D; A = Normal.X; B = Normal.Y; C = Normal.Z; D = Math3D.DotProduct(Normal, PointOnPlane); if (D != 0) { M = A / (D * PerspFactor); N = B / (D * PerspFactor); K = C / D; } else { M = 0; N = 0; K = 0; } }
public TVertex TransformVertex(TVertex v) { return(CombinedMatrix.MulVertex(v)); }
// Set rotation matrix around arbitrary axis public void SetArbitraryRot(TVertex P1, TVertex P2, float Angle) { TMat4x4 MTra = ZeroMat(), MRo_X = ZeroMat(), MRo_Y = ZeroMat(), MRo_Z = ZeroMat(), TempM = ZeroMat(); float D; // Find the direction cosines of the arbitrary axis P1-->P2 . // The direction cosines will be in C TVertex C = Math3D.CalcNormalizedVec(P1, P2); D = (float)Math.Sqrt(Math3D.Sqr(C.Y) + Math3D.Sqr(C.Z)); // Special case for the X axis if (D == 0) { MTra.SetTrans(-P1.X, -P1.Y, -P1.Z); MRo_X.SetRotateX(Angle); TempM = MTra.MulMat(MRo_X); MTra.SetTrans(P1.X, P1.Y, P1.Z); this = TempM.MulMat(MTra); } else { MTra.SetTrans(-P1.X, -P1.Y, -P1.Z); // Prepare matrix rotation about axis X with angle Alfa Cos(Alfa) = C.z / D Sin(Alfa) = C.y / D } MRo_X.SetUnit(); MRo_X.m11 = C.Z / D; MRo_X.m22 = MRo_X.m11; MRo_X.m12 = C.Y / D; MRo_X.m21 = -MRo_X.m12; // prepare matrix rotation about axis Y with angle Beta Cos(Beta) = D Sin(Beta) = -C.x MRo_Y.SetUnit(); MRo_Y.m00 = D; MRo_Y.m22 = MRo_Y.m00; MRo_Y.m02 = C.X; MRo_Y.m20 = -MRo_Y.m02; TMat4x4 M; // M= Trans * Rot about axis X * Rot about axis Y TempM = MTra.MulMat(MRo_X); M = TempM.MulMat(MRo_Y); // prepare matrix rotation about axis Z with angle Angle MRo_Z.SetRotateZ(Angle); // TempM= Trans * Rot axis X * Rot axis Y * Rot about axis Z by angle Angle TempM = M.MulMat(MRo_Z); // Find inverse Y matrix MRo_Y.m00 = D; MRo_Y.m22 = D; MRo_Y.m02 = -C.X; MRo_Y.m20 = C.X; M = TempM.MulMat(MRo_Y); // Find inverse x matrix MRo_X.m11 = C.Z / D; MRo_X.m22 = MRo_X.m11; MRo_X.m21 = C.Y / D; MRo_X.m12 = -MRo_X.m21; TempM = M.MulMat(MRo_X); // Find inverse translation matrix MTra.SetTrans(P1.X, P1.Y, P1.Z); this = TempM.MulMat(MTra); } }
public static float DotProduct(TVertex P1, TVertex P2) { return(P1.X * P2.X + P1.Y * P2.Y + P1.Z * P2.Z); }
// The distance from point P1 to P2 public static float PointDistance(TVertex P1, TVertex P2) { return((float)Math.Sqrt(Sqr(P1.X - P2.X) + Sqr(P1.Y - P2.Y) + Sqr(P1.Z - P2.Z))); }
private void TransformAxis(TMat4x4 Mat) { TransformedAxisPointA = Mat.MulVertex(OriginalAxisPointA); TransformedAxisPointB = Mat.MulVertex(OriginalAxisPointB); }
private bool TestForBackClipping(TVertex V1, TVertex V2, TVertex V3) { return(!((V1.Z < 0) && (V2.Z < 0) && (V3.Z < 0))); }
// Perform rendering on a specific context public void Render(CRenderContext Context) { if (!Visible) { return; } // Calculate transform matrix TMat4x4 Mat = GetTransformMatrix(Context); // Calculate the inverse matrix TMat4x4 InverseMat = Mat.FindInverseMat(); // Clear translation effect InverseMat.ClearTranslation(); // Calculate the viewer position in object coordinates TVertex ViewDirection = Context.GetViewDirection(); TVertex ViewerPosInObjCoords = InverseMat.MulVertex(ViewDirection); float PerspectiveFactor = Context.GetPerspectiveFactor(); Color IlluminatedFaceColor; foreach (TFace3D Face in FaceTable) { bool FaceVisible; float FaceDotProd = 0; if (!Context.IsBackfaceCullingMode()) { // No backface culling, the face is always visible FaceVisible = true; } else { // Do backface culling FaceDotProd = Math3D.DotProduct(ViewerPosInObjCoords, Face.Normal); // Perspective mode if (Context.IsPerspectiveMode()) { // Remember if the face is visible FaceVisible = (FaceDotProd > THRESHOLD_FOR_CULLING); } else { FaceVisible = (FaceDotProd > 0); } } if (FaceVisible) { // Get current face vertices and transform to world coordinates TVertex[] FaceVertex = new TVertex[3] { Mat.MulVertex(VertexTable[Face.AIndex]), Mat.MulVertex(VertexTable[Face.BIndex]), Mat.MulVertex(VertexTable[Face.CIndex]) }; Point[] ScreenCoords = new Point[3]; if (TestForBackClipping(FaceVertex[0], FaceVertex[1], FaceVertex[2])) { bool PreventFaceDraw = false; // Perspective mode if (Context.IsPerspectiveMode()) { // Transform the from world coordinates to screen coordinates for (int i = 0; i < 3; i++) { if (Math.Abs(FaceVertex[i].Z) < POLYGON_Z_MIN_VALUE) { PreventFaceDraw = true; break; } ScreenCoords[i].X = (int)(FaceVertex[i].X * PerspectiveFactor / FaceVertex[i].Z); ScreenCoords[i].Y = (int)(FaceVertex[i].Y * PerspectiveFactor / FaceVertex[i].Z); if ((Math.Abs(ScreenCoords[i].X) > POLYGON_COORD_MAX_VALUE) || (Math.Abs(ScreenCoords[i].Y) > POLYGON_COORD_MAX_VALUE)) { PreventFaceDraw = true; break; } } } else // Orthogonal projection { PreventFaceDraw = false; // Transform the from world coordinates to screen coordinates for (int i = 0; i < 3; i++) { ScreenCoords[i].X = (int)(FaceVertex[i].X / ORTHO_PROJECTION_SCALING); ScreenCoords[i].Y = (int)(FaceVertex[i].Y / ORTHO_PROJECTION_SCALING); } } if (!PreventFaceDraw) { T2DTriangle ScreenTriangle = new T2DTriangle(ScreenCoords[0], ScreenCoords[1], ScreenCoords[2]); if (Context.IsWireFrameMode()) { Context.DrawTriangle(ScreenTriangle); } else // Filled triangles mode { float LightLevel = FaceDotProd + MIN_LIGHT_LEVEL; // Clip to maximum light level if (LightLevel > 1.0) { LightLevel = 1.0f; } // Calculate face color int ARGBColor = ClipColorChn(Face.Color.R, LightLevel); ARGBColor |= ClipColorChn(Face.Color.G, LightLevel) << 8; ARGBColor |= ClipColorChn(Face.Color.B, LightLevel) << 16; // Set maximum alpha channel value ARGBColor = (int)((uint)ARGBColor | 0xff000000); IlluminatedFaceColor = Color.FromArgb(ARGBColor); // Calculate factors for the polygon filling routine TVertex FaceNormal = Math3D.CalcFaceNormal(FaceVertex[0], FaceVertex[1], FaceVertex[2]); float M, N, K; CalculatePolygonFactors(FaceNormal, FaceVertex[1], PerspectiveFactor, out M, out N, out K); TriangleFiller.DrawFilledTriangle(ScreenTriangle, Context, IlluminatedFaceColor, M, N, K); } } } } } RenderChildObjects(Context); }