Computer Graphics From Scratch - Chapter 7

news2025/1/17 23:12:27

系列文章目录

简介:Computer Graphics From Scratch-《从零开始的计算机图形学》简介
第一章: Computer Graphics From Scratch - Chapter 1 介绍性概念
第二章:Computer Graphics From Scratch - Chapter 2 基本光线追踪
第三章:Computer Graphics From Scratch - Chapter 3 光照
第四章:Computer Graphics From Scratch - Chapter 4 阴影和反射
第五章:Computer Graphics From Scratch - Chapter 5 扩展光线追踪
第六章:Computer Graphics From Scratch - Chapter 6 线条


Chapter 7

  • 系列文章目录
  • Filled Triangle - 实心三角形
  • 一、Drawing Wireframe Triangles - 绘制线框三角形
  • 二、Drawing Filled Triangles - 绘制填充三角形
  • 三、Summary - 概括


Filled Triangle - 实心三角形

In the previous chapter, we took our first steps toward drawing simple shapes—namely, straight line segments—using only PutPixel and an algorithm based on simple math. In this chapter, we’ll reuse some of the math to draw something more interesting: a filled triangle.

在上一章中,我们迈出了绘制简单形状的第一步,即仅使用PutPixel和基于简单数学的算法绘制直线段。在本章中,我们将重用一些数学来绘制更有趣的东西:实心三角形


一、Drawing Wireframe Triangles - 绘制线框三角形

我们可以使用DrawLine方法绘制三角形的轮廓:

DrawWireframeTriangle (P0, P1, P2, color) 
{
	DrawLine(P0, P1, color);
	DrawLine(P1, P2, color);
	DrawLine(P2, P0, color);
}

这种轮廓被称为线框,因为它看起来像一个由线条组成的三角形,如图7-1所示:
Figure 7-1: A wireframe triangle with vertices (–200,–250), (200,50), and (20,250)

图 7-1: A wireframe triangle with vertices (–200,–250), (200,50), and (20,250)

这是一个充满希望的开始!接下来我们将探讨如何用颜色填充三角形。


二、Drawing Filled Triangles - 绘制填充三角形

我们想画一个三角形,用我们选择的颜色填充。正如计算机图形学中的情况一样,解决这个问题的方法不止一种。我们将通过将填充三角形视为水平线段的集合来绘制填充三角形,这些线段在绘制时看起来像三角形。图7-2显示了如果我们可以看到单独的线段,这样的三角形会是什么样子。
在这里插入图片描述

图7-2:使用水平线段绘制填充三角形

以下是我们想要做的事情的一个非常粗略的近似值:

for each horizontal line y between the triangle's top and bottom
	compute x_left and x_right for this y
	DrawLine(x_left, y, x_right, y)

让我们从“三角形的顶部和底部之间”开始。三角形由其三个顶点 P 0 P_0 P0 P 1 P_1 P1 P 2 P_2 P2定义。如果 我们 通过增加 y y y值对这些点进行排序,使得 y 0 ≤ y 1 ≤ y 2 y_0≤y_1≤y_2 y0y1y2,则三角形所占的y值范围为 [ y 0 , y 2 ] [y_0,y_2] [y0y2]

if y1 < y0 { swap(P1, P0) }
if y2 < y0 { swap(P2, P0) }
if y2 < y1 { swap(P2, P1) }

通过这种方式对顶点进行排序可以使事情变得更简单:在这样做之后,我们可以始终假设 P 0 P_0 P0是三角形的最低点, P 2 P_2 P2是最高点,因此我们不必处理所有可能的排序。

接下来我们要计算x_leftx_right数组。这有点棘手,因为三角形有三条边,而不是两条。然而,仅考虑 y y y的值,我们总是有从 P 0 P_0 P0 P 2 P_2 P2的“高”边,以及从 P 0 P_0 P0 P 1 P_1 P1 P 1 P_1 P1 P 2 P_2 P2的两个“短”边。

y 0 = y 1 y_0=y_1 y0=y1 y 1 = y 2 y_1=y_2 y1=y2 时有一种特殊情况,即三角形的一条边是水平的。当这种情况发生时,另两个边的高度相同,因此任何一个都可以被认为是“高”边。我们应该选择右边还是左边?幸运的是,这并不重要;
该算法将支持从左到右和从右到左的水平线,因此我们可以坚持我们的定义,即“高”侧是从 P 0 P_0 P0 P 2 P_2 P2的一侧。

