计算机图形学 21:光怎样经过多次反射
白色地板靠近红墙时,为什么会带上红色?只计算“地板直接看见白灯”的路径,地板仍是灰白的。要产生墙面的颜色影响,还需要计算灯先照到墙、墙再照到地板的贡献。 本篇把第 18 篇的最近交点、第 19 篇的反射积分和第 20 篇的随机估计接起来。场景只有一个开口盒子,除顶灯外都是 Lambert 表面。颜色渗透用墙色对照与线性数值检查,路径终止则另有可手算的控制实验。 从相机方向逐段估计入射光 相机射线先找到表面 x。它向相机发出的光包含自身发射,也包含来自其他方向的反射。对反射积分抽取一个方向 ω,沿该方向再求最近交点 y,就把 x 的未知入射光转成了 y 向 x 的出射光。 这条计算路径从相机出发,与通常描述的“光从灯传播到相机”方向相反。它是一种积分求解顺序,不是宣称真实光子从相机射出。每次只延长一个随机方向,形成一条路径;重复多条路径再平均。 用 β 保存到当前顶点之前的累计权重,初值为 RGB 三个通道的 1。采到下一段方向后更新: βnew=βfr(x,ωi,ωo)∣n⋅ωi∣pω(ωi).\beta_{new}=\beta\frac{f_r(x,\omega_i,\ome...
计算机图形学 20:随机样本怎样估计积分
第 19 篇把半球划成规则小格,累加入射光。若场景里多一次反射,积分又增加一组方向;继续铺规则网格,组合数量会迅速增长。蒙特卡洛方法改用随机样本估计积分,但随机位置不是任意挑选的:样本来自哪里、以什么概率出现,决定了每个样本应有多大权重。 先用一个答案已知的问题检查这个关系:在 [0,1] 上积分 x²,答案为 1/3。同一份程序比较均匀采样、重要性采样,以及故意遗漏半个区间的错误策略。第三种结果波动很小,却始终离正确答案很远。 概率密度不是一个点的概率 连续随机变量 X 的概率密度为 p(x) 时,落进区间 [a,b] 的概率是该区间内 p 的积分。单个点通常具有零概率;不能把 p(x)=2 解释为某点出现的概率是 200%。例如 [0,1/2] 上恒定密度 2,在其他位置为零,总概率仍为 1。 这也与第 03 篇的规则采样不同。中心点序列由网格确定,没有为每个位置分配抽样概率;把确定性求积中的步长随意改名为 PDF,并不能直接得到同一组统计结论。 设目标积分为 I=∫f(x)dx,随机样本按 p 产生。对于 p 非零的位置,把样本贡献写成 Y=f(X)/p(X),就有: E...
计算机图形学 19:表面颜色从哪里来
把材质反射率设为 0.6,像素就应该写成 0.6 吗?同一块表面放在不同照明下,显然不会保持相同的显示颜色。问题在于材质参数、到达表面的光、离开表面的光和屏幕码值分别代表不同的量。 本篇选择一个能手算的场景:不发光、不透射的漫反射平面,法线上方一个圆锥内有恒定入射辐亮度,其余方向为零。先算物理量,再用确定性求积核对,最后才把结果压缩到灰度图。它是已知入射条件下的局部积分,不是通用间接光照求解器。 功率落到面积上,还缺一个方向 辐射通量 Φ 表示单位时间传递的辐射能量,单位 W。把入射通量按表面积分配,得到辐照度 E=dΦ/dA,单位 W/m²。它回答一小块表面总共收到多少功率,没有保留这些光分别来自哪些方向。 方向分布由辐亮度 L 描述。通过面积 dA、沿某个小立体角 dω 传播的功率满足: dΦ=Lcosθ dA dω.d\Phi=L\cos\theta\,dA\,d\omega. dΦ=LcosθdAdω. θ 是该方向与表面法线的夹角,面积投影为 cosθ dA。L 的单位为 W/(m²·sr),sr 是立体角单位球面度。一个方向范围在单位球面上覆盖的面积就是其立体角,...
计算机图形学 18:怎样减少求交次数
第 17 篇每条射线询问场景中的全部图元。128 个球、16,384 条射线,就要执行 2,097,152 次球体求交,即使每条射线附近实际上只有一个球。 本篇给图元建立包围盒层级。验收不只观察渲染图,还逐射线比较最近交点,分别计数包围盒测试、节点访问和精确图元求交。分离球体与完全重叠球体采用同一份实现,观察结构何时有效、何时只增加开销。 一个盒子怎样排除整组图元 如果一个盒子包含组内全部几何,射线没有经过盒子,就不可能碰到组内几何。这个单向推理是加速结构的基础。射线经过盒子却不一定碰到表面,因为盒内允许有空白。 第 16 篇已有轴对齐包围盒 Bounds。球的盒为 center±radius;三角形的盒对三个顶点逐轴取最小、最大。父盒合并子盒的 low 和 high,不需要重新访问孩子内部的所有顶点。 保守包围意味着可以多保留候选,但不能漏掉真实几何。盒子过大主要损害速度,盒子过小会改变渲染结果。这里不使用包围盒命中代替球或三角形命中,它只决定是否继续调用第 17 篇的精确求交函数。 对于 X 轴,盒内要求 lowₓ≤oₓ+t dₓ≤highₓ。当 dₓ 非零时,除法得到进入...
计算机图形学 17:一条光线先碰到什么
同一个像素前方有两个球,应该显示哪一个?光栅器把三角形投到像素上,再比较深度;射线方法从像素反推一个观察方向,分别询问场景中的几何,最后保留沿这个方向最先到达的表面。 两种方法都在解决可见性。本篇只生成物体编号图和法线图,不计算反射光、阴影或多次散射。颜色连续变化可以来自法线可视化,不能据此把图像称为真实感光照结果。 从像素中心到世界射线 射线写成 r(t)=o+td。o 是起点,d 是方向,t 是参数。d 若为单位向量,t 才等于沿射线走过的距离。将 d 放大两倍,同一个交点的 t 就减半,几何位置不变。 沿用第 02 篇相机约定:右手坐标系,相机向局部 −Z 观察,屏幕 y 向下。对于宽 W、高 H 的图像,在像素 (x,y) 中心取样,垂直视场角为 θ,像平面上的横纵坐标为: sx=(2x+0.5W−1)WHtanθ2,sy=(1−2y+0.5H)tanθ2.s_x=\left(2\frac{x+0.5}{W}-1\right)\frac WH\tan\frac\theta2, \qquad s_y=\left(1-2\frac{y+0.5}{H}\right)\ta...
计算机图形学 16:多个模型怎样组成场景
把两个模型挂到同一个父节点下,旋转父节点后,模型画面跟着转了,碰撞或裁剪使用的包围盒却还停在原处。渲染结果和空间查询各自使用一套变换缓存时,很容易出现这种分歧。 本篇建立一个可从文件导入的三节点场景:一个分组节点与两个共享网格的实例。更换父节点变换后,同时核对世界顶点、实例包围盒与整个子树的包围盒;非法层级与缺失资源也必须明确失败。 资源和实例分别保存什么 第 12 篇的 Mesh 保存模型自身的顶点和三角形连接。把同一个方形放到两处,不需要复制它的顶点数组。两个场景节点只需引用同一个网格编号,各自保存局部变换。 资源表中的网格位于模型空间;场景节点记录“这份资源以什么变换出现在场景里”。改变一个实例的位置,不应改写资源表坐标,否则其他引用者也会改变。当前求值接口把资源表作为常量引用,只输出世界矩阵与包围盒。 分组节点可以没有网格。它仍然定义局部坐标系,其变换影响后代。实验中节点 0 就是这样的分组,节点 1 和 2 都引用资源 0。资源 0 只有四个顶点、两个三角形,但画面里出现两个实例。 节点关系采用森林:每个节点只有一个 parent 整数,−1 表示根。这种数据表示本身...
计算机图形学 15:怎样减少面数又控制形变
一个 64 面的封闭模型,能否只保留 8 面?删除任意三角形会留下孔洞;直接合并最近的两个顶点,也可能改变连接或翻转表面。减少面数需要同时回答三个问题:合并哪条边、把合并点放在哪里、怎样判断结果还能使用。 本篇复用第 12 篇的网格和半边结构,实现受约束的边折叠。排序代价采用二次误差度量(QEM),验收另算真实三角形距离与固定视角轮廓。三项数值回答不同的问题,不能用一个低代价数值替代全部检查。 折叠一条边会删除什么 对内部边 (a,b),把两个端点合并到新位置 x。包含整条边的两个三角形因顶点重合而删除;其余引用 b 的三角形改为引用 a,再从顶点数组删掉 b 并修正编号。 合法的闭合三角网格边折叠通常使 V 减 1、E 减 3、F 减 2,因此欧拉示性数 V−E+F 不变。但数量相符不能保证操作合法:两个原本不同的面可能变成相同索引集合,顶点一环也可能不再是单一扇区。 一个反例是四面体。折叠任一边会删除它相邻的两个面,余下两个面却落到同一组三个顶点上。若只检查“公共邻点有两个”,这个反例会通过;完整的邻接条件还涉及边等单纯形,不能缩成邻点数量比较。 collapse_clos...
计算机图形学 14:粗网格怎样变成曲面
把四面体每个面切成四个小三角形,它会变圆吗?如果所有新增点仍在原来的面上,答案是否定的:面数增加,几何外形却没有改变。曲面细分还必须更新顶点位置,而且更新规则要区分内部和边界。 本篇复用第 12 篇的索引网格与半边邻接,主实现选择三角网格 Loop 细分。单三角形检验边界,闭合四面体检验内部规则,两组都实际执行多次更新。第 13 篇的曲线说明了加权平均可以改变形状;这里还要保证相邻面共享同一个新增顶点。 一轮细分有两件事 对旧三角形 (a,b,c),先在三条边上各生成一个新顶点,编号记为 ab、bc、ca。四个子面依次写为 (a,ab,ca)、(b,bc,ab)、(c,ca,bc)、(ab,bc,ca)。这个顺序保留旧面的绕序。 拓扑拆分之外,还有位置更新。旧顶点 a 的新位置不是旧坐标的别名;边点 ab 也不一定是边的中点。所有位置都根据旧层网格计算,之后一起成为新层的顶点数组。 若一边遍历一边改写旧坐标,稍后访问的顶点就会混合新旧两层数据。输出不仅偏离规则,还可能依赖遍历顺序。subdivision.hpp 的 loop_step 复制位置数组用于输出,所有加权输入都明确读...
计算机图形学 13:少量控制点怎样生成曲线
把一条拱形曲线左侧的控制点提高,右半段会不会改变?如果两段曲线在同一点接上,而且切线方向相同,沿曲线运动的物体会不会突然变速?这两个问题分别涉及控制点的影响范围和参数的含义,仅凭曲线看起来平滑无法回答。 本篇用四个控制点构造三次 Bézier 曲线,实际生成移动前后的图像,再用独立多项式检查求值结果。坐标沿用第 01 篇的向量约定,图像沿用累计 C++17 工程;这里的二维曲线嵌在 z=0 平面,不经过透视相机。 从线性插值到曲线 两点之间的线性插值是 L(t)=(1−t)A+tB,t∈[0,1]。四个点 P₀、P₁、P₂、P₃ 可以先两两插值,得到三个点;再对这三个点插值,得到两个点;最后再插值一次,得到曲线上对应 t 的一个点。 用 Pᵢ⁽ʳ⁾ 表示第 r 层的结果,de Casteljau 递推为: Pi(0)=Pi,Pi(r)=(1−t)Pi(r−1)+tPi+1(r−1),B(t)=P0(n).P_i^{(0)}=P_i,\qquad P_i^{(r)}=(1-t)P_i^{(r-1)}+tP_{i+1}^{(r-1)},\qquad B(t)=P_0^{(n)}. P...
计算机图形学 12:三角网格怎样保存邻接
两个三角形组成一个方形,渲染时只需依次提交顶点。若要把方形对角线换成另一条,就必须知道这条边属于哪两个面、两侧相对的顶点是谁,以及修改后每个顶点周围是否仍连成一片。图像数组和三角形列表本身没有直接回答这些问题。 本篇在累计光栅器前增加网格邻接结构。一个方形用于检查边界与翻边,一个四面体用于检查闭合一环,非法输入用于验证拒绝路径。图像展示连接变化,连接表与数值不变量负责验收。 索引相同才表示同一个顶点 索引网格保存一份位置数组和一份三角形索引数组。方形四点为: p0=(−1,−1,−3),p1=(1,−1,−3),p2=(1,1,−3),p3=(−1,1,−3).p_0=(-1,-1,-3),\quad p_1=(1,-1,-3),\quad p_2=(1,1,-3),\quad p_3=(-1,1,-3). p0=(−1,−1,−3),p1=(1,−1,−3),p2=(1,1,−3),p3=(−1,1,−3). 两个面分别为(0,1,2)、(0,2,3)。共有四个顶点、五条无向边、两个面。边(0,2)属于两面,其余四条边各属于一面。 邻接按索引识别,而不是比较坐标是否近...











