public void Render(Camera cam, bool orthographic, bool backfaceCulling, float scale, DepthTexture texture, Position3D modelPosition) { //make a copy, don't touch original points to keep accuracy TriangleData tDataTmp = tData; //move the vertices in local space ScaleVertices(ref tDataTmp, scale); RotateVertices(ref tDataTmp, modelPosition); TranslateVerticesLocal(ref tDataTmp, modelPosition); //move the vertices in world space TranslateVerticesWorld(ref tDataTmp, cam.CameraPosition); RotateVertices(ref tDataTmp, cam.CameraPosition); //culling/drawing/perspective if (InZRange(tDataTmp, cam.FarClippingPlane)) { if (!orthographic) { PerspectiveVertices(ref tDataTmp, cam.ScreenDepthTexture, cam.CalculatedFov); } if (backfaceCulling && NotFacingCamera(tDataTmp)) { return; } DrawTriangle(tDataTmp, texture, cam.ScreenDepthTexture); } }
//Check if its in the screenTexture area. Left/right/... are the bounding box of the triangle limited to screen space. //Returns False if not in screen screenTexture area. private bool OnScreen(TriangleData tData, DepthTexture screenTexture, ref int left, ref int right, ref int top, ref int bottom) { left = (int)Left(tData); if (left > screenTexture.Width) { return(false); } right = (int)Right(tData); if (right < 0) { return(false); } top = (int)Top(tData); if (top > screenTexture.Height) { return(false); } bottom = (int)Bottom(tData); if (bottom < 0) { return(false); } left = Math.Max(0, left); right = Math.Min(screenTexture.Width, right); top = Math.Max(0, top); bottom = Math.Min(screenTexture.Height, bottom); return(true); }
private void ScaleVertices(ref TriangleData tData, float scale) { if (scale != 1.0f) { tData.Vertex1.Scale(scale); tData.Vertex2.Scale(scale); tData.Vertex3.Scale(scale); } }
private int Area(TriangleData tData) { int x1 = (int)tData.Vertex1.x; int y1 = (int)tData.Vertex1.y; int x2 = (int)tData.Vertex2.x; int y2 = (int)tData.Vertex2.y; int x3 = (int)tData.Vertex3.x; int y3 = (int)tData.Vertex3.y; return(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)); }
private void PerspectiveVertices(ref TriangleData tData, DepthTexture screenTexture, float calculatedFov) { if (tData.Vertex1.z > 0) { tData.Vertex1.Perspective(calculatedFov, screenTexture.HalfWidth, screenTexture.HalfHeight); } if (tData.Vertex2.z > 0) { tData.Vertex2.Perspective(calculatedFov, screenTexture.HalfWidth, screenTexture.HalfHeight); } if (tData.Vertex3.z > 0) { tData.Vertex3.Perspective(calculatedFov, screenTexture.HalfWidth, screenTexture.HalfHeight); } }
private void TranslateVerticesLocal(ref TriangleData tData, Position3D delta) { tData.Vertex1.TranslateLocal(delta); tData.Vertex2.TranslateLocal(delta); tData.Vertex3.TranslateLocal(delta); }
//triangle render tools private void RotateVertices(ref TriangleData tData, Position3D angle) { tData.Vertex1.Rotate(angle); tData.Vertex2.Rotate(angle); tData.Vertex3.Rotate(angle); }
public BaseTriangle(TriangleData tData) { this.tData = tData; }
private void DrawTriangle(TriangleData tData, DepthTexture modelTexture, DepthTexture screenTexture) { //set array boundes int left = 0; int right = 0; int top = 0; int bottom = 0; if (!OnScreen(tData, screenTexture, ref left, ref right, ref top, ref bottom)) { return; //cull out triangles not in screen space } //setup values for the draw loop int x1 = (int)tData.Vertex1.x; int y1 = (int)tData.Vertex1.y; float z1 = tData.Vertex1.z; int x2 = (int)tData.Vertex2.x; int y2 = (int)tData.Vertex2.y; float z2 = tData.Vertex2.z; int x3 = (int)tData.Vertex3.x; int y3 = (int)tData.Vertex3.y; float z3 = tData.Vertex3.z; //precomputed values int totalArea = Math.Abs(Area(tData)); if (totalArea < 1) { return; //filter subpixel triangles } //precompute area pt1 int y2my3 = y2 - y3; int y3my1 = y3 - y1; int y1my2 = y1 - y2; //computing uvs float uvX1 = tData.Uv1.u * modelTexture.Width; float uvX2 = tData.Uv2.u * modelTexture.Width; float uvX3 = tData.Uv3.u * modelTexture.Width; float uvY1 = tData.Uv1.v * modelTexture.Height; float uvY2 = tData.Uv2.v * modelTexture.Height; float uvY3 = tData.Uv3.v * modelTexture.Height; //draw loop for (int y = top; y < bottom; y++) { //precompute area pt2 int apre = x2 * (y3 - y) + x3 * (y - y2); int bpre = x1 * (y - y3) + x3 * (y1 - y); int cpre = x1 * (y2 - y) + x2 * (y - y1); bool inTriangle = false; //right side exit scanline optimization for (int x = left; x < right; x++) { //find out what points are in the triangle with the precompute area int ba = Math.Abs(x * y2my3 + apre); int bb = Math.Abs(x * y3my1 + bpre); int bc = Math.Abs(x * y1my2 + cpre); if (ba + bb + bc <= totalArea) { inTriangle = true; //interpolate pixel amounts float a = ba / (float)totalArea; float b = bb / (float)totalArea; float c = 1 - (a + b); //get the uv/depth int u = (int)(uvX1 * a + uvX2 * b + uvX3 * c); int v = (int)(uvY1 * a + uvY2 * b + uvY3 * c); float depth = z1 * a + z2 * b + z3 * c; //set the pixel if passes depth test screenTexture.SetPixelDepthTest(x, y, modelTexture.GetPixel(u, v), depth); } else if (inTriangle) { break; //end scanline if exiting right side of the triangle } } } }
private float Bottom(TriangleData tData) { return(MathTools.Max3(tData.Vertex1.y, tData.Vertex2.y, tData.Vertex3.y)); }
private float Top(TriangleData tData) { return(MathTools.Min3(tData.Vertex1.y, tData.Vertex2.y, tData.Vertex3.y)); }
private float Right(TriangleData tData) { return(MathTools.Max3(tData.Vertex1.x, tData.Vertex2.x, tData.Vertex3.x)); }
private float Left(TriangleData tData) { return(MathTools.Min3(tData.Vertex1.x, tData.Vertex2.x, tData.Vertex3.x)); }
private float MinZ(TriangleData tData) { return(MathTools.Min3(tData.Vertex1.z, tData.Vertex2.z, tData.Vertex3.z)); }
private bool NotFacingCamera(TriangleData tData) { return(Area(tData) > -1); }
private bool InZRange(TriangleData tData, float farClippingPlane) { return(!(MaxZ(tData) < 0 || MinZ(tData) > farClippingPlane)); }