x_right的值将来自高边或连接短边;x_left的值将来自另一个集合。我们将从计算三条边的 x x x值开始。因为我们将绘制水平线段,所以我们希望每个 y y y值都有一个 x x x值;这意味着我们可以使用插值计算这些值,其中 y y y为自变量, x x x为因变量:

x01 = Interpolate(y0, x0, y1, x1)
x12 = Interpolate(y1, x1, y2, x2)
x02 = Interpolate(y0, x0, y2, x2)

其中一侧的 x x x值为 x 02 x02 x02;另一侧的值来自 x 01 x01 x01 x 12 x12 x12的串联。注意,有一个重复的 x 01 x01 x01 x 12 x12 x12中的值: y 1 y1 y1 x x x值既是 x 01 x01 x01的最后一个值,也是 x 12 x12 x12的第一个值。我们只需要去掉其中一个(我们任意选择 x 01 x01 x01的最后一个值),然后连接数组:

remove_last(x01)
x012 = x01 + x12

我们最终得到了 x 02 x02 x02 x 012 x012 x012,我们需要确定哪个是x_left,哪个是x_right。要做到这一点,我们可以选择任意一条水平线(例如,中间的一条),并比较 x 02 x02 x02 x 012 x012 x012中的 x x x值:如果 x 02 x02 x02中的 x x x小于 x 012 x012 x012中,那么我们知道 x 02 x02 x02必须是x_left;否则,它必须是x_right

m = floor(x02.length / 2)
if x02[m] < x012[m] {
	x_left = x02
	x_right = x012
} else {
	x_left = x012
	x_right = x02
}

现在我们有了绘制水平段所需的所有数据。我们可以用DrawLine来做这个。然而,DrawLine是一个非常通用的函数,在这种情况下,我们总是从左到右绘制水平线,因此使用简单的for循环更有效。这也让我们对我们绘制的每个像素有了更多的“控制”,这在接下来的章节中特别有用。


示例7-1显示了完整的DrawFilledTriangle。

DrawFilledTriangle (P0, P1, P2, color) 
{// Sort the points so that y0 <= y1 <= y2
	if y1 < y0 { swap(P1, P0) }
	if y2 < y0 { swap(P2, P0) }
	if y2 < y1 { swap(P2, P1) }// Compute the x coordinates of the triangle edges
	x01 = Interpolate(y0, x0, y1, x1)
	x12 = Interpolate(y1, x1, y2, x2)
	x02 = Interpolate(y0, x0, y2, x2)// Concatenate the short sides
	remove_last(x01)
	x012 = x01 + x12

	❹ // Determine which is left and which is right
	m = floor(x012.length / 2)
	if x02[m] < x012[m]
	{
		x_left = x02
		x_right = x012
	} 
	else 
	{
		x_left = x012
		x_right = x02
	}// Draw the horizontal segments
	for y = y0 to y2 
	{
		for x = x_left[y - y0] to x_right[y - y0] 
		{
			canvas.PutPixel(x, y, color)
		}
	}
}

示例7-1:绘制填充三角形的函数


让我们看看这里发生了什么。函数接收三个顶点,以任意顺序将三角形作为参数。我们的算法需要他们按从下到上的顺序排列,所以我们这样排序❶.

接下来,我们计算三条边的每个y值的x值❷, 并连接阵列;

从两个“短”的侧面❸. 然后我们计算出哪个是x_left,哪个是x_right❹.

最后,对于顶部和在三角形的底部,我们得到它的左x坐标和右x坐标,并绘制逐像素分段❺.

结果如图7-3所示;出于验证目的,我们调用DrawFilledTriangle,然后使用相同坐标但不同颜色的DrawWireframeTriangle。无论何时都要验证结果,这是查找代码中错误的一种非常有效的方法!


在这里插入图片描述

图7-3:带线框边缘的实心三角形,用于验证


您可以在https://gabrielgambetta.com/cgfs/triangle-demo;

您可能会注意到三角形的黑色轮廓与绿色内部区域不完全匹配;这在三角形的右下边缘尤其明显。这是因为DrawLine正在计算该边的 y = f ( x ) y=f(x) y=f(x),但是

