内容工厂. / 演示空间 课题 10 · 课程 47
面向工程师

动动手看演示

当前领域 图形渲染 + 物理模拟 课题 10 个 课程 47 课 段落 178 段

这里只列已经做出来的。

管线各阶段的数据处理

3 课 · 9 段已交付

骨架:GPU 干两件事 —— ① 把顶点流处理成裁剪空间顶点;② 据此画像素。 一个几何顶点、一张纹理、一组参数,从进入到输出被逐阶段变换与消费的全过程。

附录 · 图元的增删发生在哪一段、为什么它是可选的 —— 查得到就行,不进主线。

PBR 高级效果

7 课 · 25 段已交付

骨架:着色不是「给表面涂颜色」,而是解一个积分 —— 对每个着色点,把所有入射方向的贡献按 BRDF 加权累加。 沿模型谱系走,每一代都是对同一个积分更好的一次近似。

附录 A1 · CSM 级联阴影(级联按对数切分)—— 成本高于主线,按需展开。

全局光照 GI

5 课 · 15 段已交付

骨架:一个着色点接收到的光,有一部分来自别的物体反射的光;而别的物体,又接收到它反射的光。 要算清这一点只能在场景里采样 —— 而一旦靠采样,就受 1/√N 支配。

附录 A1 光子映射与辐照度缓存 / A2 VXGI —— 成本高,按需展开。

物理模拟

5 课 · 20 段已交付

骨架:物理模拟每一帧只做三件事 —— ① 对每个物体积分;② 找出接触(谁压着谁、压多深);③ 解约束(按质量分配地纠回来)。 前三课把这三件事各讲透一次;第四课把「硬」约束换成「软」约束,绳子与布料就出来了;第五课把镜头挪到关节与骨骼,收口整条链。

附录 A1 高阶积分器(RK2 / RK4 / Verlet)/ A2 连续碰撞检测(CCD、保守推进)/ A3 摩擦锥与休眠 / A4 关节与骨骼(点/铰/锥约束、motor、ragdoll)—— 按需展开。

动画与骨骼

5 课 · 20 段已交付

骨架:动画 = 每一帧先把骨架姿态算出来,再把网格顶点按权重「挂」到骨头上(蒙皮是「读姿态」的人,IK / 弹簧骨 / 关键帧是「写姿态」的三条路)。 第一课做前半段(姿态 → 顶点);第 2–4 课做「写姿态」的三条路 —— 解出来的(IK 反解)、演出来的(弹簧骨)、 以及真实项目里占比最大的那一条:补出来的(关键帧与插值);第 5 课把这些动作叠起来:权重混合、相位、遮罩、加层。

附录 A1 双四元数蒙皮与辅助骨 / A2 反向动力学(双骨解析解 / FABRIK / CCD)/ A3 Verlet 弹簧骨 / A4 切线与钳制(怎样既平滑又不过冲)/ A5 状态机与过渡条件、根运动与脚步锁定、混合树与分层遮罩 —— 按需展开。

特效与粒子

5 课 · 20 段已交付

骨架:特效 = 一大堆各自独立的小东西,每一个只做三件事 —— ① 按自己的速度挪一步;② 按自己的寿命决定还剩多少不透明; ③ 按「从远到近」的顺序盖到画面上。前五个课题讲的都是"一个东西怎么被画对"(一条管线、一个球、一个场景、一堆刚体、一具骨架), 这个课题开始讲"一堆":每个粒子都微不足道,一团的观感全来自它们怎么叠加 —— 而"叠加"正是第 3 课的混合、"挪一步"正是第 5 课的积分。 第 1 课搭出引擎,第 2 课把"速度从哪来"换成每处空间给一个无散的速度场(旋度噪声),粒子才开始像"被空气推着走"; 第 3 课把粒子放进有物体的场景,于是"谁盖谁"要从二值判定换成按场景深度连续淡出(软粒子); 第 4 课把"画完的那张图"本身当成数据再算一遍 —— 亮处的光要溢到邻域去(后处理链:提取 → 金字塔模糊 → 按强度 k 加回去); 第 5 课把图里的深度与法线也用起来:环境光被挡住多少(遮蔽)、镜子里那份光从哪来(反射)—— 而这一切都有个前提:图里没有的东西就等于不存在。

