Rasterization 学习笔记

======================Barycentric interpolation======================================

<1>2d/3d Check point in triangle test

float areas(vector p1;vector p2;vector p3)
{
    return length(cross(p1-p2,p3-p2)) * 0.5f;  
}


int ptInTri(vector inpt;vector p1;vector p2; vector p3)
{
    float s = areas(p1,p2,p3);
    float s1 = areas(inpt,p2,p3) / s;
    float s2 = areas(inpt,p3,p1) / s;
    float s3 = areas(inpt,p1,p2) / s;
    if(s1<0.0f || s1>1.0f)
    {
        return false;
    }
    if(s2 < 0.0f || s2 >1)
    {
        return false;
    }
    if(s3 < 0.0f || s3 >1)
    {
        return false;
    }
    float all = s1 + s2 + s3;
    if (all-1.0f<0.000001f)
        return true;
    else 
        return false;
}
View Code

<2>2d check can use : 

<test 3d in houdini found problem>

int ptInTri2(vector P;vector A;vector B; vector C)
{
    vector u = B - A;
    vector v = C - A;
    vector w = P - A;
    
    vector vCrossW = cross(v, w);
    vector vCrossU = cross(v, u);
    
    if (dot(vCrossW, vCrossU) < 0)
        return false;
 
    vector uCrossW = cross(u, w);
    vector uCrossV = cross(u, v);
    
    
    // Test sign of t
    if (dot(uCrossW, uCrossV) < 0)
        return false;
 
    float denom = length(uCrossV);
    float r = length(vCrossW) / denom;
    float t = length(uCrossW) / denom;
 
    return (r + t <= 1);
}
View Code

<3> Color Interpolation:

float areas(vector p1;vector p2;vector p3)
{
    return length(cross(p1-p2,p3-p2)) * 0.5f;  
}

vector P = getInputP();
float s  = areas(p1,p2,p3);
float s1 = areas(P,p2,p3) / s;
float s2 = areas(P,p3,p1) / s;
float s3 = areas(P,p1,p2) / s;

vector PColor = p1.color * s1 + p2.color*s2 + p3.color*s3;
View Code

<4>we can use this method to getPointAt uv like maya function or houdini primuv();

float areas(vector p1;vector p2;vector p3)
{
    return length(cross(p1-p2,p3-p2)) * 0.5f;  
}


vector getPointAtUV(float u;float v)
{
    clamp(u,0,1);
    clamp(v,0,1);
    
    
    // get current gdp's points
    vector gdpPtsPos[];
    for(int i=0;i<3;i++)
    {
        vector curl = point(0,"P",i);
        //printf("%f ,%f , %f 
",curl[0],curl[1],curl[2]);
        append(gdpPtsPos,curl);
    }
    
    vector p1 = gdpPtsPos[0];
    vector p2 = gdpPtsPos[1];
    vector p3 = gdpPtsPos[2];
    
    // tri area     
    float s = areas(p1,p2,p3);
    // reverse to get base on  u value
    
    float uArea = u * 0.5 / s;
    
    // reverse to get base on  v value
    float vArea = v * 0.5 / s ;
    
    
    // the w value 
    float wArea =0;
    if(1 - uArea - vArea < 0)
    {
        wArea = 0;
    }
    else
    {
        wArea =( 1 - u - v )*0.5 / s;
    }
    
        
    //https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/barycentric-coordinates
   
    //P=uA+vB+wC.
    
    vector retP = p1 * uArea + p2*vArea + p3*wArea;
    return retP;
           
}



#define maxscatter 100000

for(int i=0;i<maxscatter;i++)
{
    float u = rand(i);
    float v = rand(i*100);
    vector retPos = getPointAtUV(u,v);
    addpoint(geoself(),retPos);
}
View Code

 <4>Color Define:

(1)ARGB:uint32_t,也就是单位为uint8_t ,共4个,a ,r ,g ,b    0xFF FF FF FF (255,255,255,255)

//  uint32_t c;