DrawTriangle正在计算 x = f ( y ) x=f(y) x=f(y),由于四舍五入,这可能会产生稍微不同的结果。这是一种我们愿意接受的近似误差,以使我们的渲染算法更快。


三、Summary - 概括

在本章中,我们开发了一种在画布上绘制填充三角形的算法。这是绘制线段的一个步骤。我们还学会了将三角形视为一组可以单独使用的水平线段。

在下一章中,我们将扩展数学和算法,以绘制一个填充有颜色渐变的三角形;算法背后的数学和推理将是本书中开发的其他功能的关键。


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

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

相关文章

新生儿喝奶后不要马上放回床上睡觉,为宝宝健康着想,先做1件事

看到一个问题&#xff0c;题主问&#xff0c;新生儿喝完奶能马上放回床上睡觉吗&#xff1f;可以吗&#xff1f;也许每个人都认为照顾新生儿是一件非常简单的事情&#xff0c;因为新生儿几乎整天都在睡觉。当他们饿的时候&#xff0c;他们会让他们的宝宝吃牛奶。他们吃饱了就要…

博客搭建教程(一):静态博客 GitHub + Gridea

同步blog文章 注册一个 Github 账号并创建仓库 注册Github账号 如果你没有 Github 的账号&#xff0c;那么可以进入 官网 开始注册&#xff08;注意一下用户名的填写&#xff0c;如果不使用自定义域名&#xff0c;用户名将会是你的 Github 分配给你的域名&#xff0c;例如你的…

D. George and Interesting Graph(最大匹配)

Problem - 387D - Codeforces 乔治喜欢图表。最重要的是&#xff0c;他喜欢有趣的图。我们将假设一个有向图是有趣的&#xff0c;如果它符合以下标准。 该图不包含任何多弧。 有一个顶点v&#xff08;我们称她为中心&#xff09;&#xff0c;这样对于图形u的任何顶点&#xff…

信息网络传播视听节目服务单位的设立与经营

一、行业准入 &#xff08;一&#xff09;网络视听业务准入范围 利用公共互联网&#xff08;含移动互联网&#xff09;向计算机、手机用户提供视听节目服务&#xff08;不含交互式网络电视&#xff08;IPTV&#xff09;、互联网电视、专网手机电视业务&#xff09;业务的&…

几个小设置让 mac 更好用

今天在 youtube 上看到一个视频[1]&#xff0c;讲新 mac 到手后一定要做的几个设置&#xff0c;有几个之前我不知道的小设置&#xff0c;非常好用&#xff0c;看完马上就用上了。一些常用的就不列了&#xff0c;比如说设置点按、三指拖拽&#xff0c;不知道的可以去搜索了解&am…

【Python数据可视化】使用geoplotlib绘制地理空间数据

geoplotlib前言一、安装geoplotlib包二、读取csv数据使用1.点密度可视化2.直方图3. Voronoi图总结前言 ❤️❤️希望大家能多多点赞。❤️❤️ 需要数据集的可以评论。 Geoplotlib 是地理空间数据可视化的开源Python库&#xff0c;包含了大量的地理空间可视化操作&#xff0c…

131. 分割回文串

131. 分割回文串 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正着读和反着读都一样的字符串。 示例 1&#xff1a; 输入&#xff1a;s “aab” 输出&#xff1a;[[“a”,“a”,“b”]…

青少年等级考试【Python通关干货】(二级)

青少年等级考试【Python通关干货】(二级)1.列表类型的概念 2.序列的通用操作 3.可变序列及列表的通用操作 4.列表的特有操作 5.元组类型的概念与操作

激活学习:一种挑战反向传播的生物启发算法

激活学习(activation learning)是一种生物启发的简单本地学习规则构建的前向无监督通用模型&#xff0c;它的核心是构建多层神经网络使得网络输出激活强度能反映输入的相对概率大小。并且&#xff0c;它在一些任务上达到并超过反向传播的表现。激活学习的概念由山东大学教授周洪…

C++11标准模板(STL)- 算法(std::adjacent_difference)

定义于头文件 <algorithm> 算法库提供大量用途的函数&#xff08;例如查找、排序、计数、操作&#xff09;&#xff0c;它们在元素范围上操作。注意范围定义为 [first, last) &#xff0c;其中 last 指代要查询或修改的最后元素的后一个元素。 计算范围内各相邻元素之间…

