[TinyRenderer] Chapter1 p3 Line

news/2024/9/30 23:27:44

(注:本小节不是对划线算法事无巨细的证明,如果你需要更加系统的学习,请跳转至文末的参考部分)
如果你是一名曾经学习过图形学基础的学生,那么你一定对画线算法稔熟于心,中点划线算法,Bresenham算法。其中,现代光栅化器中使用最多的就是Bresenham算法,它以去除了除法和浮点运算而著称。

但如果现在让你看下面的这段代码,你能否把它和Bresenham算法联系起来呢?

void Segment::draw(const Point2i begin, const Point2i end, const RGBPixel& color, BMPImage& image)
{int x0 = begin.x;int y0 = begin.y;int x1 = end.x;int y1 = end.y;int dx = abs(x1 - x0);int dy = abs(y1 - y0);int sx = (x0 < x1) ? 1 : -1;int sy = (y0 < y1) ? 1 : -1;int error = dx - dy;while (true){image.set(x0, y0, color);if (x0 == x1 && y0 == y1)break;int e2 = 2 * error;if (e2 > -dy){error -= dy;x0 += sx;}if (e2 < dx){error += dx;y0 += sy;}}
}

如果你可以顺利地说出每行代码的含义,那么恭喜你,你已经完全掌握了Bresenham算法,你可以跳过本小节,进行下一小节的学习。
但如果你还有所异或,那么相信我,看完本小节,你必定有所收获。

本节目标

在光栅化渲染器中加入画线功能

分析

首先,让我们考虑一种再简单不过的场景,你从一个初始点begin出发,从左向右,沿着斜率在0~1的直线到达end

这是一个Bresenham算法的基础场景,在这个场景中,我们可以通过中点划线算法知道存在一个判断依据,用于确定在每次遍历时y的值是否需要改变。

这个值的变化由直线方程给出,在这里我们仅使用beginend给出。(具体论证请翻阅参考)
还记得我们的假设场景么?在这个场景下:

assert: (x0 < x1) and ((y1 – y0) < (x1 – x0))
δx = x1 – x0;
δy = y1 – y0;
incrE = 2 * δy;
incrNE = 2 * (δy - δx);
d = 2 * δy – δx;

保持x递增的同时,判断y是否改变。
d<0 -> d += incrE
else -> d += incrNE and ++y

现在我们得到了在斜率为0~1的时候的Bresenham算法,且begin.x<end.x
那么对于其他场景呢?

  1. begin.x > end.x
  2. slope < 0 or slope > 1
  3. 平行于坐标轴的方向

解决方案:

  1. 只需要将begin和end两个点做一下交换即可
  2. slope < 0 or slope > 1
    1. slope < 0只需要对begin和end加上符号,最后set的时候再变回来即可
    2. slope > 1这个更加简单,只需要交换xy即可
  3. 平行于轴体的方向只需要特判一下进行处理,而且这样效率更高
实现

实际上TinyRenderer的实现思路也是如此:

void line(int x0, int y0, int x1, int y1, TGAImage &image, TGAColor color) { bool steep = false; if (std::abs(x0-x1)<std::abs(y0-y1)) { std::swap(x0, y0); std::swap(x1, y1); steep = true; } if (x0>x1) { std::swap(x0, x1); std::swap(y0, y1); } int dx = x1-x0; int dy = y1-y0; int derror2 = std::abs(dy)*2; int error2 = 0; int y = y0; for (int x=x0; x<=x1; x++) { if (steep) { image.set(y, x, color); } else { image.set(x, y, color); } error2 += derror2; if (error2 > dx) { y += (y1>y0?1:-1); error2 -= dx*2; } } 
} 

而这种实现还可以转化成下面的这种写法,就是上面我们提到的方法,更加优雅,不需要特判条件,使用统一变量。

实现

