计算机图形学 31:力怎样变成运动
一个无阻尼弹簧从拉伸位置释放,理论上应一直以相同振幅振荡。用最直接的 Euler 更新位置和速度,程序却越振越大;把位置改成使用更新后的速度,画面稳定了,但它是否真的保存了能量? 本篇固定一个能写出解析解的单弹簧,比较两种更新顺序。所有实验到达同一个 11 秒时刻,同时观察位移、速度、能量和步长。半隐式 Euler 只在特定步长范围内有界,能量有界也不代表运动相位准确。 动画姿态与动力学状态有不同输入 第 29 篇用关键帧和绝对时间求姿态,时间一给定就能插值得到结果。动力学模型则保存状态,下一状态依赖当前状态、受力和积分方法。只知道位置,通常还不够决定下一步向哪里运动。 取一维质点,弹簧固定端与静止平衡点位于 x=0。x 是偏离平衡点的有符号位移,v 是速度;当前例子没有重力、阻尼、碰撞和弹簧长度下限。它不是一条只能承受拉力的绳子,x<0 时仍按同一 Hooke 定律回复。 量纲具体规定为米、千克、秒。质量 m=1 kg,弹簧刚度 k=4 N/m,受力 F=−kx,正位移产生负向力,负位移产生正向力。由 F=ma 得到: x˙=v,v˙=−kmx=−ω2x,ω=k/m=2...
计算机图形学 30:骨骼怎样带动网格
一段圆柱的底端固定,顶端绕轴转半圈。给每个顶点分配两根骨骼的权重,再混合骨骼变换,圆柱中间却缩成一点。骨骼都是刚体旋转,顶点为什么仍然发生收缩? 判断这种画面之前,需要排除另一种问题:绑定姿态是否已经移动了顶点。漏掉绑定逆矩阵、乘错次序或把关节编号当成场景节点编号,都能产生错误变形。两骨骼实验先检查这些条件,再用解析半径证明扭转收缩是线性混合蒙皮本身的限制。 网格坐标与关节坐标必须有明确关系 第 16 篇的场景图只求每个节点的世界变换。一个网格实例应用一个矩阵,所有顶点一起运动。骨骼动画则允许同一网格的不同顶点受到不同关节影响,甚至同一个顶点同时受两根骨骼影响。 沿用右手系、列向量和弧度。C++ 的矩阵按行存储,乘法作用方向仍是右侧先执行,不能从内存排列推断几何次序。当前网格的绑定顶点直接处于参考世界坐标,不额外使用网格节点变换。 记第 j 根骨骼绑定时的世界矩阵为 Bⱼ,当前世界矩阵为 Gⱼ(t)。绑定逆矩阵把绑定网格中的点转换到该关节的绑定局部坐标,当前世界矩阵再把它变换回来: Cj(t)=Gj(t)Bj−1,p~j(t)=Cj(t)p~.C_j(t)=G_j(t)B_j^...
计算机图形学 29:两个姿态之间怎样运动
一根杆从 170° 转到 −170°,终点只相隔 20°。直接混合两个角度,参数中点却是 0°,杆绕了 340°。更换成四元数还不够:同一个旋转有两个反号表示,若选错端点符号,插值仍可能走长路。 本篇固定两秒动画,比较朴素角度插值、最短弧 SLERP 与归一化线性插值。CPU 检查姿态、时间输入和角速度,浏览器真实绘制并提供拖动、播放、暂停。不同采样频率的验收比较同一绝对时刻,避免把“每帧加一点”造成的速度差误认为插值误差。 两个角度数字没有指定中间路线 打开关键帧实验。点击“核对CPU样本与GPU画面”,将时间放在 1000 毫秒,再切换插值方式。最短弧中点指向左,朴素角度中点指向右。 局部杆端点为 p=(1,0,0),绕 +z 轴旋转,沿用第 01 篇右手系。正角将 +x 转向 +y;计算使用弧度,表格和图中使用度。时间以秒输入,屏幕显示毫秒滑块,两者相差 1000 倍。 起止角度 θ₀=170°、θ₁=−170°,时刻 t∈[0,2] 对应 u=t/2。直接线性混合得到: θnaive(t)=(1−u)170∘+u(−170∘)=170∘−340∘u.\theta_{\...
计算机图形学 28:实时材质怎样近似离线光照
一个黑色物体挡住天空时,附近的漫反射表面会变暗。若实时着色只按法线查询预计算的环境光,同一法线在遮挡物附近和远处得到相同的入射光,阴影就会缺失。两张图即使颜色接近,也可能没有计算同一组光路。 本篇固定环境图、材质、相机与曝光,比较 GPU 的漫反射环境 IBL 和 CPU 的带可见性路径采样。选用能解析积分的简单环境,先验证预计算和着色器,再解释真实遮挡造成的模型差异。第 23 篇的 GGX 与折射模型保持原有含义,本实验明确选择 Lambert 材质,不把漫反射结果外推到金属或玻璃。 同一个场景的两个光照模型 打开环境光照对照。点击“运行GPU并核对CPU”,再切换 GPU IBL、CPU 路径参考与线性差异三种视图。“CPU路径参考”只通过 GPU 显示已有 CPU 数据,没有在浏览器中执行 GPU 路径追踪。 接收体为原点处的单位球,RGB 反射率固定为 (0.65,0.55,0.45)。黑色遮挡球中心 (0.55,0,1.6),半径 0.35,反射、透射与自发光都为零。它实际参加 CPU 射线求交,不是最后在图片上涂出的黑圆。 正交相机从 z=4 沿 −z 观察,图像...
计算机图形学 27:为什么更多物体会变慢
同一个四边形重复绘制 4,096 次,可以提交 4,096 条绘制命令,也可以提交一条带有 4,096 个实例的命令。两种方法都要处理 24,576 个顶点,都覆盖同样的像素。减少绘制命令主要改变的是命令组织成本,不能据此推断三角形处理、着色或显示速度一定提高。 第 26 篇已经检查了坐标、颜色、布局与深度。本篇保留它的 WebGPU 与线性颜色约定,用互不重叠的小四边形隔离提交方式的影响。实验先检查两种方法生成相同的字节,再测量 CPU 编码提交、GPU render pass 和连续绘制时的帧回调间隔。 固定画面,再改变提交方式 打开实例化实验。点击“运行完整对照”,页面依次检查 64、1,024、4,096 个物体。完整原始样本保留在页面下方,可另查看本次实际测量 JSON。 图中每个小块都是 GPU 绘制的两个三角形。所有场景使用 512×512 附件,每像素一个样本,没有纹理、光照和 MSAA;背景黑色,不启用混合。每个格子的宽高占格距的 72%,避免交叠与排序影响。物体增多时单个小块会缩小,因此只在同一物体数内比较两种提交方式,不把不同物体数的耗时当作相同几何负...
计算机图形学 26:软件管线怎样映射为着色器
第 11 篇的软件光栅器已经能把网格变成颜色图,第 16 篇又把局部变换串成世界变换。到了 WebGPU,顶点变换、属性插值、深度测试和纹理采样由固定功能与着色器共同完成。迁移的难点在于让两条管线对同一批字节、坐标和颜色作出同一种解释。 本篇固定一个 128×128 场景:两个有重叠的倾斜四边形,共享一张 8×8 纹理,使用同一组 float32 MVP 矩阵。CPU 生成参考缓冲与诊断图,浏览器在真实 WebGPU 设备上渲染并读回颜色、辅助数据和深度附件。内部像素要求数值一致;几何边界单独统计,不把两种光栅器不同的覆盖规则伪装成错误。 先运行同场景实验 打开 CPU 与 WebGPU 对照实验。点击“运行 GPU 并核对 CPU”,再依次查看纹理颜色、UV、原始深度和差异位置。页面显示的是 GPU 附件读回值,不是 CPU 图片或预存截图。 实际验证日期为 2026-09-22。Codex 内嵌浏览器报告 Chrome/153.0.0.0,安全上下文为 true,适配器 vendor 为 apple、architecture 为 metal-3;device 与 desc...
计算机图形学 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...