MyBatis 配置文件解析

MyBatis 的核心配置文件是 mybatis-config.xml。注意配置文件中节点的顺序有要求&#xff0c;必须按照下面的顺序填写节点信息&#xff1a; (properties,settings,typeAliases,typeHandlers,objectFactory,objectWrapperFactory,reflectorFactory,plugins,environments,databa…

Odoo丨如何在Odoo中修改HTML编辑工具栏?

文章目录一、前言二、渲染原理三、修改方法一、前言 在odoo中&#xff0c;当我们在页面上使用Html类型或者html的小组件的时候&#xff0c;页面渲染成如下格式&#xff0c;供用户编辑⬇ 上方有一些工具栏如背景颜色&#xff0c;字体颜色&#xff0c;字体大小&#xff0c;插入表…

【Linux04-进程概念下】不愧是操作系统,优美的设计!

前言 上期的分享让我们知道进程大概的模样&#xff0c;本期一样重要&#xff0c;能学到操作系统设计的优美&#xff0c;体会到前辈们的智慧。 #环境变量 是什么 OS提供&#xff0c;往往有特殊功能的全局变量&#xff08;/etc/profile.d是设置环境变量的目录&#xff09; [b…

React 入门:实战案例 Github搜索_axios发送请求

文章目录快速搭建 API 服务器在 Search 组件中实现 Axios 发送请求在 App 组件中管理 List 组件的用户列表状态在 List 组件中更新渲染用户列表数据优化完善完整源码最终效果&#xff1a;快速搭建 API 服务器 根据下面步骤来操作&#xff0c;就可以快速搭建一个符合本案例使用…

明年跨境电商外贸的新增量在哪里?来自专家的2个判断

明年跨境电商外贸的新增量在哪里&#xff1f;来自专家的2个判断2022年&#xff0c;外贸大环境不容易&#xff0c;外贸人也不容易。自2021年9月以来&#xff0c;海运费飙涨&#xff0c;库容一降再降。大批的货品滞留库存&#xff0c;部分卖家只好硬着头皮扛下来了高额的仓储费&a…

最佳实践 | 帮助您的游戏在斋月期间大放异彩

作者 / Google Play 游戏业务发展经理 Nimrod Levy世界各地的开发者都发现&#xff0c;在斋月期间&#xff0c;许多庆祝这个神圣月份的国家/地区的用户都会比平时更活跃。这是一个吸引穆斯林玩家的宝贵机会。斋月是伊斯兰历的第 9 个月。世界各地的穆斯林都会在这个月进行斋戒、…

RV1126笔记二十二:pt->onnx->rknn模型转换

若该文为原创文章,转载请注明原文出处。 一、介绍 实现的目标是,把RK提供的yolov5s.pt转成onnx,在把onnx转成rknn,部署到RV1126上面。 这里不训练模型,所以只要搭建好环境后,就可以直接运行测试。 这里只是提供一种转换的方法,有其他的方式,可以自行测试。 由于不…

立根铸魂 崛起数智时代 操作系统产业峰会2022即将启幕!

如今&#xff0c;数字经济成为全球经济增长的主引擎。基础软件是数字经济发展的基础&#xff0c;是制造强国、网络强国、数字中国建设的关键支撑。而基础软件中的操作系统&#xff0c;作为数字基础设施的底座&#xff0c;已经成为推动产业数字化、智能化发展的核心力量。 2022…

Codeforces Round #840 (Div. 2)

A. Absolute Maximization 题目链接&#xff1a;Problem - A - Codeforces 样例输入&#xff1a; 4 3 1 0 1 4 5 5 5 5 5 1 2 3 4 5 7 20 85 100 41 76 49 36样例输入&#xff1a; 1 0 7 125题意&#xff1a;给定一个长度为n的数组a[]&#xff0c;我们可以对这个数组中的数进…

VueJs中setup的使用(上)

前言在写组合式API代码时,首先接触到的是setup这个函数,在一些项目代码里,你会看到有的直接在script标签上添加setup标识,有的在选项式API方式里,以setup()函数,配置选项的方式出现在单文件组件里什么时候用setup()函数方式,什么时候不用,对于有些新手同学,有些困惑,以及它的一…