Triangle Rasterizer with Perspective Correction


Some years ago i implemented a full Software Render (learning purpose) using just regular C#.
Some days ago i was desperate trying to find a good Triangle rasterizer with perspective correction and then i remembered about the code i had written !

The following code shows a barycentric Triangle Rasterizer (i did not put the auxiliar classes, but they are very very intuitive). Idea explained here.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Etapa1.SofRender
{    
    /// 
    /// Baricentric Rasterizer COM perspective correction nos Textcoords[n]
    /// 
    public class BaricentricRasterizer
    {
        public BaricentricRasterizer()
        {
            
        }       

        public List DrawTriangle(Triangle tri)
        {
            List vertices = new List();

            Vector4 p0 = tri.P1[Slots.POSITION0];
            Vector4 p1 = tri.P2[Slots.POSITION0];
            Vector4 p2 = tri.P3[Slots.POSITION0];

            Vector4[] vecs = new Vector4[] { p0, p1, p2 };
            float minx = float.MaxValue;
            float miny = float.MaxValue;
            float maxx = float.MinValue;
            float maxy = float.MinValue;

            foreach (var item in vecs)
            {
                if (item.X < minx)
                {
                    minx = item.X;
                }
                if (item.X > maxx)
                {
                    maxx = item.X;
                }

                if (item.Y < miny)
                {
                    miny = item.Y;
                }
                if (item.Y > maxy)
                {
                    maxy = item.Y;
                }
            }

            for (int i = (int)minx - 1; i <= (int)maxx + 1; i++)
            {
                for (int j = (int)miny - 1; j <= (int)maxy + 1; j++)
                {
                    float alpha = 0;
                    float beta = 0;
                    float gama = 0;
                    ComputeAlphaBethaGama(ref alpha, ref beta, ref gama, tri.P1[Slots.POSITION0], tri.P2[Slots.POSITION0], tri.P3[Slots.POSITION0], i, j);

                    if (alpha >= 0 && alpha <= 1 && beta >= 0 && beta <= 1 && gama >= 0 && gama <= 1)
                    {
                        VertexType vt = new VertexType();                        
                        foreach (var item in tri.P1.VertexElements)
                        {
                            if (item == Slots.NORMAL0 || item == Slots.NORMAL1 || item == Slots.POSITION0 || item == Slots.POSITION1 || item == Slots.COLOR0 || item == Slots.COLOR1 )
                            {
                                vt[item] = alpha * tri.P1[item] + beta * tri.P2[item] + gama * tri.P3[item];                                
                            }
                            else
                            {

                                float w = (1f / tri.P1[Slots.POSITION0].W) * alpha
                                        + (1f / tri.P2[Slots.POSITION0].W) * beta
                                        + (1f / tri.P3[Slots.POSITION0].W) * gama;

                                float xx = (tri.P1[item].X / tri.P1[Slots.POSITION0].W) * alpha
                                    + (tri.P2[item].X / tri.P2[Slots.POSITION0].W) * beta
                                    + (tri.P3[item].X / tri.P3[Slots.POSITION0].W) * gama;

                                float yy = (tri.P1[item].Y / tri.P1[Slots.POSITION0].W) * alpha
                                    + (tri.P2[item].Y / tri.P2[Slots.POSITION0].W) * beta
                                    + (tri.P3[item].Y / tri.P3[Slots.POSITION0].W) * gama;

                                float zz = (tri.P1[item].Z / tri.P1[Slots.POSITION0].W) * alpha
                                    + (tri.P2[item].Z / tri.P2[Slots.POSITION0].W) * beta
                                    + (tri.P3[item].Z / tri.P3[Slots.POSITION0].W) * gama;

                                float ww = (tri.P1[item].W / tri.P1[Slots.POSITION0].W) * alpha
                                    + (tri.P2[item].W / tri.P2[Slots.POSITION0].W) * beta
                                    + (tri.P3[item].W / tri.P3[Slots.POSITION0].W) * gama;

                                float correctedx = xx / w;
                                float correctedy = yy / w;
                                float correctedz = zz / w;
                                float correctedw = ww / w;
                                vt[item] = new Vector4(correctedx, correctedy, correctedz, correctedw);
                            }
                        }
                        float z = alpha * p0.Z + beta * p1.Z + gama * p2.Z;                        
                        vt[Slots.POSITION0] = new Vector4(i, j, z, 1);                                                
                        vertices.Add(vt); 
                    }
                }                
            }
            return vertices;
        }

        void ComputeAlphaBethaGama(ref float alpha, ref float beta, ref float gama , Vector4 p0, Vector4 p1, Vector4 p2 , float x, float y)
        {
            alpha = ComputeFunction(x, y, p1, p2) / ComputeFunction(p0.X, p0.Y, p1, p2);
            beta = ComputeFunction(x, y, p2, p0)  / ComputeFunction(p1.X, p1.Y, p2, p0);
            gama = ComputeFunction(x, y, p0, p1)  / ComputeFunction(p2.X, p2.Y, p0, p1);
        }

        float ComputeFunction(float x, float y, Vector4 pa, Vector4 pb)
        {
            return (pa.Y - pb.Y) * x + (pb.X - pa.X) * y + pa.X * pb.Y - pb.X * pa.Y;
        }

    }
}

