Computer Graphics From Scratch - Chapter 8

news2024/9/29 18:41:09

系列文章目录

简介: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 线条
第七章:Computer Graphics From Scratch - Chapter 7 实心三角形


Chapter 8

  • 系列文章目录
  • Shaded Triangle - 阴影三角形
  • 一、Defining Our Problem - 定义我们的问题
  • 二、Computing Edge Shading - 计算边缘着色
  • 三、Computing Interior Shading - 计算内部着色
  • 四、Summary - 概括


Shaded Triangle - 阴影三角形

In the previous chapter, we developed an algorithm to draw a triangle filled with a solid color. Our goal for this chapter is to draw a shaded triangle—that is, a triangle filled with a color gradient.

在上一章中,我们开发了一种算法来绘制填充有纯色的三角形。本章的目标是绘制一个带阴影的三角形,即一个填充有颜色渐变的三角形


一、Defining Our Problem - 定义我们的问题

我们想用单一颜色的不同色调填充三角形。它会看起来如图8-1. shades 色调

在这里插入图片描述

图8-1:一个着色的三角形


我们需要一个更正式的定义来定义我们试图绘制的内容。我们有一个基色C:例如, ( 0 , 255 , 0 ) (0,255,0) (02550) 纯绿色。我们将为每个顶点分配一个实值 h h h,表示顶点处颜色的强度 h h h [ 0.0 , 1.0 ] [0.0, 1.0] [0.01.0] 范围内,其中 0.0 0.0 0.0 表示最暗的阴影(即黑色), 1.0 1.0 1.0 表示尽可能亮的阴影(即原始颜色),而不是白色!

为了计算给定三角形 C 的基色和该像素 h h h 处的强度的像素的确切色调,我们将逐通道相乘
C h = ( R C ⋅ h , G C ⋅ h , B C ⋅ h ) C_h = (R_C · h, G_C · h, B_C · h) Ch=RChGChBCh
因此, h = 0.0 h = 0.0 h=0.0 产生纯黑色, h = 1.0 h = 1.0 h=1.0 产生原始颜色 C, h = 0.5 h = 0.5 h=0.5 产生的颜色是原始颜色的一半亮度。


二、Computing Edge Shading - 计算边缘着色

为了绘制一个带阴影的三角形,我们需要做的就是为三角形的每个像素计算一个 h h h 值,计算相应的颜色阴影,然后绘制像素。

然而,在这一点上,我们只知道三角形顶点的 h h h 值,因为我们选择了它们。我们如何计算三角形其余部分 h h h 值?

让我们从三角形的边缘开始。考虑边缘 A B AB AB。我们知道 h A h_A hA h B h_B hB。在 A B AB AB 的中点 M M M 处会发生什么?

由于我们希望强度从 A A A B B B 平滑变化,因此 h M h_M hM 的值必须在 h A h_A hA h B h_B hB之间。既然 M M M A B AB AB 的中间,为什么不选择 h M h_M hM h A h_A hA h B h_B hB的中间,也就是它们的平均值呢?

更正式地说,我们有一个函数 h = f ( P ) h = f(P) h=f(P),它给每个点 P P P 一个强度值 h h h; 我们知道它在 A A A B B B f f f 分别的值, h ( A ) = h A h(A) = h_A h(A)=hA h ( B ) = h B h(B)= h_B h(B)=hB
我们希望这个函数是平滑的。由于我们对 h = f ( P ) h = f(P) h=f(P)一无所知,因此我们可以选择任何与我们所知的函数兼容的函数,例如线性函数(图8-2)。

在这里插入图片描述

Figure 8-2: A linear function h§, compatible with what we know about h(A) and h(B)


这与前一章的情况非常相似:我们有一个线性函数 x = f ( y ) x = f(y) x=f(y)
我们知道这个函数在三角形顶点的值,我们想计算沿其边的 x x x 值。
我们可以以非常相似的方式沿三角形的边 计算 h h h 的值,使用 以 y y y 作为自变量的插值(我们知道)和 h h h 作为因变量(我们想要的值):


x01 = Interpolate(y0, x0, y1, x1)
h01 = Interpolate(y0, h0, y1, h1)

x12 = Interpolate(y1, x1, y2, x2)
h12 = Interpolate(y1, h1, y2, h2)

x02 = Interpolate(y0, x0, y2, x2)
h02 = Interpolate(y0, h0, y2, h2)

