/// <summary> /// Does a perspective-correct, 3-way interpolation of vertex data based on projected point. /// Only ProjectedPosition, WorldPosition and Color/ColorTolerance have meaning here. /// </summary> /// <param name="x">2D Screen-Space pixel X coordinate</param> /// <param name="y">2D Screen-Space pixel Y coordinate</param> /// <returns>Perspective-correct interpolated Vertex value for this point.</returns> override public Vertex GetVertex(double x, double y) { Vertex interpolation = new Vertex(); Point3D currRasterPoint = new Point3D(x, y, 0); Weights screenWeights = ComputeScreenWeights(currRasterPoint); // This gets us screen weights // Use screen weights to find current Z Point3D currProjectedPoint = new Point3D(x, y, WeightedSum(vertex1.ProjectedPosition.Z, vertex2.ProjectedPosition.Z, vertex3.ProjectedPosition.Z, screenWeights)); interpolation.ProjectedPosition = currProjectedPoint; // Now that we have currProjectedPoint, we can go ahead and compute other weights Weights homogeneousWeights = ComputeHomogeneousWeights(currProjectedPoint); // Now we can use the perspectiveCorrectionFactor and the homogeneousWeights to // find the perspective-correct weights. Weights pcWeights = ComputePerspectiveCorrectWeights(homogeneousWeights); // Position ( Eye Space ) interpolation.Position = Interpolator.WeightedSum(vertex1.Position, vertex2.Position, vertex3.Position, pcWeights); // Normal - ignored // Texture Coordinates - ignored // Color - force V1 since all magic lines are the same interpolation.Color = vertex1.Color; // Color Error - force black by default interpolation.ColorTolerance = Color.FromArgb(0x00, 0x00, 0x00, 0x00); if (pixelOnEdge) { // Since numerical precision makes these borderline cases inaccurate, // we set the tolerance of this pixel to ignore it. interpolation.ColorTolerance = Color.FromArgb(0x00, 0xFF, 0xFF, 0xFF); } return(interpolation); }
private Edge GetClippingPlaneEdge(Point3D p1, Point3D p2, Point3D p3, double planeDepth) { double z1 = p1.Z - planeDepth; double z2 = p2.Z - planeDepth; double z3 = p3.Z - planeDepth; bool ss12 = MathEx.SameSign(z1, z2); bool ss23 = MathEx.SameSign(z2, z3); bool ss31 = MathEx.SameSign(z3, z1); // We can determine where the clipping plane intersects the Triangle by performing "same sign" tests // on the z values of the projected vertices // // 1-------------3 // \ / \ / The internal lines represent edges created by the clipping plane // \/b a\/ . if 1 & 2 are on the same side of the plane and 3 is not // \ c / - create and return segment a // \-----/ . if 2 & 3 are on the same side of the plane and 1 is not // \ / - create and return segment b // \ / . if 3 & 1 are on the same side of the plane and 2 is not // 2 - create and return segment c // . otherwise, the clipping plane does not intersect this triangle // - return null if (ss12 && !ss23) { // Segment a Weights w1 = Interpolator.GetWeightsToXYPlane(p1, p3, planeDepth); Weights w2 = Interpolator.GetWeightsToXYPlane(p2, p3, planeDepth); Point3D start = Interpolator.WeightedSum(p1, p3, w1); Point3D end = Interpolator.WeightedSum(p2, p3, w2); return(new Edge(start, end)); } if (ss23 && !ss31) { // Segment b Weights w1 = Interpolator.GetWeightsToXYPlane(p1, p2, planeDepth); Weights w2 = Interpolator.GetWeightsToXYPlane(p1, p3, planeDepth); Point3D start = Interpolator.WeightedSum(p1, p2, w1); Point3D end = Interpolator.WeightedSum(p1, p3, w2); return(new Edge(start, end)); } if (ss31 && !ss12) { // Segment c Weights w1 = Interpolator.GetWeightsToXYPlane(p1, p2, planeDepth); Weights w2 = Interpolator.GetWeightsToXYPlane(p2, p3, planeDepth); Point3D start = Interpolator.WeightedSum(p1, p2, w1); Point3D end = Interpolator.WeightedSum(p2, p3, w2); return(new Edge(start, end)); } return(null); }
private Vertex GetVertexAheadOfCamera(Vertex v1, Vertex v2) { // At this point, being ahead of camera is being in -z Weights weights = Interpolator.GetWeightsToXYPlane(v1.PositionAsPoint3D, v2.PositionAsPoint3D, -distanceAheadOfCamera); Vertex result = new Vertex(); result.Color = Interpolator.WeightedSum(v1.Color, v2.Color, weights); result.ColorTolerance = Interpolator.WeightedSum(v1.ColorTolerance, v2.ColorTolerance, weights); result.ModelSpacePosition = Interpolator.WeightedSum(v1.ModelSpacePosition, v2.ModelSpacePosition, weights); result.Position = Interpolator.WeightedSum(v1.Position, v2.Position, weights); result.TextureCoordinates = Interpolator.WeightedSum(v1.TextureCoordinates, v2.TextureCoordinates, weights); result.ModelSpaceNormal = MathEx.Normalize(Interpolator.WeightedSum(v1.ModelSpaceNormal, v2.ModelSpaceNormal, weights)); result.Normal = MathEx.Normalize(Interpolator.WeightedSum(v1.Normal, v2.Normal, weights)); return result; }
public Triangle[] CreateScreenSpaceLines(Point3D begin, Point3D end, double thickness, Color color) { VerticesBehindCamera behind = VerticesBehindCamera.None; if (begin.Z >= 0) { behind |= VerticesBehindCamera.Vertex1; } if (end.Z >= 0) { behind |= VerticesBehindCamera.Vertex2; } switch (behind) { case VerticesBehindCamera.Vertex1: { // 'begin' is behind the camera. Replace it with a new point that isn't. Weights weights = Interpolator.GetWeightsToXYPlane(begin, end, -distanceAheadOfCamera); begin = Interpolator.WeightedSum(begin, end, weights); break; } case VerticesBehindCamera.Vertex2: { // 'end' is behind the camera. Replace it with a new point that isn't. Weights weights = Interpolator.GetWeightsToXYPlane(begin, end, -distanceAheadOfCamera); end = Interpolator.WeightedSum(begin, end, weights); break; } case VerticesBehindCamera.Vertex1And2: return(new Triangle[0]); default: break; } return(new Triangle[] { new ScreenSpaceLineTriangle(begin, end, thickness, color, projection), new ScreenSpaceLineTriangle(end, begin, thickness, color, projection) }); }