计算机图形学 11:沿管线定位一张错误图像
立方体的位置、轮廓与阴影都正常,一个原本背光的侧面却出现了棋盘。检查最终颜色只能知道结果变了,无法立即判断是纹理、法线、光方向还是颜色编码出了问题。把同一个可见样本分别画成深度、法线和UV,能缩小排查范围;再用数值检查验证阶段之间的关系,才能确认原因。 本篇复用第10篇的地面、立方体、相机与光源,不再复制一套渲染器。正确路径输出四张诊断图,错误路径只在照明时混用局部法线与世界光方向。几何、纹理查询和阴影比较全部相同,因此图像差异有一个明确来源。 中间结果需要有明确含义 当前累计管线先变换顶点,在齐次空间裁剪,随后除w、映射视口、判断覆盖并比较深度。通过测试的样本保存局部位置、面法线和对象编号。着色阶段据此求UV、查询纹理与阴影,在线性域计算明暗,最后编码为sRGB。 这些阶段对应常见图形管线的变换、光栅化、逐样本着色与可见性职责。但这里的执行次序和数据结构属于CPU教学实现,不描述GPU一定采用的内部调度,也没有实现全部可编程阶段。 test_scene.hpp从第10篇提取原有场景提交代码,仍是地面两片、盒子十二片三角形。shadow_check.cpp与新增的pipelin...
计算机图形学 10:光源看不见的地方怎样变暗
地面没有条纹纹理,渲染结果却出现整齐的明暗带。增大一个深度偏移参数后,条纹消失;继续增大,立方体明明贴着地面,阴影却与底边分开。前一种是错误自阴影,后一种是偏移过大造成的漏影。 本篇固定几何、相机、光源和分辨率,只改变偏移。除了三张实际图像,还用独立射线与盒相交判断地面是否真的被遮挡,分别统计“错误变暗”和“错误受光”,不把看起来干净的图直接认定为正确。 从光源再做一次可见性判断 第06篇从相机出发,为每个像素保存最近表面的深度。阴影映射把同一思路用于光源:第一遍从光源观察场景,保存最近表面的光源深度;第二遍从相机观察可见表面,将每个表面位置投回光源空间,与第一遍比较。 一个表面可能被相机看见,却被另一块几何挡住光源。因此相机深度测试和阴影比较各自回答不同问题,不能复用相机深度值直接判阴影。 设接收点在光源NDC中的深度为z,阴影图在对应位置保存D。沿用近处0、远处1的约定,若z>D,接收点比光源看见的最近表面更远,应被遮挡。加入接收点偏移b后,当前判断为: shadow=[z−b>D].\text{shadow}=[z-b>D]. shadow=[z−b&g...
计算机图形学 09:法线怎样决定明暗
把模型横向拉长两倍,轮廓变化正确,高光却可能出现在错误位置。顶点位置和法线若都乘同一个缩放矩阵,程序不会报错,但法线已经不再垂直于表面。 本篇先用点积定位这个问题,再用同一个32三角形曲面比较平面与平滑着色。几何、覆盖与光源不变,只改变着色法线;所有颜色仍在线性域计算,最后沿用第04篇的sRGB输出。 法线保存的是垂直关系 三角形顶点为p0,p1,p2p_0,p_1,p_2p0,p1,p2时,两条边e1=p1−p0e_1=p_1-p_0e1=p1−p0、e2=p2−p0e_2=p_2-p_0e2=p2−p0位于表面内。非退化三角形的单位几何法线为: ng=e1×e2∥e1×e2∥.n_g=\frac{e_1\times e_2}{\|e_1\times e_2\|}. ng=∥e1×e2∥e1×e2. 交换顶点绕序会改变叉积符号。零面积三角形没有唯一的面方向,本系列仍拒绝对零向量归一化,不通过更换分母掩盖退化几何。 顶点上还可以存一组用于着色的法线。它们可以来自原始光滑曲面,也可以由相邻面按明确权重平均。几何法线描述三角形本身,着色法线描述希望使用...
计算机图形学 08:怎样减少锯齿与纹理闪烁
斜边变得平滑以后,地板上的细棋盘仍可能随着相机移动而闪烁。这两种现象都涉及采样,但需要平均的对象不同:轮廓处要估计像素有多少面积被图元覆盖;图元内部则要估计一个像素对应的纹理区域里有哪些颜色。 第07篇已经修正透视UV插值。本篇继续区分“采样位置正确”与“采样区域充分”,用两个互相独立的CPU实验验证覆盖采样和纹理预滤波。它们采用明确的规则网格,不代表某块GPU的实际多采样布局。 一个像素需要的是区域信息 先选盒式像素滤波器,把像素看成单位正方形。对黑色背景上的白色图元,理想线性颜色等于图元与像素相交的面积,范围为[0,1]。若恰好覆盖四分之一,颜色应为0.25,再经过sRGB编码用于显示。 在像素中心只问一次“是否在三角形内”,只能得到0或1。沿斜边移动时,这个判断会突然翻转。增加覆盖样本可以得到更多中间值,但有限点集仍是面积的近似,不等于精确积分。 本实验的64×64视口中,白色区域在直线y=0.375x+8.25y=0.375x+8.25y=0.375x+8.25上方,屏幕Y仍向下。它由两个三角形组成,四角为(0,0)、(64,0)、(64,32.25)、(0,8.25)...
计算机图形学 07:为什么贴图会扭曲
把一张棋盘贴到倾斜平面上,外轮廓已经投影成梯形,内部格线却在三角形对角线处折弯。问题可能不在图片,也不在投影矩阵,而在投影之后仍然用屏幕重心坐标直接平均UV。 本篇用两个三角形表示同一个平面,保持几何、相机、覆盖规则和棋盘采样方式不变,只切换UV插值。除了两张结果图,还通过射线与平面相交独立求出UV,避免用同一个插值公式验证自身。 UV描述的是表面上的位置 纹理坐标u、v是从表面位置到二维纹理域的映射。本实验把平面四角分别标为(0,0)、(1,0)、(1,1)、(0,1)。u增加表示从左向右,v增加表示从平面近边走向远边。它们不是屏幕像素坐标,也不是相机距离。 棋盘在UV域分成8×8格,取floor(8u)与floor(8v),两者之和的奇偶决定灰度。端点1钳制到最后一格,防止访问第8号格。这是明确选定的点采样和边界规则;本篇没有读取外部纹理图片,也没有双线性过滤。 两种灰度在线性域取0.04与0.8,最后通过第04篇的sRGB函数编码一次。因而本次比较不会混入“一个版本在线性域、另一个版本在显示码值域”的颜色差异。 屏幕中点不一定对应空间中点 先看一条边。空间端点A、B的w分...
计算机图形学 06:哪个表面可见
一个三角形的顶点越过近裁面,整个三角形就消失;两个物体只交换绘制顺序,前后关系就颠倒。这是两种不同的可见性错误。前者需要裁剪保留仍在视锥内的几何,后者需要在每个样本处比较深度。 第02篇只能判断一个点是否合法,第05篇只能判断一个屏幕样本是否属于三角形。本篇将两者连接起来:先在齐次空间裁剪,再投影、光栅化和比较深度。实验使用128×128图像,颜色仍按第04篇的线性RGB约定编码输出。 裁掉的是外侧部分,不是整个图元 沿用相机朝−Z、列向量、NDC深度[0,1]的约定。裁剪坐标记为(x,y,z,w)(x,y,z,w)(x,y,z,w),可见体满足: w+x≥0,w−x≥0,w+y≥0,w−y≥0,z≥0,w−z≥0.w+x\ge0,\quad w-x\ge0,\quad w+y\ge0,\quad w-y\ge0,\quad z\ge0,\quad w-z\ge0. w+x≥0,w−x≥0,w+y≥0,w−y≥0,z≥0,w−z≥0. 六个不等式分别表示左、右、下、上、近、远平面。它们在四个分量上都是线性的,因此可以直接求边与平面的交点。这里的z已经是投影矩阵输出,不能再把相机...
计算机图形学 05:哪些样本属于三角形
两个三角形拼成矩形,沿对角线出现一条黑缝,未必是顶点没有对齐。如果两边都拒绝恰好落在共享边上的样本,就会漏画;如果两边都接受,则会重复覆盖。几何边界相同,还需要一致的边界归属规则。 本篇在32×32图像中放置一个24×24矩形,用两个三角形组成它。程序不仅输出图像,还逐样本累计归属次数,分别复现重复、漏算和正确覆盖。相机与深度暂不参与,输入已经是屏幕空间位置。 三条有向边描述一个三角形 沿用图像左上原点、X向右、Y向下。顶点a、b确定一条有向边,定义二维边函数: E(a,b,p)=(bx−ax)(py−ay)−(by−ay)(px−ax).E(a,b,p)=(b_x-a_x)(p_y-a_y)-(b_y-a_y)(p_x-a_x). E(a,b,p)=(bx−ax)(py−ay)−(by−ay)(px−ax). 它是两个二维向量的叉积标量。p落在直线上时为零,落在两侧时符号相反,绝对值等于对应平行四边形面积。交换a、b会反号,因此公式与顶点绕序必须同时固定。 对于三个顶点 v0,v1,v2v_0,v_1,v_2v0,v1,v2,令 A=E(v0,v1,v2...
计算机图形学 04:为什么平均颜色会发暗
把黑色与白色各取一半,直接平均8位码值得到128;在线性光域平均后再编码,却得到约188。同样写着“平均”,结果差了60个码值。原因不是加法写错,而是参与加法的数字代表了不同的量。 第03篇为了观察采样,直接把教学信号映成灰度码值。本篇开始固定后续渲染器的颜色约定:光照累加与过滤使用线性浮点值,sRGB编码留到显示输出;高动态范围压缩另行处理,并保留压缩前数据。 RGB三个分量还没有说明全部含义 一个三元组只有在原色、白点和传递函数确定后,才具有明确的颜色含义。相同的RGB数字放在不同颜色空间里,不保证对应相同颜色。这里选择sRGB原色与D65白点,先区分它的编码值与线性光值,不扩展广色域转换。 设c为归一化的sRGB编码分量,L为对应线性分量,当前接口限定二者输入在[0,1]内。c不是与光能成正比的量。将c翻倍,通常不会让对应的L恰好翻倍。 这也不表示L直接以坎德拉或辐射亮度单位计量。当前L是相对于约定白色的线性数值,能够在同一工作空间中做线性组合;要得到绝对物理单位,还需曝光、光源与显示标定。后续讲物理光照时会再次明确这些单位。 sRGB不是一个简单的2.2次方 本实验依据...
计算机图形学 03:为什么细线会断裂、棋盘格会闪烁
一条细线移动很小的距离后突然消失,不一定是几何数据丢了。如果采样点恰好都落在线外,图像数组中就没有任何数值能证明那条线存在。随后放大图片,也无法从缺失的样本中恢复它。 本篇把二维图像暂时简化成一维明暗信号,在完全相同的信号上改变采样率与预滤波。输出包括浮点 CSV、原始 PPM 和实际转换的 PNG。显示放大与信号采样分开处理,避免把浏览器缩放造成的视觉变化当作算法改善。 从连续函数到有限数组 取归一化区间 0≤x<10\le x<10≤x<1,定义: g(x)=12+12cos(2π⋅12x).g(x)=\frac12+\frac12\cos(2\pi\cdot12x). g(x)=21+21cos(2π⋅12x). 它在一个单位区间内有12个周期,数值范围为[0,1]。x是归一化位置,12的单位是“每单位区间的周期数”。这里的数值是教学灰度信号,尚不宣称是经过标定的物理亮度;第04篇再区分线性颜色与显示编码。 N个均匀样本分别取在区间中心: ci=i+1/2N,i=0,…,N−1.c_i=\frac{i+1/2}{N},\qquad i=0,\ldo...
计算机图形学 02:相机怎样把空间投到屏幕
一个点的屏幕横坐标算错,可能来自模型位置、相机姿态、投影矩阵、透视除法或视口映射。只打印最终像素,无法区分这些原因。本篇让一个点逐站输出坐标,并用近平面、远平面与相机后方的样本检查边界。 实验沿用第 01 篇的列向量与右手系。相机朝自身的 −Z 方向观察;透视投影后的 NDC 横纵坐标范围是 [-1,1],深度范围是 [0,1]。这些是本系列的具体选择。不同教材可以使用不同约定,矩阵必须随之变化。 从物体位置到相机坐标 模型空间用于描述物体自身的几何,例如一个三角形相对于其建模原点的位置。模型矩阵 M 把它放进世界空间。观察矩阵 V 再将世界坐标表达为相机坐标,投影矩阵 P 产生裁剪坐标: pclip=PVMpmodel.p_{clip}=PVMp_{model}. pclip=PVMpmodel. 这不是三个任意可交换的操作。按照第 01 篇的列向量约定,最右侧的 M 先作用;写成 MVP 会改变含义。实现中分别保存中间结果,验收通过后才有理由预先合并矩阵。 设模型点为 (1,0,0,1)(1,0,0,1)(1,0,0,1),模型矩阵将物体沿 Z 平移 −1,世界坐标便是...