接下来,我们将 x x x 数组连接为**“短”**边,然后确定 x02x012 中的哪一个x_left,哪个x_right。同样,我们可以在这里对 h h h 向量做一些非常相似的事情。

但是,我们将始终使用 x x x 值来确定哪一侧是左边,哪一侧是右边, h h h 值只会“跟随”。
x x x h h h 是屏幕上实际点的属性,因此我们不能自由混合搭配左右两侧的值。

我们可以按如下方式编码:


// Concatenate the short sides
remove_last(x01)
x012 = x01 + x12

remove_last(h01)
h012 = h01 + h12

// Determine which is left and which is right
m = floor(x012.length / 2)
if x02[m] < x012[m] 
{
	x_left = x02
	h_left = h02
	x_right = x012
	h_right = h012
} 
else 
{
	x_left = x012
	h_left = h012
	x_right = x02
	h_right = h02
}

这与上一章(示例 7-1)中代码的相关部分非常相似,只是每次我们使用 x x x 向量做某事时,我们对相应的 h h h 向量执行相同的操作。


三、Computing Interior Shading - 计算内部着色

最后一步是绘制实际的水平 。对于每个细分 ,我们知道 x_leftx_right ,如上一章所述; 现在我们也知道 h_lefth_right 。但这次我们不能只是从左到右迭代并用基色绘制每个像素:我们需要为这个 的每个像素计算 h h h 值。

同样,我们可以假设 h h h x x x 线性变化,并使用插值来计算这些值。在这种情况下,自变量是 x x x,它从我们着色的特定水平 x_left 值变为 x_right 值;

因变量为 h h h,其对应的 x_leftx_right 值为该段的 h_lefth_right


x_left_this_y = x_left[y - y0]
h_left_this_y = h_left[y - y0]

x_right_this_y = x_right[y - y0]
h_right_this_y = h_right[y - y0]

h_segment = Interpolate(x_left_this_y, h_left_this_y,
						x_right_this_y, h_right_this_y)

或者,用更紧凑的方式表示:

h_segment = Interpolate(x_left[y - y0], h_left[y - y0],
						x_right[y - y0], h_right[y - y0])

现在只需计算每个像素的颜色并绘制它!示例 8-1 显示了 DrawShadedTriangle 的完整伪代码。

DrawShadedTriangle (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 and h values of the triangle edges
	x01 = Interpolate(y0, x0, y1, x1)
	h01 = Interpolate(y0, h0, y1, h1)

	x12 = Interpolate(y1, x1, y2, x2)
	h12 = Interpolate(y1, h1, y2, h2)

	x02 = Interpolate(y0, x0, y2, x2)
	h02 = Interpolate(y0, h0, y2, h2)

	// Concatenate the short sides
	remove_last(x01)
	x012 = x01 + x12

	remove_last(h01)
	h012 = h01 + h12

	// Determine which is left and which is right
	m = floor(x012.length / 2)
	if x02[m] < x012[m] 
	{
		x_left = x02
		h_left = h02
		x_right = x012
		h_right = h012
	} 
	else 
	{
		x_left = x012
		h_left = h012
		x_right = x02
		h_right = h02
	}

	// Draw the horizontal segmentsfor y = y0 to y2 
	{
		x_l = x_left[y - y0]
		x_r = x_right[y - y0]
		❸ h_segment = Interpolate(x_l, h_left[y - y0], x_r, h_right[y - y0])
		for x = x_l to x_r 
		{
			❹ shaded_color = color * h_segment[x - x_l]
			canvas.PutPixel(x, y, shaded_color)
		}
	}
}

Listing 8-1: A function for drawing shaded triangles

该函数的伪代码与上一章(示例7-1)中开发的函数非常相似。
在水平循环之前❷, 我们以类似的方式操纵 x x x 向量和 h h h 向量,如上所述。
在循环中,我们有一个额外的调用Interpolate❸ 以计算当前水平中每个像素的 h h h值。
最后,在内部循环中,我们使用 h h h的插值来计算每个像素的颜色❹.

注意,我们对三角形顶点的排序与之前一样❶. 然而,我们现在认为这些顶点及其属性(如强度值 h h h )是一个不可分割的整体;也就是说,交换两个顶点的坐标也必须交换它们的属性。

您可以在以下位置找到此算法的实时实现 https://gabrielgambetta.com/computer-graphics-from-scratch/demos/raster-04.html


四、Summary - 概括