A:(uint8_t)   ( (c & 0xFF 00 00 00) >>24)
R:(uint8_t)   ( (c & 0x00 FF 00 00) >>16)
G:(uint8_t)   ( (c & 0x00 FF 00 00) >>8)
B:(uint8_t)   ( (c & 0x00 00 00 FF) >>0)

 (2)从uint8_t r,g,b,a转换到uint32_t,用位和求回去

((uint32_t)a<<24) | ((uint32_t)r<<16) | ((uint32_t)g<<8) | ((uint32_t)b<<0)

(2)float color:sixteen bytes:

struct color{float a, float r,float g,float b}

 转换成ARGB(uint32_t)颜色也简单.

color fc = {1.0f,0.5f,0.0f,1.0f};
uint8_t r
= (uint8_t) (floorf(fc.r*255.0f)) uint8_t g = (uint8_t) (floorf(fc.g*255.0f)) uint8_t b = (uint8_t) (floorf(fc.b*255.0f)) uint8_t a = (uint8_t) (floorf(fc.a*255.0f))

=========================Rasterization==================================================

<1>Line:

画斜线没用到斜率方程,直接用的线性差值。

 DrawApi.h

#ifndef DRAWAPI_H
#define DRAWAPI_H

#include <QImage>
#include "LineSegment.h"
#include <glm/glm.hpp>
#include <iostream>
#include "MathUtility.h"
using namespace TopVertex;
class DrawApi
{
public:
    template <typename T = glm::vec3>
    static void drawLine(QImage &image ,LineSegment<T> &line,const glm::vec3 &color)
    {

        auto &sp = line.startPoint();
        auto &ep = line.endPoint();
        float m  = line.getSlope();

        if(line.getType() == LineSegment<T>::HORIZON)
        {
            std::cout << "write horizon line
";
            auto y = sp[1];
            for(int x=sp[0] ; x <= ep[0]; x++)
            {
                image.setPixel(x,y,qRgb(color[0],color[1],color[2]));
            }
            return;
        }
        if(line.getType() == LineSegment<T>::VERTICAL)
        {
            std::cout << "write verticle line
";
            auto x = sp[0];
            auto y0 = sp[1];
            auto y1 = ep[1];
            if(y0 < y1)
            {
                for(int y=y0;y<=y1;y++)
                {
                    image.setPixel(x,y,qRgb(color[0],color[1],color[2]));
                }
            }
            else
            {
                for(int y=y1;y<=y0;y++)
                {
                    image.setPixel(x,y,qRgb(color[0],color[1],color[2]));
                }
            }
            return;
        }
        if(line.getType() == LineSegment<T>::NORMAL)
        {
            std::cout << "write normal line
";
            int startRow = 0;
            int endRow   = 0;

            if(sp[1] < ep[1])
            {
                startRow = sp[1];
                endRow   = ep[1];
            }
            else
            {
                startRow = ep[1];
                endRow   = sp[1];
            }
            for(int r = startRow;r<=endRow;r++)
            {
                auto bias = GLY_MATH::fit<float>(r,startRow,endRow,0.1f,1.0f);
                auto pos  = GLY_MATH::linearInterpolation(sp,ep,bias);
                image.setPixel(pos[0],pos[1],qRgb(color[0],color[1],color[2]));
            }
            return;
        }

    }
};








#endif // DRAWAPI_H
View Code

LineSegment.h

