private static FragmentData?AsyncTask(int x, int y, ref Vector3 V0P, ref Vector3 V1P, ref Vector3 V2P, ref Vector2 V02, ref Vector2 V12, ref Vector2 V22, ref VertexData V0, ref VertexData V1, ref VertexData V2) { Vector2 pos; Vector3 BaryCoord; //check if pixel is to be ignored or not //conservative rasterization only rasterizes if center of fragment is in the triangle pos = new Vector2(x + .5f, y + .5f); BaryCoord = BaryCentricCoord(pos, V0P, V1P, V2P); //discard fragments which do not have their centers intersect the triangle if (!InBounds(BaryCoord.X, 0, 1) || !InBounds(BaryCoord.Y, 0, 1) || !InBounds(BaryCoord.Z, 0, 1)) { return(null); } //interpolate vertex data into fragment data FragmentData frag = InterpolateData(V0, V1, V2, BaryCoord); //interpolate z position and store x and y frag.Position = new Vector3(x, y, V0P.Z * BaryCoord.X + V1P.Z * BaryCoord.Y + V2P.Z * BaryCoord.Z); //save fragment (order is not important) return(frag); }
/// <summary> /// Interpolate a Fragment's data using its location with regards to its triangle and the triangle data /// </summary> /// <param name="V0">vertex data for vertex 1 of the triangle</param> /// <param name="V1">vertex data for vertex 2 of the triangle</param> /// <param name="V2">vertex data for vertex 3 of the triangle</param> /// <param name="Coordinates">barycentric coordinates of the fragment</param> /// <returns>interpolated fragment data</returns> public static FragmentData InterpolateData(VertexData V0, VertexData V1, VertexData V2, Vector3 Coordinates) { FragmentData ret = FragmentData.Default(); //linearly interpolate all data for fragment for (int i = 0; i < V0.Booleans.Count; i++) { float zero = (V0.Booleans[i] ? Coordinates.X : 0), one = (V1.Booleans[i] ? Coordinates.Y : 0), two = (V2.Booleans[i] ? Coordinates.Z : 0); ret.Booleans.Add((zero + one + two) >= .5); } for (int i = 0; i < V0.DoubleFloatingPoints.Count; i++) { ret.DoubleFloatingPoints.Add((V0.DoubleFloatingPoints[i] * Coordinates.X) + (V1.DoubleFloatingPoints[i] * Coordinates.Y) + (V2.DoubleFloatingPoints[i] * Coordinates.Z)); } for (int i = 0; i < V0.FloatingPoints.Count; i++) { ret.FloatingPoints.Add((V0.FloatingPoints[i] * Coordinates.X) + (V1.FloatingPoints[i] * Coordinates.Y) + (V2.FloatingPoints[i] * Coordinates.Z)); } for (int i = 0; i < V0.Integer16s.Count; i++) { ret.Integer16s.Add((short)((V0.Integer16s[i] * Coordinates.X) + (V1.Integer16s[i] * Coordinates.Y) + (V2.Integer16s[i] * Coordinates.Z))); } for (int i = 0; i < V0.Integer64s.Count; i++) { ret.Integer64s.Add((long)((V0.Integer64s[i] * Coordinates.X) + (V1.Integer64s[i] * Coordinates.Y) + (V2.Integer64s[i] * Coordinates.Z))); } for (int i = 0; i < V0.Integers.Count; i++) { ret.Integers.Add((int)((V0.Integers[i] * Coordinates.X) + (V1.Integers[i] * Coordinates.Y) + (V2.Integers[i] * Coordinates.Z))); } for (int i = 0; i < V0.Integer8s.Count; i++) { ret.Integer8s.Add((byte)((V0.Integer8s[i] * Coordinates.X) + (V1.Integer8s[i] * Coordinates.Y) + (V2.Integer8s[i] * Coordinates.Z))); } for (int i = 0; i < V0.Matricies.Count; i++) { ret.Matricies.Add((V0.Matricies[i] * Coordinates.X) + (V1.Matricies[i] * Coordinates.Y) + (V2.Matricies[i] * Coordinates.Z)); } for (int i = 0; i < V0.Vector2s.Count; i++) { ret.Vector2s.Add((V0.Vector2s[i] * Coordinates.X) + (V1.Vector2s[i] * Coordinates.Y) + (V2.Vector2s[i] * Coordinates.Z)); } for (int i = 0; i < V0.Vector3s.Count; i++) { ret.Vector3s.Add((V0.Vector3s[i] * Coordinates.X) + (V1.Vector3s[i] * Coordinates.Y) + (V2.Vector3s[i] * Coordinates.Z)); } for (int i = 0; i < V0.Vector4s.Count; i++) { ret.Vector4s.Add((V0.Vector4s[i] * Coordinates.X) + (V1.Vector4s[i] * Coordinates.Y) + (V2.Vector4s[i] * Coordinates.Z)); } return(ret); }
public void Run(VertexIn[] vertexBuffer, int[] indexBuffer, CBuffer constantBuffer, Bitmap outputBuffer, float[,] depthBuffer) { TextureSampler sampler = new TextureSampler() { _pipeline = this }; //initialize variables if (verts == null || verts.Length == vertexBuffer.Length) { verts = new VertexData[vertexBuffer.Length]; } if (depthBuffer != null) { if (depthLock == null || depthLock.GetLength(0) != outputBuffer.Width || depthLock.GetLength(1) != outputBuffer.Height) { depthLock = new object[depthBuffer.GetLength(0), depthBuffer.GetLength(0)]; } for (int x = 0; x < outputBuffer.Width; x++) { for (int y = 0; y < outputBuffer.Height; y++) { depthLock[x, y] = new object(); } } } //Create tasks and process vertices; Parallel.For(0, vertexBuffer.Length, (i) => { verts[i] = VertexShader.VertexMain(vertexBuffer[i], in constantBuffer); verts[i].Position.Y = -verts[i].Position.Y; }); int size = outputBuffer.Width * outputBuffer.Height; BitmapData dat = outputBuffer.LockBits(new Rectangle(0, 0, 800, 600), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); byte[] colDat = new byte[size * 4]; Marshal.Copy(dat.Scan0, colDat, 0, colDat.Length); int width = outputBuffer.Width; int height = outputBuffer.Height; //Create tasks and process data to output pixels Parallel.For(0, indexBuffer.Length / 3, (i) => { int i1 = i * 3; //Assemble geometry and rasterize triangles List <FragmentData> frags = SoftwareRasterizer.Rasterize(verts[indexBuffer[i1]], verts[indexBuffer[i1 + 1]], verts[indexBuffer[i1 + 2]], height, width); Parallel.For(0, frags.Count, (j) => { //get fragment FragmentData frag = frags[j]; //get pixel color Vector4 pixel = FragmentShader.FragmentMain(frag, in sampler, in constantBuffer); //store coord into ints for speed int x = (int)frag.Position.X, y = (int)frag.Position.Y; //don't do depth test if no buffer is given if (depthBuffer == null) { lock (depthLock[x, y]) { int index = (y * width) + x; index *= 4; colDat[index] = (byte)(pixel.Z * 255); colDat[index + 1] = (byte)(pixel.Y * 255); colDat[index + 2] = (byte)(pixel.X * 255); colDat[index + 3] = (byte)(pixel.W * 255); } } else { //check depth buffer and set output if necessary //lock for thread safety lock (depthLock[x, y]) { //check if our pixel is nearer than nearest pixel previously drawn float depth = depthBuffer[x, y]; if (frag.Position.Z <= depth) { //if our pixel is closest, set depthbuffer to our depth depthBuffer[x, y] = frag.Position.Z; //set outputBuffer color int index = (y * width) + x; index *= 4; colDat[index] = (byte)(pixel.Z * 255); colDat[index + 1] = (byte)(pixel.Y * 255); colDat[index + 2] = (byte)(pixel.X * 255); colDat[index + 3] = (byte)(pixel.W * 255); } } } }); }); Marshal.Copy(colDat, 0, dat.Scan0, colDat.Length); outputBuffer.UnlockBits(dat); }