附录 A1 流场的更多形式(势流 / 速度场贴图)—— 按需展开。

程序化生成

4 课 · 17 段已交付

骨架:程序化生成 = 不摆位置、只定规则 —— 同一颗种子 + 同一个规则,必须长出同一片内容。 而"像自然"靠两件事:横着看,每个格点上一个随机数、中间按核平滑地连起来;竖着看,把很多层按幂律叠起来(自相似)。 前六个课题讲的都是"把一个已经存在的东西画对",这个课题讲"东西本身是怎么长出来的" —— 它也是唯一一个"随机"真正进了算式的地方:第 1 课先把随机数从"一个没有距离概念的数"变成一张处处光滑的场, 第 2 课再换一种喂坐标的方式(不改函数、只改坐标)—— 同一张场立刻长出走向、山脊与峡谷,摆上一套只读高度的着色,它就是地形。 第 3 课换掉规则本身:不说"相邻处要相似",只说相邻处必须是一对见过的搭配 —— 机器拼出一张不违和的图, 而"拼不出来"这件事第一次变成了一笔可以数的账。 第 4 课连"瓦片"也不要了:规则从一张样例图里自己数出来 —— 输出里出现的每一个 N×N 小方块都必须来自样例(C1), 而"局部合法 ≠ 整体像"这件事,可以用两把不同大小的尺子当场量出来。

附录 A1 把约束钉到具体内容上(封边 / 钉死关键格 / 分层生成)/ A2 关卡连通性 —— 按需展开。

采样与重建

4 课 · 16 段已交付

骨架:前八课的输入都是已经离好的东西(顶点、像素、瓦片、样例图)。这个课题退到更前面一步:连续的东西怎么变成一串数? 而这正好是整站最基础的那道数学 —— 采样与重建:纹理过滤、Mipmap、MSAA、阴影贴图走样、TAA,全是它。 全课题骨架:采样不是"取点",是"用一串离散值 + 一个重建核,去猜那个连续的东西";核决定它像不像, 而"先滤再采"是唯一的治本手段 —— 图像里的摩尔纹与声音里的混叠,是同一道数学。 第 1 课把这条链走完一遍,每一步都留一个能拿笔核的数:折叠律 f_alias = |f − k·f_s|、 重建核的过点条件 h(0)=1、h(整数≠0)=0、混叠幅度 = 采前低通的 |H(f)|。 最该记住的一句是:混叠不是"像",是"相同" —— 700 Hz 采成 1000 Hz 与直接采 300 Hz, 是两个逐位相同的样本序列;画 11 条条纹、只有 16 个像素,与画 5 条是同一张图。 第 2 课接着拆"先滤再采"里的那台滤波器:它就是一个差分方程,五项系数就是那条频响曲线; "设计滤波器"从形状反解系数有三条能拿笔核的特值;而唯一的坑是双线性变换把频率轴用 tan 扭了一下 —— 不预畸变时 −3 dB 点越靠近 Nyquist 偏得越狠(0.45·f_s 处偏 −32.44%)。
第 3 课反过来 —— 不采一根弦,而是用一条几十个采样长的环形延迟线把一根弦"长"出来: 音高由"这一圈走几拍"(p + ½)定,衰减由环路里那个滤波器定。 第 4 课换一个问法:一个声音怎么被放到"左边 / 远处 / 身后"去 —— 答案是给它算出几个增益 (方位角给两个、距离给一个、朝向再给一个),而 equalpower 那套算法有个反直觉的底: 它把方位角折回 [−90°, 90°],于是"正前"与"正后"的两个增益逐位相同。

