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);
        }
Esempio n. 3
0
        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);
        }