I also implemented a "Span" Triangle rasterizer (without perspective correction), the code is also shown below: (idea explanation http://joshbeam.com/articles/triangle_rasterization/)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Etapa1.SofRender
{
    /// 
    /// NAO LEVA EM CONTA A PROFUNDIDADE DOS TRIANGULOS (FORWARD DIFERRENCING)
    /// DA PROBLEMA COM PROJECAO PERSPECTIVA
    /// 
    public class Rasterizer
    {        
        public Rasterizer()
        {
            
        }
        List vos = new List();

        public List DrawTriangle(Triangle t1)
        {
            vos.Clear();
             Edge[] edges = new Edge[]{
                new Edge(t1.P1,t1.P2) , new Edge(t1.P2,t1.P3), new Edge(t1.P3,t1.P1)};

             int maxLength = 0;
             int longEdge = 0;

             // find edge with the greatest length in the y axis
             for (int i = 0; i < 3; i++)
             {
                 int length = (int)edges[i].P2.Y - (int)edges[i].P1.Y;
                 if (length > maxLength)
                 {
                     maxLength = length;
                     longEdge = i;
                 }
             }

             int shortEdge1 = (longEdge + 1) % 3;
             int shortEdge2 = (longEdge + 2) % 3;

             // draw spans between edges; the long edge can be drawn
             // with the shorter edges to draw the full triangle
             DrawSpansBetweenEdges(edges[longEdge], edges[shortEdge1]);
             DrawSpansBetweenEdges(edges[longEdge], edges[shortEdge2]);
             return vos;
        
        }

        private void DrawSpansBetweenEdges(Edge e1, Edge e2)
        {
            // calculate difference between the y coordinates
            // of the first edge and return if 0
            float e1ydiff = (float)(e1.P2.Y - e1.P1.Y);
            if (e1ydiff == 0.0f)
                return;

            // calculate difference between the y coordinates
            // of the second edge and return if 0
            float e2ydiff = (float)(e2.P2.Y - e2.P1.Y);
            if (e2ydiff == 0.0f)
                return;

            // calculate differences between the x coordinates
            // and colors of the points of the edges
        float e1xdiff = (float)(e1.P2.X - e1.P1.X);
        float e2xdiff = (float)(e2.P2.X - e2.P1.X);

        Dictionary Data1 = new Dictionary();
        Dictionary Data2 = new Dictionary();
        foreach (var item in e1.VertexType2.VertexElements)
        {
            Vector4 e1colordiff  = e1.VertexType2[item] - e1.VertexType1[item];
            Vector4 e2colordiff = e2.VertexType2[item] - e2.VertexType1[item];
            Data1[item] = e1colordiff;
            Data2[item] = e2colordiff;
        }
        

         

        // calculate factors to use for interpolation
        // with the edges and the step values to increase
        // them by after drawing each span
        float factor1 = (float)(e2.P1.Y - e1.P1.Y) / e1ydiff;
        float factorStep1 = 1.0f / e1ydiff;
        float factor2 = 0.0f;
        float factorStep2 = 1.0f / e2ydiff;

            // loop through the lines between the edges and draw spans
            for(int y = (int) e2.P1.Y; y < (int)e2.P2.Y; y++) {
                // create and draw span    

                Dictionary Datax1 = new Dictionary();
                Dictionary Datax2 = new Dictionary();
                foreach (var item in e1.VertexType2.VertexElements)
                {
                    Vector4 x1 =  e1.VertexType1[item] + Data1[item] * factor1;
                    Vector4 x2 =  e2.VertexType1[item] + Data2[item] * factor2;
                    Datax1[item] = x1;
                    Datax2[item] = x2;
                }

                Span span = new Span(Datax1,
                          (int)e1.P1.X + (int)(e1xdiff * factor1),
                          Datax2,
                          (int)e2.P1.X + (int)(e2xdiff * factor2));

                DrawSpan(span, y);

                // increase factors
                factor1 += factorStep1;
                factor2 += factorStep2;
        }




        }

        private void DrawSpan(Span span, int y)
        {
            int xdiff = span.X2 - span.X1;
            if (xdiff == 0)
                return;

            Dictionary Data = new Dictionary();
            foreach (var item in span.d1.Keys)
            {
                Data[item] = span.d2[item] - span.d1[item];
                //Color colordiff = span.Color2.SubColors(span.Color1);
            }         
            

            float factor = 0.0f;
            float factorStep = 1.0f / (float)xdiff;

            // draw each pixel in the span
            for (int x = span.X1; x < span.X2; x++)
            {
                VertexType vo = new VertexType();
                foreach (var item in Data.Keys)
                {
                           
                           vo[item] = span.d1[item] + Data[item] * factor;                            
                           //span.Color1.AddColors(colordiff.MultByConstColor(factor))
                }

                vo[Slots.POSITION0] = new Vector4(x, y, vo[Slots.POSITION0].Z, 0);
                vos.Add(vo);
                //render.SetPixel(x, y, 10 ,span.Color1.AddColors(colordiff.MultByConstColor(factor)));
                factor += factorStep;
            }
        }       
        

    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Etapa1.SofRender
{
    public class Span
    {    
       public int X1, X2;
       public Dictionary d1, d2;

       public Span(Dictionary data1, int x1, Dictionary data2, int x2)
       {
           if (x1 < x2)
           {
               this.X1 = x1;
               this.d1 = data1;
               this.X2 = x2;
               this.d2 = data2;
           }
           else
           {
               this.X1 = x2;
               this.d1 = data2;
               this.X2 = x1;
               this.d2 = data1;
           }
       }

    }
}

The code for the full Software Render (not optimized, not well written, not completely right (clipping implementation was a huge workaround), but very good for learning) can be found here http://softrender.codeplex.com/.

,

  1. #1 by garage roller doors sydney on 19 de agosto de 2017 - 11:26 am

    usually posts some very interesting stuff like this. If youre new to this site

  2. #2 by Marijuana Dispensary on 19 de agosto de 2017 - 11:27 am

    Hey very nice site!! Man .. Beautiful .. Amazing .. I will bookmark your website and take the feeds also…I’m happy to find so many useful information here in the post, we need develop more strategies in this regard, thanks for sharing. . . . . .

  3. #3 by online sportsbook on 19 de agosto de 2017 - 12:22 pm

    This blog is definitely rather handy since I’m at the moment creating an internet floral website – although I am only starting out therefore it’s really fairly small, nothing like this site. Can link to a few of the posts here as they are quite. Thanks much. Zoey Olsen

  4. #4 by merlin garage door opener on 19 de agosto de 2017 - 12:52 pm

    check beneath, are some entirely unrelated websites to ours, nonetheless, they’re most trustworthy sources that we use

  5. #5 by Mirina Collections on 19 de agosto de 2017 - 12:54 pm

    Your home is valueble for me. Thanks!…

  6. #6 by http://www.saugatuck.com/louboutin.asp on 19 de agosto de 2017 - 1:29 pm

    I have the headphonesof my personal mother for mothers evening, plus she absolutely adored things! It really is really pretty headphonesand the saying regarding the card your goes into the box is very emotional!! And the premium of beads are very good!

  7. #7 by Birkin Hermes Replica on 19 de agosto de 2017 - 1:30 pm

    I had gotten this headphonesconcerning my mom to parents evening, and also she completely adored that it! The actually attractive headphonesas well as the saying regarding the card which will come in the box is very sentimental!! And the quality of the beads is very good!

  8. #9 by net gambling sites on 19 de agosto de 2017 - 1:40 pm

    Wonderful web site. Lots of useful information here. I’m sending it to some pals ans also sharing in delicious. And obviously, thank you for your effort!

  9. #10 by garage doors on 19 de agosto de 2017 - 2:05 pm

    the time to read or check out the content material or web-sites we’ve linked to below the

  10. #11 by garage door on 19 de agosto de 2017 - 2:25 pm

    always a large fan of linking to bloggers that I enjoy but really don’t get a whole lot of link adore from

  11. #12 by http://copenhagenclinic.dk on 19 de agosto de 2017 - 3:13 pm

    Right now it appears like Drupal is the best blogging platform available right now. (from what I’ve read) Is that what you’re using on your blog?

  12. #13 by pvc strip curtain chennai on 19 de agosto de 2017 - 3:34 pm

    You should take part in a contest for one of the best blogs on the web. I will recommend this site!

  13. #14 by live tv on 19 de agosto de 2017 - 3:42 pm

    Fantastic web site. A lot of useful info here. I’m sending it to some friends ans also sharing in delicious. And of course, thanks for your sweat!

  14. #15 by kauaseguros.blogs.sapo.pt on 19 de agosto de 2017 - 4:44 pm

    very nice post, i certainly love this website, keep on it

  15. #16 by finde mehr on 19 de agosto de 2017 - 4:50 pm

    Er wird Dir wahrscheinlich erzählen, dass er einen Job sucht und auch seinen Aufenthalt bekommt.

  16. #17 by line tv on 19 de agosto de 2017 - 5:05 pm

    Thank you for another informative site. The place else could I get that kind of information written in such an ideal way? I’ve a challenge that I am just now operating on, and I have been on the glance out for such information.

  17. #18 by Cheap Moncler Coats on 19 de agosto de 2017 - 5:37 pm

    I have our headphonesof my personal mother concerning mothers day, then she definitely liked it! The actually pretty headphonesas well as the saying on the card you already know will come into the container is really sentimental!! And top quality of beads is actually ideal!

  18. #19 by hermes belt replica on 19 de agosto de 2017 - 5:37 pm

    I got that headphonesof my personal mother towards mothers evening, as well as she completely adored it! Their actually pretty headphonesas well as the saying in the card your goes into the package is very sentimental!! And top quality of the beads was ideal!

  19. #20 by Collene Asselmeier on 19 de agosto de 2017 - 5:42 pm

    What a cute little Fuck Doll. May she be fucked to high heaven….

  20. #21 by Leland Ouinones on 19 de agosto de 2017 - 5:42 pm

    Do you let the arab niggers fuck her? You swedes seem to enjoy the Arabs. http://www.freehdpornx.com/gushing-pussy-veronica-vain.htm

  21. #22 by http://www.ud-dannelse.dk on 19 de agosto de 2017 - 6:20 pm

    You really make it appear really easy with your presentation however I in finding this topic to be really one thing that I think I’d never understand. It sort of feels too complex and very huge for me. I’m taking a look forward in your subsequent submit, I will attempt to get the dangle of it!

  22. #23 by MBBS Admission in Government College on 19 de agosto de 2017 - 6:57 pm

    I?d have to check with you here. Which is not something I usually do! I enjoy reading a post that will make people think. Also, thanks for allowing me to comment!

  23. #24 by garage roller doors sydney on 19 de agosto de 2017 - 7:18 pm

    one of our guests a short while ago advised the following website

  24. #25 by http://www.sundbirsta.com/ukclreplica.asp on 19 de agosto de 2017 - 8:16 pm

    I had gotten this headphonesof the mom of mothers time, as well as she completely liked things! The quite adorable headphonesand the suggesting regarding the card in which comes in box is very sentimental!! As well as the high quality of beads is actually great!

  25. #26 by cheap nike roshe run on 19 de agosto de 2017 - 8:17 pm

    I have this one headphonesof our mom for mothers time, then she definitely loved that! It is actually cute headphonesand stating regarding the card just that goes within the package is really sentimental!! And the excellent of the beads is awesome!

  26. #27 by click on 19 de agosto de 2017 - 8:22 pm

    Amazing blog! Do you have any suggestions for aspiring writers? I’m hoping to start my own website soon but I’m a little lost on everything. Would you propose starting with a free platform like WordPress or go for a paid option? There are so many options out there that I’m totally overwhelmed .. Any ideas? Appreciate it!

  27. #28 by free snap milfs on 19 de agosto de 2017 - 8:44 pm

    free snap milfs

  28. #29 by meine quellen on 19 de agosto de 2017 - 9:00 pm

    Welch ein schönes Stück.Nun sah ich ihn zwischen einer Menge interessierter Gäste einen Pfeiler lehnen und stoisch auf einen großformatigen Akt schauen.

  29. #30 by merlin garage door on 19 de agosto de 2017 - 9:13 pm

    Here is a great Weblog You may Come across Exciting that we Encourage You

1 826 827 828
(não será publicado)