//Divide primitives into triangles private void TriangulatePrimitives(ref DrawCall drawCall) { var primitives = new List <Primitive>(); foreach (var item in drawCall.Primitives) { //ignore the primitive that was cliped if (item.Vertics.Length == 0) { continue; } //we select a vertex to make triangulate var importantVertex = item.Vertics[0]; //we can know the number of triangles is (item.Vertics.Length - 2) for (int i = 0; i < item.Vertics.Length - 2; i++) { var vertics = new UnitProperty[3]; //new triangle vertics[0] = importantVertex; vertics[1] = item.Vertics[i + 1]; vertics[2] = item.Vertics[i + 2]; //normalize the ordering(counter-clockwise) Utility.NormalizeOrdering(ref vertics); //add it primitives.Add(new Primitive(vertics)); } } drawCall.Primitives = primitives.ToArray(); }
public void Subtract(UnitProperty unitProperty) { color -= unitProperty.color; depth -= unitProperty.depth; position -= unitProperty.position; positionTransformed -= unitProperty.positionTransformed; positionAfterDivide = positionTransformed / positionTransformed.W; }
public void Add(UnitProperty unitProperty) { color += unitProperty.color; depth += unitProperty.depth; position += unitProperty.position; positionTransformed += unitProperty.positionTransformed; positionAfterDivide = positionTransformed / positionTransformed.W; }
public PixelProperty(UnitProperty baseProperty, Vector2 location) { unitProperty = baseProperty; Location = location; }
protected virtual object OnProcessUnit(ref UnitProperty unitProperty, params object[] inputData) { return(Vector4.Zero); }
internal void StartProcessUnit(ref UnitProperty unitProperty, params object[] inputData) { ProcessUnit.Invoke(ref unitProperty, inputData); }
private void RasterizerPrimitives(ref DrawCall drawCall) { List <PixelProperty> pixels = new List <PixelProperty>(); var renderTarget = GraphicsPipeline.OutputMergerStage.RenderTarget; //for each primitives(triangles) //and the primitives are counter-clockwise. foreach (var primitive in drawCall.Primitives) { //bounding box = (left, top, right, bottom) Vector4 boundingBox = new Vector4(float.MaxValue, float.MaxValue, float.MinValue, float.MinValue); //create triangle Vector2[] triangle = new Vector2[3]; int index = 0; //enum the vertex foreach (var vertex in primitive.Vertics) { //compute the bounding box boundingBox.X = Math.Min(boundingBox.X, vertex.PositionAfterDivide.X); boundingBox.Y = Math.Min(boundingBox.Y, vertex.PositionAfterDivide.Y); boundingBox.Z = Math.Max(boundingBox.Z, vertex.PositionAfterDivide.X); boundingBox.W = Math.Max(boundingBox.W, vertex.PositionAfterDivide.Y); //make triangle data and convert it to the render target //the range of point in the ndc space is [-1 ,1] //so the point in the screen is (point + 1) * size * 0.5f triangle[index] = new Vector2( (primitive.Vertics[index].PositionAfterDivide.X + 1) * renderTarget.Width * 0.5f, (primitive.Vertics[index].PositionAfterDivide.Y + 1) * renderTarget.Height * 0.5f); index++; } //convert the boundingBox to the render target boundingBox.X = (float)Math.Floor((boundingBox.X + 1) * renderTarget.Width * 0.5f); boundingBox.Y = (float)Math.Floor((boundingBox.Y + 1) * renderTarget.Height * 0.5f); boundingBox.Z = (float)Math.Ceiling((boundingBox.Z + 1) * renderTarget.Width * 0.5f); boundingBox.W = (float)Math.Ceiling((boundingBox.W + 1) * renderTarget.Height * 0.5f); //for the float boundingBox.X = Utility.Limit(boundingBox.X, 0, renderTarget.Width); boundingBox.Y = Utility.Limit(boundingBox.Y, 0, renderTarget.Height); boundingBox.Z = Utility.Limit(boundingBox.Z, 0, renderTarget.Width); boundingBox.W = Utility.Limit(boundingBox.W, 0, renderTarget.Height); //get the triangle's area //we do not need to divide 2 float triangleArea = MathHelper.AreaFunction(triangle[0], triangle[1], triangle[2]); //make the UnitProperties for computing the pixel's unitProperty //rule: P = z * (P0 / z0 * e0 + P1 / z1 * e1 + P2 / z2 * e2) //e0 + e1 + e2 = 1 var unitProperties = new UnitProperty[3]; unitProperties[0] = primitive.Vertics[0] / primitive.Vertics[0].PositionTransformed.Z; unitProperties[1] = primitive.Vertics[1] / primitive.Vertics[1].PositionTransformed.Z; unitProperties[2] = primitive.Vertics[2] / primitive.Vertics[2].PositionTransformed.Z; //make the invert z to compute the pixel's invert z //rule: Z = 1 / (1 / z0 * e0 + 1 / z1 * e1 + 1 / z2 * e2) var triangleInvertZ = new float[3]; triangleInvertZ[0] = 1.0f / primitive.Vertics[0].PositionTransformed.Z; triangleInvertZ[1] = 1.0f / primitive.Vertics[1].PositionTransformed.Z; triangleInvertZ[2] = 1.0f / primitive.Vertics[2].PositionTransformed.Z; //enum the pixel for (int x = (int)boundingBox.X; x <= boundingBox.Z; x++) { for (int y = (int)boundingBox.Y; y <= boundingBox.W; y++) { //0.5f offset, because we will use the center of pixel var pixel = new Vector2(x + 0.5f, y + 0.5f); //compute the area(ratio) about sub-triangle float subArea0 = MathHelper.AreaFunction(triangle[1], triangle[2], pixel) / triangleArea; float subArea1 = MathHelper.AreaFunction(triangle[2], triangle[0], pixel) / triangleArea; float subArea2 = MathHelper.AreaFunction(triangle[0], triangle[1], pixel) / triangleArea; if (subArea0 < 0 || subArea1 < 0 || subArea2 < 0) { continue; } //compute the property UnitProperty pixelProperty = unitProperties[0] * subArea0 + unitProperties[1] * subArea1 + unitProperties[2] * subArea2; float invertZ = 1.0f / (triangleInvertZ[0] * subArea0 + triangleInvertZ[1] * subArea1 + triangleInvertZ[2] * subArea2); pixelProperty = pixelProperty * invertZ; //accept the pixel pixels.Add(new PixelProperty(pixelProperty, new Vector2(x, y))); } } } //get the pixels drawCall.Pixels = pixels.ToArray(); }
//Clip the edge with a face private static UnitProperty ClipEdge(UnitProperty start, UnitProperty end, FrustumFace faceIndex) { float t = 0; //vector = end - start var vector = end - start; // result = start + (end - start) * t switch (faceIndex) { case FrustumFace.Left: // (start.x + vector.x * t) / (start.w + vector.w * t) = -1 // t = -(start.x + start.w) / (vector.x + vector.w) // and (vector.x + vector.w) != 0 // because there is most one vertex on the face(x = -w), so (vector.x + vector.w) = (end.x - start.x + end.w - start.w) != 0 t = -(start.PositionTransformed.X + start.PositionTransformed.W) / (vector.PositionTransformed.X + vector.PositionTransformed.W); break; case FrustumFace.Right: // (start.x + vector.x * t) / (start.w + vector.w * t) = 1 // t = (start.w - start.x) / (vector.x - vector.w) // and (vector.x - vector.w) != 0 // because there is most one vertex on the face(x = w), so (vector.x - vector.w) = (end.x - start.x - end.w + start.w) != 0 t = (start.PositionTransformed.W - start.PositionTransformed.X) / (vector.PositionTransformed.X - vector.PositionTransformed.W); break; case FrustumFace.Bottom: // (start.y + vector.y * t) / (start.w + vector.w * t) = -1 // t = (start.y + start.w) / (vector.y + vector.w) // and (vector.y + vector.w) != 0 // because there is most one vertex on the face(y = -w), so (vector.y + vector.w) = (end.y - start.y + end.w - start.w) != 0 t = -(start.PositionTransformed.Y + start.PositionTransformed.W) / (vector.PositionTransformed.Y + vector.PositionTransformed.W); break; case FrustumFace.Top: // (start.y + vector.y * t) / (start.w + vector.w * t) = 1 // t = (start.w - start.y) / (vector.y - vector.w) // and (vector.y - vector.w) != 0 // because there is most one vertex on the face(y = w), so (vector.y - vector.w) = (end.y - start.y - end.w + start.w) != 0 t = (start.PositionTransformed.W - start.PositionTransformed.Y) / (vector.PositionTransformed.Y - vector.PositionTransformed.W); break; case FrustumFace.Near: // (start.z + vector.z * t) / (start.w + vector.w * t) = 0 // t = - (start.z / vector.z) // and vector.z != 0 // because there is most one vertex on the face(z = 0), so vector.z = (end.z - start.z) != 0 t = -(start.PositionTransformed.Z / vector.PositionTransformed.Z); break; case FrustumFace.Far: // (start.z + vector.z * t) / (start.w + vector.w * t) = 1 // t = (start.w - start.z) / (vector.z - vector.w) // and (vector.z - vector.w) != 0 // because there is most one vertex on the face(z = w), so (vector.z - vector.w) = (end.z - start.z - end.w + start.w) != 0 t = (start.PositionTransformed.W - start.PositionTransformed.Z) / (vector.PositionTransformed.Z - vector.PositionTransformed.W); break; default: break; } var result = start + vector * t; //divide for the new vertex result.PositionAfterDivide = result.PositionTransformed / result.PositionTransformed.W; return(result); }
protected virtual void OnProcessUnit(ref UnitProperty unitProperty, object vertex, params object[] inputData) { // }