在本章中,我们扩展了上一章中开发的三角形绘制代码,以支持平滑着色的三角形。请注意,我们仍然可以使用它来绘制单色三角形,方法是使用 1.0 作为所有三个顶点的 h h h 值。

这个算法背后的想法实际上比看起来更通用。 h h h 是强度值的事实对算法的“形状”没有影响; 我们只在最后,当我们要调用 PutPixel 时,才为这个值赋予意义。这意味着我们可以使用此算法来计算三角形顶点的任何属性的值,对于三角形的每个像素,只要我们假设该值在屏幕上线性变化。

在接下来的章节中,我们确实会使用这个算法来改善三角形的视觉外观。

然而,在下一章中,我们要绕道而行。掌握了在2D画布上绘制三角形后,我们将把注意力转向三维

.

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

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

相关文章

ts基础入门学习之上篇

1.安装typescript编译器 npm i -g typescript 安装之后使用tsc运行ts文件&#xff0c;然后会编译出对应的js文件&#xff0c;再通过node运行js文件&#xff0c;就能获得打印内容。 ts定义内容 function fn(people, date) {console.log(hello${people},today is ${date}); } fn…

C++模板(一)

文章目录C模板&#xff08;一&#xff09;1. 泛型编程2. 函数模板2.1 函数模板格式2.2 模板原理2.3 模板实例化2.4 模板参数匹配原则3. 类模板3.1 类模板格式3.2 背景3.3 类模板的实例化C模板&#xff08;一&#xff09; 1. 泛型编程 前面我们学到了函数重载这个特性&#xf…

Zabbix“专家坐诊”第181期问答汇总

题一 Q&#xff1a;大佬们&#xff0c;有没有基础的 监控模板 触发器分享下&#xff1f; A&#xff1a;你可以试一下乐维免费版&#xff08;https://forum.lwops.cn/download &#xff09;&#xff0c;里面基本的模板全齐。 问题二 Q &#xff1a;orabbix监控查询SQL执行时…

如何保证数据库和缓存双写一致性?

前言 数据库和缓存&#xff08;比如&#xff1a;redis&#xff09;双写数据一致性问题&#xff0c;是一个跟开发语言无关的公共问题。尤其在高并发的场景下&#xff0c;这个问题变得更加严重。 我很负责的告诉大家&#xff0c;该问题无论在面试&#xff0c;还是工作中遇到的概率…

CAD中怎么旋转光标?CAD旋转光标的方法步骤

CAD中怎么旋转光标&#xff1f;浩辰CAD软件作为一款拥有自主核心技术的CAD平台软件产品&#xff0c;提供了CAD旋转光标命令&#xff0c;本节课程就和小编一起来了解一下浩辰CAD软件中CAD旋转光标的方法步骤吧&#xff01; CAD旋转光标命令启动方式&#xff1a; 1、命令行&…

Redis第三讲

目录 三、Redis03 3.1 Redis持久化之RDB 3.1.1 什么是RDB 3.1.2 备份是如何执行的 3.1.3 Fork 3.1.4 RDB持久化流程 3.1.5 dump.rdb文件 3.1.6 配置rdb文件生成位置 3.1.7 如何触发RDB快照以及保持策略 3.2 Redis持久化之AOF 3.2.1 什么是AOF 3.2.2 AOF持久化流程 …

Java反序列化漏洞——CommonsCollections3链分析

一、原理CC1链中我们是通过调用Runtime.getRuntime.exec()来执行系统命令&#xff0c;而另一个方向我们可以通过TemplatesImpl加载字节码的类&#xff0c;通过调⽤其newTransformer() 方法&#xff0c;即可执⾏这段字节码的类构造器&#xff0c;我们在类构造器中加入恶意代码&a…

【Seata】_01 分布式事务基础知识和常见的解决方案

本地事务 单一的数据库事务&#xff0c;ACID由数据库直接提供 分布式事务 一个服务调用操作两个数据库&#xff1b; 多个服务操作同一个数据库&#xff1b; 多个服务操作多个数据库&#xff1b; 分布式事务无法由数据库保证 Seata 分布式事务解决方案 Seata提供AT/TCC/SAG…

HDMI Audio InfoFrame

Audio InfoFrame 是HDMI Source向Sink传递当前音频流特性的一种InfoFrame。要求是至少每两帧图像就要传输一次Audio InfoFrame。Audio InfoFrame的传输可以是Data Island周期的任何时刻。 HDMI在音频的传输上&#xff0c;packet包的标准是按照IEC60958或者IEC61938来的。 Aud…

