计算机图形学 25:一次绘制怎样交给 GPU
第 11 篇的软件管线在 CPU 上依次处理顶点、覆盖、深度和颜色。换成 GPU 后,JavaScript 不再逐像素执行这些循环,但仍要明确告诉设备:顶点放在哪里,怎样解释这些字节,运行哪个着色器,结果写到哪张纹理。 先画一个三角形。三个顶点分别携带红、绿、蓝颜色,内部由管线插值。除亲眼检查画面,还读回一个内部像素与一个背景像素,再故意遗漏缓冲用途,观察错误怎样返回。这样可以把“提交了命令”“设备完成了数据写入”和“页面确实出现结果”分开验证。 先运行这一个页面 打开 WebGPU 三角形实验。点击“初始化 / 恢复”,再点击“重绘并读回像素”。页面必须显示彩色三角形及像素检查结果;不支持 WebGPU 时显示原因,不用静态截图替代。 实际验证日期为 2026-09-20。Codex 内嵌浏览器报告 Chrome/153.0.0.0,安全上下文为 true,适配器 vendor 为 apple、architecture 为 metal-3,首选画布格式为 bgra8unorm。设备与描述字段为空,不能从这些空字段推断具体 GPU 型号,也不能把浏览器的兼容性 User-Ag...
计算机图形学 24:怎样判断渲染器算对了
一张噪点减少的图,可能仍然把同一束直接光加了两遍。一张稳定偏暗的图,可能来自截断路径,也可能只是输出时漏了 sRGB 编码。继续增加采样数只能处理其中一部分问题。 本篇用累计渲染器回答一个具体问题:小面积灯照亮盒子时,怎样区分随机误差、参考误差和实现错误?实验保留线性像素,重复运行不同种子,再用解析用例检查几何、材质、采样与颜色输出。图像中的直接光和探针中的完整光传输分别验证,不能互相替代。 先说明图像在估计什么 沿用第 22 篇的小灯盒。灯位于 y=0.99,半边长 0.12,面积 0.0576,朝下发出恒定辐亮度 40。相机在 (0,0,3.2),朝向原点,竖直视场角 0.75 弧度。32×32 个像素都从中心发出主光线;没有像素内抗锯齿采样。漫反射表面只计算一次直接照明,直接可见的灯返回其发射值,背景为零。 这一定义排除了两个容易混淆的目标:本组图不估计像素面积平均值,也不包含墙面之间的间接反射。因此,用带抗锯齿的离线成图或第 21 篇的完整路径图作逐像素参考,会把目标不同产生的差异混入实现误差。 对每个可见表面点,确定性参考把灯划成 64×64 与 128×128 网格...
计算机图形学 23:金属高光与玻璃折射怎样建模
同一盏灯照在金属球上,改变粗糙度会让高光展宽;透过玻璃观察时,光线还会改变方向。继续使用 Lambert 的常量 BRDF 无法表达这两种现象。把高光指数调大也不能自动得到正确的反射份额、折射方向和抽样权重。 本篇选择两种明确的模型:各向同性 GGX 单次散射导体反射,以及理想光滑、无吸收的介质界面。前者检查粗糙度和反射能量,后者检查 Fresnel、全反射与离散事件采样。暂不实现粗糙玻璃、体吸收或完整玻璃球的多界面路径追踪。 先固定方向与介质两侧 沿用第 19 篇的约定,ωᵢ 和 ωₒ 都从表面向外。ωᵢ 指向入射光的来源,实际入射传播方向是 −ωᵢ。法线 n 朝向入射介质,因此 cᵢ=n·ωᵢ≥0。程序显式传入入射侧折射率 ηᵢ 和另一侧折射率 ηₜ,不依靠一个含糊的“玻璃折射率”猜测当前在物体内还是外。 令 q=ηᵢ/ηₜ。反射方向 r=2cᵢn−ωᵢ;折射方向为: ωt=−qωi+(qci−ct)n,ct=1−q2(1−ci2).\omega_t=-q\omega_i+(q c_i-c_t)n, \qquad c_t=\sqrt{1-q^2(1-c_i^2)}. ωt...
计算机图形学 22:小光源为什么难以采样
把上一篇的整面发光天花板缩成一小块灯,路径追踪仍能得到正确期望,但有限样本的图像会变得很吵。多数随机方向没有命中灯,少数命中方向承担了很大的贡献。增加样本能缓解问题,改变采样分布则可能更有效。 本篇在同一个小灯盒子中比较三种直接光估计:按表面反射分布选方向、在灯面选点,以及用多重重要性采样合并二者。先隔离一次散射,避免把多次反射、路径终止和采样策略混成一个误差来源。 小灯让哪些样本失效 盒子沿用第 21 篇的坐标和材质:地板 y=−1,顶面 y=1,前面开口;左墙红、右墙绿,其余表面灰。新灯位于 y=0.99,朝下,边长 0.24,面积 A=0.0576,三个通道的发射辐亮度均为 40。原来发光的顶面改成反射率 0.65 的灰色表面。 这改变了场景,不能把新图和上一篇直接比较为“算法加速”。下面三种策略使用的都是这个新场景。它们只计算相机直接见灯和相机命中表面后的直接灯光,不计算第二次表面反射。 探针放在地板中心,向内偏移 10⁻⁷,反射率 ρ=0.65。若按 Lambert 的余弦分布抽方向,密度 pᵦ=cosθ/π。命中灯时,fᵣcosθ/pᵦ=ρ,所以一次非零样本为 ρL...
计算机图形学 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 表示根。这种数据表示本身...









