当前位置: 首页 > news >正文

Computer Graphics From Scratch - Chapter 8

系列文章目录

简介: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) 纯绿色。我们将为每个顶点分配一个实值 hhh,表示顶点处颜色的强度hhh[0.0,1.0][0.0, 1.0][0.01.0] 范围内,其中 0.00.00.0 表示最暗的阴影(即黑色),1.01.01.0 表示尽可能亮的阴影(即原始颜色),而不是白色!

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


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

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

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

让我们从三角形的边缘开始。考虑边缘 ABABAB。我们知道hAh_AhAhBh_BhB。在 ABABAB 的中点 MMM 处会发生什么?

由于我们希望强度从 AAABBB 平滑变化,因此 hMh_MhM 的值必须在 hAh_AhAhBh_BhB之间。既然 MMMABABAB 的中间,为什么不选择 hMh_MhMhAh_AhAhBh_BhB的中间,也就是它们的平均值呢?

更正式地说,我们有一个函数 h=f(P)h = f(P)h=f(P),它给每个点 PPP 一个强度值 hhh; 我们知道它在 AAABBBfff 分别的值,h(A)=hAh(A) = h_A h(A)=hAh(B)=hBh(B)= h_Bh(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)
我们知道这个函数在三角形顶点的值,我们想计算沿其边的 xxx 值。
我们可以以非常相似的方式沿三角形的边 计算 hhh 的值,使用 以 yyy 作为自变量的插值(我们知道)和 hhh 作为因变量(我们想要的值):


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)

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

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

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


// Concatenate the short sides
remove_last(x01)
x012 = x01 + x12remove_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 = x02h_left = h02x_right = x012h_right = h012
} 
else 
{x_left = x012h_left = h012x_right = x02h_right = h02
}

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


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

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

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

因变量为hhh,其对应的 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 <= y2if 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 edgesx01 = 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 sidesremove_last(x01)x012 = x01 + x12remove_last(h01)h012 = h01 + h12// Determine which is left and which is rightm = floor(x012.length / 2)if x02[m] < x012[m] {x_left = x02h_left = h02x_right = x012h_right = h012} else {x_left = x012h_left = h012x_right = x02h_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)中开发的函数非常相似。
在水平循环之前❷, 我们以类似的方式操纵 xxx 向量和 hhh 向量,如上所述。
在循环中,我们有一个额外的调用Interpolate❸ 以计算当前水平中每个像素的hhh值。
最后,在内部循环中,我们使用hhh的插值来计算每个像素的颜色❹.

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

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


四、Summary - 概括

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

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

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

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

.

http://www.lryc.cn/news/10062.html

相关文章:

  • 金三银四”不香了?
  • 个人开源PCB开发板列表汇总
  • 2023美国大学生数学建模竞赛(美赛)思路代码
  • makefile简易教程
  • 快速入门nginx
  • 甘特图:项目管理工具,轻松简化工作流程
  • 刷题专练之翻转题练习
  • 【Java】死锁
  • DS图—图的最短路径(无框架)迪杰斯特拉算法
  • 【笔记】数据异常检测与修复总结
  • 算法笔记(七)—— 图的相关知识及算法
  • ssh配置互信时错误解决方法
  • SQL69 返回产品并且按照价格排序
  • vue+elementUI 实现设置还款日字母弹窗组件
  • 【JavaGuide面试总结】Redis篇·中
  • Python:每日一题之全球变暖(BFS连通性判断)
  • VUE -- defineExpose
  • 实用调试技巧【下篇】
  • 【数据结构期末例题】
  • 管理物理和快照备数据库(Physical and Snapshot Standby Databases)
  • 双目立体视觉:SAD算法
  • 海外问卷调查答题技巧,纯干货分享,新手小白看过来
  • 【NGINX入门指北】Nginx Web 架构实验
  • rtt-nano移植
  • cnn+transformer
  • Python fileinput模块:逐行读取多个文件
  • Vue3路由传参
  • 用户管理——认证功能JWT和Session
  • hashlib — 加密哈希算法
  • 四喜临门选股预警源码指标