使用契约测试得不偿失?试试契约先行开发

契约维护的难题 如今微服务凭借其灵活、易开发、易扩展等优势深入人心&#xff0c;不同服务之间的集成和交互日渐繁多且复杂。这些服务之间交互的方式是多样的&#xff0c;常见的有 HTTP 请求和消息队列。在它们交互的过程中&#xff0c;会有服务的版本演进&#xff0c;交互信…

算法的时间复杂度与空间复杂度

…………………………………………………………………………………………………………………… ………………………………………………………………………加油…………………………………………………………………………. 如何衡量一个算法的好与坏呢&#xff1f;这是本篇的重点…

财报解读:硬件支撑思科增长,云平台何时能突围?

北京时间2023年2月16日&#xff0c;美国网络设备老牌巨头思科公布了其2023财年第二季度财报&#xff0c;业绩超预期。 据思科财报显示&#xff0c;其2023财年Q2实现营收136亿美元&#xff0c;分析师预期为134.3亿美元&#xff1b;同时给出大超预期的业绩指引&#xff0c;思科预…

jetson nano(ubuntu)编译Qt creator

文章目录一.apt安装二.源码编译安装1.Qt Creator源码下载2.相关软件安装cmakeninjallvm/clang3.Qt Creator源码编译一.apt安装 sudo apt-get install qtcreatorapt安装的版本只有4的&#xff0c;版本较低&#xff0c;只有qmake进行项目配置&#xff0c;6版本以上可以使用cmake…

7大体系防作弊,牛客放大招了!严肃笔试客户端上线!

如果问起学生对在线笔试的印象&#xff0c;“不公平”和“不服气”占了半壁江山。学生认为很多企业的在线笔试系统并不完善。原因一&#xff0c;不能有效地规避部分学生的作弊行为&#xff1b;原因二&#xff0c;在线考试系统不稳定&#xff0c;bug频出&#xff0c;导致笔试发挥…

CURL error 60: SSL certificate problem: certificate has expired

项目使用guzzleHttp做的一个接口&#xff0c;报错&#xff1a;certificate has expired 因为在linux centos环境与window环境有所不同&#xff0c;在此记录一下解决过程。 目录 报错提示 原因 解决方式 1.去掉guzzlehttp的验证 2.更新CA证书 总结 报错提示 cURL error 60…

RadZen运行和部署,生成业务web应用程序

RadZen运行和部署,生成业务web应用程序 快速简单地生成业务web应用程序&#xff0c;可视化地构建和启动web程序&#xff0c;而我们为您创建新代码。 从信息开始 连接到数据库。Radzen推断您的信息并生成一个功能完备的web应用程序。支持MSSQL REST服务。 微调 添加页面或编辑生…

人工智能、机器学习和深度学习有哪些区别?

人工智能在如今越来越火&#xff0c;诸多词汇时刻萦绕在我们耳边&#xff1a;人工智能、机器学习、深度学习等。不少人对这些高频词汇的含义及其背后的关系总是似懂非懂、一知半解。为了帮助大家更好地理解人工智能&#xff0c;这篇文章用最简单的语言解释了这些词汇的含义&…

tomcat-container 源码分析

说明 本文基于 tomcat 8.5.x 编写。author blog.jellyfishmix.com / JellyfishMIX - githubLICENSE GPL-2.0 tomcat 的 container 容器 tomcat 由 connector 和 container 两部分组成&#xff0c;connector 接收到请求后&#xff0c;先将请求包装为 request&#xff0c;然后…

六、H5新特性

文章目录一、H5的兼容二、H5新增特性2.1 语义化标签2.2 增强表单2.3 音频、视频一、H5的兼容 支持 HTML5的浏览器包括Firefox(火狐浏览器)&#xff0c;IE9及其更高版本&#xff0c;Chrome(谷歌浏览器)&#xff0c;Safari,Opera等&#xff0c;国内的遨游浏览器&#xff0c;以及…

【Kubernetes 企业项目实战】07、最新一代微服务网格 Istio 入门到企业实战(上)

目录 一、Istio 介绍 1.1 什么是 service mesh 1.2 什么是 Istio 1.2.1 服务注册和发现 1.2.2 服务度量 1.2.3 灰度发布 1.3 Istio 核心特性 1.3.1 断路器 1.3.2 超时 1.3.3 重试 1.3.4 多路由规则 二、架构和原理 2.1 Istio 架构 2.1.1 数据平面由一组以 Sideca…