#ifndef LINESEGMENT_H
#define LINESEGMENT_H
#include <algorithm>
#include <cmath>
#include <string>
#include <iostream>
#include <glm/glm.hpp>
template <typename T>
class LineSegment
{
public:
    typedef T value_type;
    enum TYPE{VERTICAL,HORIZON,NORMAL};
    LineSegment(T startPoint,T endPoint):
        mStartPoint(startPoint),mEndPoint(endPoint)
    {
        // LINE PROPERTY
        evalLineProperty();
        // LINE PROPERTY
    }
    LineSegment()=default;
    void setPoints(const T &startPoint , const T &endPoint)
    {
        mStartPoint = startPoint;
        mEndPoint = endPoint;
        evalLineProperty();
    }
    inline T & operator[](int i)
    {
        if(i == 0)
        {
            return mStartPoint;
        }
        else if(i == 1)
        {
            return mEndPoint;
        }
        else
        {
            throw std::string("Can't get point over 2
").c_str();
        }

    }
    TYPE getType();
    T &startPoint();
    T &endPoint();
    T startPoint()const;
    T endPoint()const;
    float getSlope()const;

    template <typename T2,typename T3>
    inline T2 intersect(const LineSegment<T3> &Line)
    {
        auto st_y = Line.startPoint()[1];  // get line y value
        auto it_x = (st_y - startPoint()[1] + startPoint()[0]*getSlope())/getSlope(); // y slope function get x pos
        return T2(it_x,st_y);
    }



private:
    void evalLineProperty()
    {


        auto x0 = mStartPoint[0];
        auto x1 = mEndPoint[0];

        if(x0 > x1)
        {
            swap(mStartPoint,mEndPoint);
        }

        x0 = mStartPoint[0];
        x1 = mEndPoint[0];
        auto y0 = mStartPoint[1];
        auto y1 = mEndPoint[1];

        if(fabs(y1-y0) <= 0.0000001f)    // horizon line slope = 0
        {
            mSlope = 0.0f;
            mLineType = HORIZON;
        }
        else if(fabs(x1-x0) <= 0.000001f) // verticle line slope = 0
        {
            mSlope = 0.0f;
            mLineType = VERTICAL;
        }
        else                              // slope !=0
        {
            mSlope = (y1 - y0) / (x1-x0);
            mLineType = NORMAL;
        }
    }

    T mStartPoint;
    T mEndPoint;
    TYPE mLineType;
    float mSlope;
};


template<typename T>
typename LineSegment<T>::TYPE LineSegment<T>::getType()
{
    return mLineType;
}

template<typename T>
float LineSegment<T>::getSlope() const
{
    return mSlope;
}

template<typename T>
T &LineSegment<T>::startPoint()
{
    return mStartPoint;
}

template<typename T>
T &LineSegment<T>::endPoint()
{
    return mEndPoint;
}

template<typename T>
T LineSegment<T>::startPoint()const
{
    return mStartPoint;
}

template<typename T>
T LineSegment<T>::endPoint()const
{
    return mEndPoint;
}



// ostream
inline std::ostream& operator<<(std::ostream &os,LineSegment<glm::vec3> line)
{
    os << "Line start points:" << line.startPoint()[0] << " " <<line.startPoint()[1] << " "<<line.startPoint()[2]
       << " | "
       << "end:" << line.endPoint()[0]<< " "<< line.endPoint()[1] << " "<< line.endPoint()[2] ;
    return os;
}

inline std::ostream& operator<<(std::ostream &os,LineSegment<glm::vec2> line)
{
    os << "Line start points:" << line.startPoint()[0] << " " <<line.startPoint()[1] << "|"
              << "end:" << line.endPoint()[0]<< " "<< line.endPoint()[1] ;
    return os;
}





#endif // LINESEGMENT_H
View Code

MathUtility.h

#ifndef MATHUTILITY_H
#define MATHUTILITY_H


#include <string>
#include <vector>
#include <iostream>
#include <sstream>
using namespace std;

namespace TopVertex
{
    class GLY_MATH
    {
    public:

        template<typename T>
        static T linearInterpolation(T val1 , T val2,float bias)
        {
            return val1*(1-bias) + val2*bias;
        }

        template<typename T>
        static T min(T a, T b) {
            if (a > b) {
                return b;
            } else {
                return a;
            }
        }

        template<typename T>
        static T max(T a, T b) {
            if (a > b) {
                return a;
            } else {
                return b;
            }
        }

        template<typename T>
        static bool zero_compare(T a, double tol = 0.00001) {
            return a >= -tol && a <= tol;
        }