附录 A1 卷积混响与脉冲响应/ A2 AudioWorklet 与在音频线程里跑自写 DSP —— 按需展开。

几何处理

4 课 · 16 段已交付

骨架:几何不是"画"出来的,是控制点 + 一条可以反复施加的规则算出来的 —— 而那条规则只做一件事:在两点之间取一点。 前九个课题的输入都是已经离好的东西(顶点、像素、瓦片、网格、样例图);这个课题退到更前面一步: 那些顶点和网格是从哪儿来的? 第 1 课把这条规则用在一排控制点上:把它重复 n 次就是一条曲线(de Casteljau 的金字塔), 行数就是次数;把系数一次算完就是 Bernstein 形式 —— 两条路线不共用任何中间量, 721 档扫下来最大差 3.46e−13。 最该记住的两句:曲线只经过首末控制点(中间那些只是"拉力",离曲线最近也还有 170.00 px); 两段接得光不光滑只看端点切线——B'(0) = n(P₁−P₀), 于是 C¹ 的条件是 P₂ → Q₀ → Q₁ 三点共线且等距(共线度从 0.384615 = 5/13 掉到 0)。 第 2 课把同一条规则搬到三维网格上:真实网格的每个点周围围着一圈面, 于是"在两点之间取一点"升级成三条同时取平均的规则(面点 / 边点 / 顶点点)。 量出来才敢说的一件事:三条只做两条,曲面比不改还糟 —— 角上的最大二面角从 90° 涨到 116.18°;三条齐了才单调下降(90° → 7.06°)。 第 3 课换一条路:不再"把网格变密",而是从一条线直接得到一整张面 —— 两个方向各做一次第 1 课的事(先按列取点、再对这一排取点)。 量出来最该记住的一件:面上的点受整片控制网影响,可四条边界曲线只受边界那一行一列影响 (扰正中间那个点,四条边界的位移恰好是 0); 再给控制点配一个权重 w = sin(α/2),同一条抛物线就落成精确的圆, 两个方向都配上,就得到精确的环面(隐式方程残差相对 4.87e−16)。 第 4 课回头补上前三课一直没交代的那个前提:"任意拓扑"是靠一份存下来的账换来的 —— 每条边拆成两条半边,记下 next / twin / 起点 / 左侧面,于是"邻居是谁"从"现算"变成"顺着指针读"。 量出来最该记住的一件:这份账有前提 —— 一条边被三个面共用、顶点星分成两片、曲面不可定向 (Möbius 带),三种情形本页都造了反例,各自被拒在不同的那一条上。 而有了邻域就能算曲率:立方体每个顶点亏 π/2,八个合起来恰好 4π(与 2πχ 之差为 0)。

附录 A1 布尔与重网格(玩具规模,如实标示意)/ A2 细分曲面的 GPU 自适应(Pixar TOG 2012)—— 按需展开。

寻路

5 课 · 20 段已交付

