栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

tinyrender game101笔记

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

tinyrender game101笔记

draw line

给定(x0,y0) (x1,y1)两个点,画出一条直线。 首先通过交换x,y轴使得变化较快的那个轴变为x轴,再交换x0,x1使得x1永远大于x0。令dx=x1-x0;dy=y1-y0;
从(x0,y0)开始,x轴每增加一个像素,因为y轴变化较慢所以增加的值dy/dx小于1, 把增加的值累积起来用变量error记录,每当error>0.5就令y的值增加1,同时error的值减去1. 但是这样做的缺点是需要使用0.5和dy/dx两个浮点数,所以直接两者同时乘以2dx。

void line(int x0, int y0,int x1, int y1, TGAImage &image,TGAColor color){
    bool steep=false;
    if(abs(y1-y0)>abs(x1-x0)){
        steep=true;
        std::swap(x0,y0);
        std::swap(x1,y1);
    }
    if(x1dx){
            y+=dy>0?1:-1;
            error-=2*dx;
        }
        if(steep){
            image.set(y,x, color);
        }else{
            image.set(x,y,color);
        }
    }
}
  • 模型导入
    .obj文件的每一行要么是点,要么表示一个面

    v 0.296 -0.070 0.953 v -0.319 -0.065 0.946

    f 1193/1240/1193 1180/1227/1180 1179/1226/1179

    第一行表示一个点,使用归一化坐标,第二行表示一由第1193,1180和1179个点组成的面。

triangle

思路,求出三角形的bbox后,需要判断其中的每一个点是否在三角形内。 这里用到了重心坐标的概念,即如果P在三角形ABC内,则存在三个分别放在ABC点上的质量,使得P成为三角形的重心。
即P点满足
u P A → + v P B → + ( 1 − u − v ) P C → = 0 u overrightarrow{P A}+v overrightarrow{P B}+(1-u-v) overrightarrow{PC}=0 uPA +vPB +(1−u−v)PC =0
现在给定P点需要求出u,v,(1-u-v),如果其中一个值小于0则说明P不在三角形内。
整理得
{ [ u v 1 ] [ A B → x A C → x P A → x ] = 0 [ u v 1 ] [ A B → y A C → y P A → y ] = 0 left{begin{array}{l} {left[begin{array}{lll} u & v & 1 end{array}right]} & {left[begin{array}{c} overrightarrow{A B}_{x} \ overrightarrow{A C}_{x} \ overrightarrow{P A}_{x} end{array}right]=0} \ {left[begin{array}{lll} u & v & 1 end{array}right]} & {left[begin{array}{c} overrightarrow{A B}_{y} \ overrightarrow{A C}_{y} \ overrightarrow{P A}_{y} end{array}right]=0} end{array}right. ⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧​[u​v​1​][u​v​1​]​⎣⎢⎢⎡​AB x​AC x​PA x​​⎦⎥⎥⎤​=0⎣⎢⎢⎡​AB y​AC y​PA y​​⎦⎥⎥⎤​=0​

可以看出(u,v,1)和两个向量(ABx,ACx,PAx) and (ABy,ACy,PAy)正交,所以可以先求出两个向量的叉乘,然后除以z轴的值,得到(u,v,1),注意这里叉乘结果的z值可能为0,这种情况可以直接归为P不在三角形内。

Vec3f barycentric(Vec2i* pts,Vec2i P){
    Vec3i v1(pts[1].x-pts[0].x,pts[2].x-pts[0].x,pts[0].x-P.x);
    Vec3i v2(pts[1].y-pts[0].y,pts[2].y-pts[0].y,pts[0].y-P.y);
    auto u=v1.cross(v2);
    if(u.z==0){
        return Vec3f(-1,1,1);
    }else{
        Vec3f v=u;
        return Vec3f(v.x/v.z,v.y/v.z,1.0f-(v.x+v.y)/v.z);
    }
}

void triangle(Vec2i* pts, TGAImage& image,TGAColor color){
    Vec2i boxmax(0,0);
    Vec2i boxmin(image.get_width()-1,image.get_height()-1);
    for(int i=0;i<3;i++){
        for(int j=0;j<2;j++){
            if(pts[i].raw[j]>boxmax.raw[j]){
                boxmax.raw[j]=pts[i].raw[j];
            }
            if(pts[i].raw[j]=0 && b.y>=0&& b.z>=0){
                image.set(x,y,color);
            }
        }
    }
}
Zbuffer

上面的实现的triangle没有考虑深度的问题,即使三角形A的z值比三角形B大,但是渲染时还是可能被B给覆盖,解决方法是利用一个zbuffer[image_width*imag_height],来缓存渲染过程中,三角形上每个点的z值,这样渲染结束后,zbuffer中每一个z值都是所有对应点中最大的。 三角形上某点z值的计算过程是以该点的重心坐标为权重,乘以三角形三个顶点的z坐标。

void triangle(Vec3i* pts, float* z_buffer, TGAImage& image,TGAColor color){
    Vec2i boxmax(0,0);
    Vec2i boxmin(image.get_width()-1,image.get_height()-1);
    for(int i=0;i<3;i++){
        for(int j=0;j<2;j++){
            if(pts[i].raw[j]>boxmax.raw[j]){
                boxmax.raw[j]=pts[i].raw[j];
            }
            if(pts[i].raw[j]=0 && b.y>=0&& b.z>=0){
                float z=0;
                for(int i=0;i<3;i++){
                    z+=b.raw[i]*pts[i].z;
                }
                int index=P.y*image.get_width()+P.x;
                if(z_buffer[index]
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/289939.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号