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 Psychic readings online on 27 de maio de 2017 - 11:35 am

    I recently noticed your website. You’ve got a loads of information here
    that’s why i like it!

  2. #2 by watch Pirates of the Caribbean Dead Men Tell No Tales on 27 de maio de 2017 - 12:15 pm

    Vimeo allows you to watch videos and short films uploaded from the neighborhood, buy films, series, and assistance film creators, in addition to the ability
    to watch and share videos on any device you may have. 

  3. #3 by Business News International on 27 de maio de 2017 - 12:23 pm

    Excellent blog here! Also your web site loads up fast! What host are you using? Can I get your affiliate link to your host? I wish my web site loaded up as quickly as yours lol

  4. #4 by Artificial Intelligence on 27 de maio de 2017 - 12:25 pm

    I like the helpful information you provide in your articles. I’ll bookmark your weblog and check again here regularly. I’m quite sure I’ll learn a lot of new stuff right here! Best of luck for the next!

  5. #5 by http://news.vancleefreplica.xyz/vancleefreplicaxyz/378.asp on 27 de maio de 2017 - 3:30 pm

    Yet not while fancy in real world provided moms wrist is actually never 2small do not choose it result that it try to be tight .. the sweet but anything yur 5year older make . No on not so it really is an ok gifts to present but not letter wow gifts…cant get wrong should don’t have actually a lot to blow for a present subsequently get they

  6. #6 by http://www.ljusihus.se/cartierlove.aspx on 27 de maio de 2017 - 4:02 pm

    it comes down in a beautiful box seems ideal then again it really is somewhat mini truly for the my parents wrist but it appearance very good just wish information technology is extended

  7. #7 by http://www.norgesrevisjon.no/modules/statichtml/514.html on 27 de maio de 2017 - 4:33 pm

    I had gotten this particular headphonesto the mom to parents day, then she completely adored that it! It is truly pretty headphonesand the stating on the card in which comes inside box is really emotional!! As well as the good of the beads are awesome!

  8. #8 by http://bollingercountychamber.com/media/90.html on 27 de maio de 2017 - 4:48 pm

    Great headphonesbuy, well cost and what are shown. Beautiful gift container plus poem additionally enclosed. Ideal for the mother’s day!

  9. #9 by http://www.saveindex.co.uk/ on 27 de maio de 2017 - 4:48 pm

    Our son provided me personally it for mothers day. He understands im maybe not about price tag but what else comes from the actual heart. I can’t feel this has the favourite shade and also truly suits my wrist. I never can get a hold of bracelets to fit headphonesmy personal small wrist. Really happy to own recieved that being a present.

  10. #10 by http://www.aspkucyl.org/files/shoesmen.asp on 27 de maio de 2017 - 8:12 pm

    it comes within a gorgeous container looks awesome and yet it is somewhat little additionally towards my personal moms wrist but it styles great simply want that it is further

  11. #11 by http://www.deshvani.in/client/66.html on 27 de maio de 2017 - 9:16 pm

    Very good headphonesinvest, nicely cost and also what are displayed. Beautiful gifts container to poem always enclosed. Great to mother’s day!

  12. #12 by Finding Peace on 27 de maio de 2017 - 10:10 pm

    we came across a cool web-site which you may well love. Take a search if you want

  13. #13 by arcade games on 27 de maio de 2017 - 10:39 pm

    You actually make it appear really easy along with your presentation however I to find this matter to be really something that I feel I would by no means understand. It seems too complicated and very broad for me. I am looking forward in your subsequent submit, I will attempt to get the grasp of it!

  14. #14 by 2H2D on 27 de maio de 2017 - 11:18 pm

    although web sites we backlink to beneath are considerably not associated to ours, we really feel they’re basically worth a go by, so have a look

  15. #15 by http://news.cartierbraceletsreplica.xyz/cartierbraceletsreplicaxyz/364.asp on 27 de maio de 2017 - 11:38 pm

    Yet not just as fancy in real life if you think moms wrist are not 2small do not buy it cause things feel tight .. its pretty however things yur 5year existing makes . Non some sort of less their a great ok gifts to present but not a wow gifts…cant go wrong when do not have a great deal to blow for a present after that take that

  16. #16 by http://news.cheapmoncler.win/cheapmonclerwin/589.asp on 27 de maio de 2017 - 11:38 pm

    Purchased this one as a present concerning the mom and she loved that. pleasant quality cool cost and also our mother enjoyed things. And sent very accelerated. When you need a gifts quick while such as this then here is the an individual you will need to choose!

  17. #17 by versuchen sie hier on 28 de maio de 2017 - 5:01 am

    Der dünne Stoff ließ wirklich alles erkennen, was sich darunter befand.

  18. #18 by persian tar on 28 de maio de 2017 - 5:08 am

    It really is a good along with handy part of data. I will be pleased that you just embraced this beneficial facts along with us. You should keep us up-to-date like that.. persian tar Appreciate your sharing.

  19. #19 by persian backgammon on 28 de maio de 2017 - 5:08 am

    I became encouraged this blog through my personal uncle persian backgammon. I’m will no longer optimistic whether or not the following set up will be published by method of them because no one understand these kinds of particular in relation to the challenge. You will be excellent! Appreciate it!

  20. #20 by http://www.borgakungen.nu/data/74.html on 28 de maio de 2017 - 7:44 am

    Awesome headphonesgo for, nicely cost then exactly what is revealed. Awesome present container and poem and enclosed. Very good of mother’s day!

  21. #21 by http://stefanbakosab.se/web/html/400.html on 28 de maio de 2017 - 8:39 am

    I have this one headphonesfor the the mom concerning mothers time, additionally she completely liked things! Their really sweet headphonesand the stating on the card in which comes inside box is very sentimental!! As well as the excellent of beads was ideal!

  22. #22 by Physics on 28 de maio de 2017 - 9:26 am

    Well I really enjoyed studying it. This subject procured by you is very practical for correct planning.

  23. #23 by Historical Place on 28 de maio de 2017 - 9:26 am

    My brother recommended I might like this web site. He was totally right. This post actually made my day. You can not imagine simply how much time I had spent for this information! Thanks!

  24. #24 by http://www.unionmarkt.de/plugins/faxhtml/1.html on 28 de maio de 2017 - 9:26 am

    I have the headphonestowards my mom for the moms day, additionally she completely enjoyed they! Their quite adorable headphonesas well as the saying on the card you already know goes into the package is very emotional!! And high quality of the beads was very good!

  25. #25 by http://news.christianlouboutinshoes.xyz/christianlouboutinshoesxyz/377.asp on 28 de maio de 2017 - 9:27 am

    I have this particular headphonesconcerning the mom for parents day, and she absolutely enjoyed things! It is really cute headphonesand stating regarding the card that will come into the box is very sentimental!! As well as the good of the beads was ideal!

  26. #26 by geh jetzt on 28 de maio de 2017 - 9:53 am

    claudia schrieb am 2.

  27. #27 by Lords mobile twitter search on 28 de maio de 2017 - 10:09 am

    I have read so many articles or reviews concerning
    the blogger lovers but this piece of writing is actually a pleasant piece of
    writing, keep it up.

  28. #28 by UK Christian Louboutin Replica on 28 de maio de 2017 - 10:52 am

    I had gotten our gifts to my mom towards Christmas time due to the fact she is actually one jewelry freak. The something she cannot wear a lot out of was, bracelets. I bought the lady that charm bracelet and/or whenever she opened up things yesterday she absolutley adored that! Today the problem is actually, this girl getting it on top of then off of by herself. Haha… on the whole very good goods, information technology delivered then appeared completely very early and/or the mom are enjoying that. Thank a person.

1 759 760 761
(não será publicado)