void Segment::draw(const Point2i begin, const Point2i end, const RGBPixel& color, BMPImage& image)
{int x0 = begin.x;int y0 = begin.y;int x1 = end.x;int y1 = end.y;int dx = abs(x1 - x0);int dy = abs(y1 - y0);// 决定决策会落在坐标系四个方位中的哪一个int sx = (x0 < x1) ? 1 : -1;int sy = (y0 < y1) ? 1 : -1;// 维护error,用于决策下一个点的位置int error = dx - dy;while (true){image.set(x0, y0, color);if (x0 == x1 && y0 == y1)break;int e2 = 2 * error;// 每次迭代会进行两次决策,共同决定下一个点是在一个角落中的哪一个// 如果在x轴上的误差较大if (e2 > -dy){error -= dy;x0 += sx;}// 如果在y轴上的误差较大if (e2 < dx){error += dx;y0 += sy;}}
}

误差判别的依据,B,C点

最后记得,反转一下y轴,因为bmp图像中的y轴方向是向下的

结果

Reference

  1. # Lesson 1: Bresenham’s Line Drawing Algorithm
  2. Bresenham.pdf
  3. # wiki Bresenham's line algorithm

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hjln.cn/news/45089.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

3个月搞定计算机二级C语言!高效刷题系列进行中

前言 大家好,我是梁国庆。 计算机二级应该是每一位大学生的必修课,相信很多同学的大学flag中都会有它的身影。 我在大学里也不止一次的想要考计算机二级office,但由于种种原因,备考了几次都不了了之。 这一次我想换个目标! 备考计算机二级C语言 今天山东省考试院发布了关于…

讯飞有一个可以根据描述文本自动生成PPT的AI接口,有趣

文档:https://www.xfyun.cn/doc/spark/PPTGeneration.html 价格方面提供了免费1000点的额度,生成一次是10点,正好100次,如果要购买的话最低要购买1344元的,没有按量付费的模式,个人小开发者可买不起。 让我们跑起来玩玩,官方提供了python的sdk,下载到本地: 不想下载sd…

RSS 解析:全球内容分发的利器及使用技巧

RSS(Really Simple Syndication)是一种 XML 格式,用于网站内容的聚合和分发,让用户能快速浏览和跟踪更新。RSS 文档结构包括 `<channel>` 和 `<item>` 元素,允许内容创作者分享标题、链接和描述。通过 RSS,用户可以定制新闻源,过滤不相关信息,提高效率。RS…

2024.6.10漏洞探针

探针(扫描器) 1、nmap漏洞库,根目录下scripts中调用2、Goby(红队版) 直接输入ip扫描资产,漏洞库较少; 3、Nessus 本地安装: 下载安装普通版;注册获取验证码; 注册用户 nessus,nessus123 漏洞利用 1、工具框架 metasploit和searchsploit 忍者系统可以一键使用msf;2、…

6.12Web应用漏洞发现探针利用

已知CMS、开发框架、 思路: 各个页面查看数据包(地址信息),查看框架,上fofa关键字搜索(查看其框架信息如thinkhphp),利用检测工具测试漏洞情况; 网站根目录下的robots.txt文件信息; /data/admin/ver.txt 网站升级时间; 常见SQL注入、登录、逻辑越权支付逻辑绕过思路:…

6.13API接口服务类漏洞探针

ip地址解析:www.x.x.x.com, 对应网站目录为d:/wwwroot/xiaodi/ 而127.x.x.x,对应网站目录为d:/wwwroot/,可能存在网站备份文件zip,所以ip网址端口都的扫描; 协议端弱口令爆破: 超级弱口令检查工具;端口服务安全问题(用于无思路时) 思路:利用探针对端口探测后,对口令安全…

Modbus协议转Profinet协议网关与气体监测系统配置案例

Modbus协议和Profinet协议作为工业领域常见的两种通讯协议,各自具有一定的特点和应用范围。Modbus转Profinet网关(XD-MDPN100/300)在工业自动化控制系统中,可以将Modbus协议转换为Profinet协议,以实现不同设备之间的数据交换和通讯。本文将结合Modbus协议转Profinet协议网…

网站_域名_DNS_端口_web访问过程

网站基本概念 服务器:能够提供服务器的机器,取决于机器上所安装的服务软件 web服务器:提供web服务(网站访问),需要安装web服务软件,Apache,tomcat,iis等域名 (Domain Name) 方便人记的 DNS (Domain Name System) 域名系统, 一个分布式数据库,让ip和域名相互映射…