        // DO NOT USE THIS FIT TO FIT VECTOR VALUE
        template<typename T>
        static T fit(T var, T omin, T omax, T nmin, T nmax) {
            T d = omax - omin;
            if (zero_compare(d)) {
                return (nmin + nmax) * 0.5;
            }
            if (omin < omax) {
                if (var < omin) return nmin;
                if (var > omax) return nmax;
            } else {
                if (var < omax) return nmax;
                if (var > omin) return nmin;
            }
            return nmin + (nmax - nmin) * (var - omin) / d;
        }

        //return -1 to 1
        template<typename T>
        static T fit_negate(T var, T omin, T omax) {
            return fit(var, omin, omax, -1.0, 1.0);
        }


        //string split
        static std::vector<std::string> split_string(std::string &inputString, char &split_char) {
            std::stringstream ss(inputString);
            std::string sub_str;
            std::vector<std::string> sp_strPath;
            sp_strPath.clear();
            while (getline(ss, sub_str, split_char)) {
                sp_strPath.push_back(sub_str);
            }
            return sp_strPath;
        }

        //value to string
        template<typename T>
        // T must be a value int/float/double
        static std::string value_to_str(T &value) {
            std::ostringstream os;
            os << value;
            return os.str();
        }


        static int wang_inthash(int key) {
            // From http://www.concentric.net/~Ttwang/tech/inthash.htm
            key += ~(key << 16);
            key ^= (key >> 5);
            key += (key << 3);
            key ^= (key >> 13);
            key += ~(key << 9);
            key ^= (key >> 17);
            return key;
        }

        static int fastRandomInt(int seed) {
            int nseed = seed * 1664525+0XFFFFFFF;
            return wang_inthash(nseed);
        }

        static float fastRandom01(int seed)
        {
            return float(fastRandomInt(seed) % 1000000) / 1000000.0f;
        }

    };
}







#endif // MATHUTILITY_H
View Code

Renderer.h

#ifndef RENDERER_H
#define RENDERER_H

#include <QImage>
#include <iostream>
#include <glm/glm.hpp>



using namespace std;





class Renderer
{
public:
    Renderer();
    void render();
};

#endif // RENDERER_H
View Code

Renderer.cpp

#include "Renderer.h"
#include "DrawApi.h"


Renderer::Renderer()
{

}

void Renderer::render()
{

    QImage image(512,512,QImage::Format_RGB32);
    image.fill(Qt::gray);
    glm::vec3 p0(150,20,0);
    glm::vec3 p1(50,100,0);
    glm::vec3 p2(250,150,0);

    //  write horizon line
    glm::vec3 p3(400,50,0);
    glm::vec3 p4(50,50,0);
    auto hline1 = LineSegment<glm::vec3>(p3,p4);
    DrawApi::drawLine(image,hline1,glm::vec3(255,255,0));


    // write verticle line
    glm::vec3 p5(100,10,0);
    glm::vec3 p6(100,500,0);
    auto hline2 = LineSegment<glm::vec3>(p5,p6);
    DrawApi::drawLine(image,hline2,glm::vec3(255,0,0));


    // write normal line
    glm::vec3 p7(50,10,0);
    glm::vec3 p8(300,500,0);
    auto hline3 = LineSegment<glm::vec3>(p8,p7);
    DrawApi::drawLine(image,hline3,glm::vec3(0,0,255));


    image.save("c:/Raster.jpg",0,100);
    return ;
}
View Code

main.cpp

auto render =  Renderer();
render.render();
View Code

 

 以上的方法不过还是垃圾,因为还是循环像素row。对于以上的方法如果不考虑计算成本,直接暴力法循环row,

然后判断pixelPos是不是在triangle里面。是就给他画出来。

 最好的方法:

 

 线求交:

 2,矩阵大法:

计算 :

rotate:

 Scale:

 

 translate:

 

 

得到的XF = 1*x + 0*y + 1*tx = x + tx;

得到的YF = 0*x + 1*y + 1*ty = y + ty;

总体带x,y,w

 3d:

 

 Orthographic Matrix:

 

Perspective Matrix

 Viewport Transform:

Raster Pipeline:

 

..

原文地址:https://www.cnblogs.com/gearslogy/p/7615992.html