骨架:寻路不是"找一条路",而是给地图上每个位置记一个数,然后从任意一点顺着这个数往下走 —— 而记数这件事只有一条规则:从已经确定的那一圈往外推一格,给新格记下它自己的数。 前十个课题的输入都是"已经摆好的东西"(顶点、像素、瓦片、网格、样例图、控制点);这个课题退到更前面一步: 从一个位置走到另一个位置,中间这件事到底怎么算? 第 1 课先把"路"换成一张数表:每格记一个 d(到起点花了多少), 每轮取 d 最小的那一格定为"已定",再给它的四个邻居记上 cand = d[n] + w。 量出来才敢写的一件事:这张表与"按层一圈圈扩"这条完全独立的路线逐格相同 —— 965 个可走格一位不差;把泥地标成"贵 4 倍"之后,最短路自己改道 (单位权 31 步穿 7 格泥 → 带权 47 步一格泥都不穿,老路线按带权算 52); 而"取到目标就停"省下 19.8% 的格数、目标那一格上的数一模一样。 第 2 课补上泛洪缺的那一半:让每格的数里多一项"从它到终点还要花多少"的猜测, 取的时候按 f = g + h 取 —— 要定的格从 965 降到 233(少算 75.9%), 而解一位不差(都是 47,第三条独立路线"从终点反向泛洪"给出同一个 47)。 最该记住的一句:"不高估"(可采纳)保的不是"答案更准",而是"答案不变" —— 把猜测整体乘 k,k 在 0 与 1 之间拖,解代价五档全是 47,变的只有要定多少格(774 → 233); 而越过那条线之后丢掉的不是答案、是保证:k = 1.25 已有 841 个格被高估却仍给出最优解, 到 k = 1.5 才真的坏(贵 5)。再把它当旋钮用(f = g + W·h), 界就是 C ≤ W·C*:W 从 1 拖到 3,要定的格从 233 掉到 41,解最多只涨 10.6%。 第 3 课顺着这层对称性往下走一步:大部分方向根本不必看。 从一格往前走时只留两个方向 —— "继续往前那一个"永远留,"旁边那一个"只在退半步是墙时才留 (后者就是所谓"被迫方向")。这条规矩与"按定义逐条算"的版本逐对核 3612 对、不一致 0, 全图 13842 个方向剪掉 10412(75.2%)。可量出来的一件意外更值钱: 它在每一条局部上都证得出,整体上却把图剪断了 —— 只按这条规矩搜索,目标上的数是 ∞ (补上"被迫方向"也仍是 ∞),而"四邻都看"只要 323 格就给出 43。 于是这一课的交付换了个位置:规矩留着讲清楚(它是跳点法的来处), 而"把一串格压成转角"这件事在已经拿到的最优路径上用(43 步 → 5 个点 / 4 段,段长和仍是 43)。 第 4 课换了一个问法:前三课都是"一个人问一次",可真实场景是一千个人朝同一个终点走。 于是把账从终点往外一次摊到每一格(积分场:每格记下"到终点还要花多少"), 再让每格只留一个方向(流场:比八个邻居取积分值最小的那个)。 量出来的是两件事:沿场从任意一格走到头,955 格一个都没卡住(除终点外无局部极小); 而"一张场 + 1000 次读"只要 1955 格次,同样的人各跑一次 A* 要 183 000 格次 —— 少算 98.93%。 ★ 这里有一处口径要如实说:积分场是四连通、流场比的是八个邻居,斜走也算一步, 所以起点那一格积分值 43、沿场真的走一遍只要 31 步。 最后补上前三课都没碰过的那一半:人多了会互相挡 —— 两个人快撞上时各让一半(谁也不把责任推给对方):不避障会从彼此身上穿过去(跨组最小距 0.0001), 而"各担一半"时最小距 0.8778,连绕行量也几乎对分(+6.1 / +6.8);只让一方担责的话,那一方要多绕 5 倍多。 第 5 课把"数的载体"从格换成面:先把空间体素化、按 agent 半径把走不了的格删掉, 再把可走面切成一批凸多边形(盖满不重叠、相邻共享一整段), 最后在多边形图上跑 A* 拿到"经过哪几个面"、再把折线拉直成"具体怎么走"。 量出来的:24×16 的玩具世界里体素化得 1264 个可走格,按半径 0.75 过滤后剩 1132; 划分出 11 个凸多边形,面积合计 283.00 与可走格数×格面积逐位相等; 拉直把 8 点(代价 28.3095)压成 4 点(27.5727),且拉直之后再也拉不动一点。 而"为什么必须是凸的"有一条有分辨力的对照:面内任取两点的连线不出面 —— 正方形上 1000 对全过,L 形(凹)上1000 对里有 232 对出界。

本课题 5 课已全部上线(泛洪 → 猜一个数 → 剪枝 → 一次算完 → 从格到面)。