☰
微分的实际应用:从“变化有多快“说起
2026/10/26 1:16:30 网站建设 项目流程

这次也先用图讲清楚微分是什么,再看它在游戏、图形和其他领域的用法。最后附一个网页小程序,可以用鼠标观察曲线上每一点的"陡峭程度"。


一、微分是什么?一句话:变化有多快

开车时,车上有两块表:

┌──────────────┐ ┌──────────────┐ │ 里程表 │ │ 速度表 │ │ 12345 公里 │ │ 60 公里/时 │ └──────────────┘ └──────────────┘ "走了多远" "此刻走得多快" (位置) (位置的变化快慢)

速度表显示的数字,就是里程的"微分"(导数)。

  • 里程涨得快,速度就大;
  • 里程不变,速度就是 0;
  • 里程在减少(倒车),速度就是负数。

微分 = 某个量此刻的变化速度。


二、用图看:微分就是曲线的"陡峭程度"

把"位置随时间变化"画成曲线:

位置 │ ╱ ← 这里很陡:变化快,导数大 │ ╱ │ ╱ │ __╱ │ __‾‾ ← 这里平缓:变化慢,导数小 │ ___‾‾ │‾ ← 这里几乎平的:导数接近 0 └──────────────────────── 时间

在曲线上某一点画一条刚好贴着它的直线(切线),这条直线的斜率就是这一点的导数:

╱ 切线(斜率 = 导数) ╱ ____●____ ╱ ╱ ╲ ╱ ╱ ╲ ╱
  • 切线往上斜:导数为正,曲线在上升;
  • 切线往下斜:导数为负,曲线在下降;
  • 切线是平的:导数为 0,曲线到顶或到底了。

最后这条特别有用,后面会反复用到。


三、电脑怎么算微分:两点之间算斜率

电脑不会画切线,但可以这样做:在旁边取一个很近的点,算两点连线的斜率。

导数 ≈ (f(x + h) − f(x)) / h ───────────────── 往前走一小步 h,看 f 变了多少,再除以步长

用 f(x) = x² 在 x = 3 处试一下(正确答案是 6):

步长 h f(3+h) f(3) 斜率 = 差 / h ───────────────────────────────────────── 1 16 9 7 / 1 = 7 0.1 9.61 9 0.61/0.1 = 6.1 0.01 9.0601 9 0.0601/0.01 = 6.01 0.001 9.006001 9 ≈ 6.001 → 越来越接近 6

画成图,就是割线一步步逼近切线:

f(x) │ ● h=1 的点 │ ╱╱ │ ╱╱ ● h=0.1 的点 │ ╱●╱ │ ╱ ╱ h 越小,连线越贴近切线 │ ╱ 3 └────────────── x
// 数值微分:中心差分比单侧差分更准staticdoubleDerivative(Func<double,double>f,doublex,doubleh=1e-4)=>(f(x+h)-f(x-h))/(2*h);

“每帧用新值减旧值,再除以时间”,本质上就是在做数值微分。游戏里到处都是这种写法。


四、其实已经用过微分:弹簧模型

上一节准星回正的三行公式:

加速度 = −硬度 × 偏移 − 阻力 × 速度 速度 += 加速度 × 时间 偏移 += 速度 × 时间

把它和微分对照一下:

偏移(位置) │ 求导:变化有多快 ▼ 速度 ← 偏移的导数 │ 再求导 ▼ 加速度 ← 速度的导数(偏移的二阶导数)

所以第一行其实是一个微分方程:

偏移的二阶导数 = −k × 偏移 − c × 偏移的导数

后两行则是在一小步一小步地解这个方程,倒着从变化率还原出位置。

还记得手算表里的第 6 帧吗?

帧 速度 偏移 5 2.6 0.90° 6 0.3 0.90° ← 最高点:速度(导数)≈ 0 7 −1.5 0.87° ← 速度变负,开始往回落

导数为 0 的地方,就是最高点。这就是第二节讲的"切线是平的"。


五、游戏和图形中的应用

应用 1:物理运动——一切会动的东西

位置 ──求导──▶ 速度 ──求导──▶ 加速度 (在哪) (多快) (油门/刹车多猛)
游戏里的需求用到的微分
角色跑动、跳跃、抛物线手雷重力 = 恒定加速度,逐帧积分得出位置
赛车漂移、刹车距离速度和加速度的关系
鼠标灵敏度、鼠标加速鼠标速度 = 本帧位置 − 上帧位置
镜头跟随不晃用速度预测目标下一刻的位置
子弹提前量(打移动靶)目标速度 × 子弹飞行时间

应用 2:光照——用导数算出表面朝向

光照需要知道表面朝哪个方向(法线)。地形通常存成一张高度图,法线就靠导数算出来:

侧视图: ↖ 法线(垂直于坡面) ╱ ________╱ 坡越陡(导数越大),法线越往旁边倒 平地:法线朝正上 ↑

做法是看某点左右、前后的高度差,也就是 x 方向和 z 方向的导数:

h(上) h(左) ● h(右) dh/dx ≈ (h右 − h左) / 2 h(下) dh/dz ≈ (h下 − h上) / 2 法线 = normalize(−dh/dx, 1, −dh/dz)
Vector3TerrainNormal(float[,]h,intx,intz){floatdx=(h[x+1,z]-h[x-1,z])*0.5f;// x 方向的导数floatdz=(h[x,z+1]-h[x,z-1])*0.5f;// z 方向的导数returnVector3.Normalize(newVector3(-dx,1f,-dz));}

法线贴图、水面波光、凹凸效果,背后都是这个原理。

应用 3:动画缓动——起步和停下要"导数为 0"

UI 弹窗、镜头移动,如果匀速开始、匀速停止,会显得很生硬:

线性:t smoothstep:3t² − 2t³ 位置 位置 │ ╱ │ __── │ ╱ │ ╱ │ ╱ │ ╱ │╱ │__╱ └──────── 时间 └──────── 时间 起点、终点斜率不为 0 起点、终点斜率 = 0 → 突然启动、突然停止 → 缓缓启动、缓缓停住

验证一下:smoothstep 的导数是 6t − 6t² = 6t(1 − t)。

  • t = 0 时导数为 0:起步时速度为 0;
  • t = 1 时导数为 0:停下时速度为 0。

设计缓动曲线,就是在设计导数长什么样。

应用 4:GPU 的 ddx / ddy——自动选贴图清晰度

GPU 渲染时会同时处理相邻的 2×2 个像素,并能直接求出"贴图坐标在屏幕上变化多快":

近处的地板:相邻像素的贴图坐标差别小 → 导数小 → 用高清贴图 远处的地板:相邻像素的贴图坐标差别大 → 导数大 → 用模糊的小贴图(mipmap) 近 ┌─┬─┬─┬─┐ 远 ┌┬┬┬┬┬┬┬┬┐ │ │ │ │ │ 格子大 ││││││││││ 格子挤在一起, └─┴─┴─┴─┘ └┴┴┴┴┴┴┴┴┘ 不降清晰度会闪烁

在着色器里可以直接写ddx(uv)、ddy(uv)。这是上次讲的顶点处理之后,光栅化阶段用到的微分。

应用 5:控制系统——弹簧阻尼就是 PID 的 D 项

工业上常用PID 控制器让机器稳定地到达目标,比如无人机悬停、恒温空调、自动瞄准炮塔:

输出 = P × 误差 + I × 误差的累积 + D × 误差的导数 (离目标多远) (一直没到位就加力) (正在多快地靠近)

对比弹簧:

加速度 = −k × 偏移 − c × 速度 (P 项) (D 项:速度就是偏移的导数)

弹簧模型本质上就是一个 PD 控制器。D 项的作用是"快到了就提前刹车",防止冲过头。阻尼比 ζ 调的就是这个刹车力度。

应用 6:找最优解——导数为 0 的地方

函数值 │ ╲ ╱ │ ╲ ╱ │ ╲__ __╱ │ ‾●‾‾ ← 最低点:切线是平的,导数 = 0 └──────────────── x

要找最大值、最小值,就去找导数为 0 的地方。常见用途有:

  • 抛物线什么时候到最高点(跳跃高度、手雷射程);
  • 游戏经济系统里,定价多少收入最高;
  • AI 寻找最佳射击角度。

应用 7:梯度下降——闭着眼睛下山

函数太复杂、没法直接解"导数 = 0"时,就一步一步往下坡方向走:

● 站在山坡上,用脚感受哪边往下(导数的正负) ╲ ● 朝下坡走一小步 ╲ ● 再感受、再走 ╲___● 导数接近 0:到谷底了
规则:x = x − 步长 × 导数

例:找 f(x) = (x − 3)² 的最低点,导数是 2(x − 3),步长取 0.1:

步数 x 导数 新 x 0 0.00 −6.00 0.60 1 0.60 −4.80 1.08 2 1.08 −3.84 1.46 3 1.46 −3.07 1.77 ... → 越来越接近 3

今天所有的 AI 模型(包括我自己)都是靠这个方法训练出来的。模型有几十亿个参数,每个参数都按"导数指示的下坡方向"微调一点点。

应用 8:牛顿法——用切线快速求解

想算 √2,也就是求 x² − 2 = 0 的解:

│ ╱ 曲线 y = x² − 2 │ ╱ │ ● 在当前点画切线 │ ╱│ │ ╱ │ 切线和 x 轴的交点,就是更好的猜测 ─┼─●──┼────── x │ 新 旧
规则:x = x − f(x) / f'(x) = x − (x² − 2) / (2x) x0 = 1 x1 = 1.5 x2 = 1.41667 x3 = 1.41421 ← 3 步就精确到 5 位小数

计算器开平方、游戏中的光线与曲面求交、IK(反向动力学,让角色的手准确碰到门把手)都常用这类方法。


六、游戏之外的应用(简要)

领域微分在算什么例子
经济边际成本、边际收益多生产 1 件,成本增加多少
医学药物浓度变化率药效多久衰减到一半
天气气压、温度的空间变化气压变化越陡,风越大
工程应力、振动桥梁共振频率(和弹簧的频率是同一个概念)
导航速度、加速度手机陀螺仪、加速度计推算位置
图像处理亮度变化率亮度突变的地方就是物体边缘(边缘检测)
人口、传染病增长率疫情模型、人口预测

七、动手看:网页小程序

复制下面全部代码,保存为微分.html,双击用浏览器打开。

  • 鼠标在画布上左右移动,红点会沿着曲线走;
  • 绿线是切线,右上角显示导数(斜率);
  • 拖动滑块改变步长 h,橙线是两点连线(割线),h 越小越接近切线;
  • 导数接近 0 时,红点会变成金色,提示这里是"山顶"或"谷底"。
<!DOCTYPEhtml><html><head><metacharset="utf-8"><title>微分:曲线的陡峭程度</title></head><bodystyle="font-family:sans-serif"><canvasid="c"width="700"height="420"style="border:1px solid #ccc"></canvas><br>步长 h:<inputtype="range"id="h"min="0.02"max="2"step="0.02"value="1"><bid="hv"></b><p>鼠标在画布上左右移动。<spanstyle="color:#0a0">绿线 = 切线(真正的导数)</span>,<spanstyle="color:#e80">橙线 = 两点连线(电脑的近似)</span>。</p><script>constcv=document.getElementById('c'),g=cv.getContext('2d');constf=x=>Math.sin(x)*2+0.3*x;// 要观察的曲线constdf=x=>2*Math.cos(x)+0.3;// 它的精确导数constS=50,OX=50,OY=210;// 1 单位 = 50 像素constsx=x=>OX+x*S,sy=y=>OY-y*S;letmx=3;cv.onmousemove=e=>{constr=cv.getBoundingClientRect();mx=(e.clientX-r.left-OX)/S;draw();};document.getElementById('h').oninput=draw;functionline(x,y,k,color,w){// 过点 (x,y)、斜率为 k 的直线g.strokeStyle=color;g.lineWidth=w;g.beginPath();g.moveTo(sx(x-3),sy(y-3*k));g.lineTo(sx(x+3),sy(y+3*k));g.stroke();}functiondraw(){consth=+document.getElementById('h').value;document.getElementById('hv').textContent=h;g.clearRect(0,0,700,420);// 坐标轴g.strokeStyle='#ccc';g.lineWidth=1;g.beginPath();g.moveTo(0,OY);g.lineTo(700,OY);g.moveTo(OX,0);g.lineTo(OX,420);g.stroke();// 曲线g.strokeStyle='#06c';g.lineWidth=3;g.beginPath();for(letpx=0;px<=700;px++){constx=(px-OX)/S,y=sy(f(x));px?g.lineTo(px,y):g.moveTo(px,y);}g.stroke();constx=mx,y=f(x),k=df(x);constk2=(f(x+h)-f(x))/h;// 电脑的近似:两点斜率line(x,y,k2,'#e80',2);// 割线line(x,y,k,'#0a0',3);// 切线// 第二个点g.beginPath();g.arc(sx(x+h),sy(f(x+h)),6,0,Math.PI*2);g.fillStyle='#e80';g.fill();// 当前点:导数接近 0 时变金色constflat=Math.abs(k)<0.15;g.beginPath();g.arc(sx(x),sy(y),9,0,Math.PI*2);g.fillStyle=flat?'#fc0':'#e00';g.fill();g.fillStyle='#000';g.font='16px sans-serif';g.fillText(`x =${x.toFixed(2)}`,450,30);g.fillText(`真正的导数(切线斜率):${k.toFixed(3)}`,450,55);g.fillText(`电脑近似(h=${h}):${k2.toFixed(3)}`,450,80);g.fillText(k>0.15?'↗ 上升中':k<-0.15?'↘ 下降中':'★ 导数≈0:山顶或谷底',450,105);}draw();</script></body></html>

可以试试:

  1. 把鼠标移到曲线的山顶:绿线变平,红点变金色,说明导数为 0 的地方就是最高点。
  2. 把 h 从 2 慢慢拖到 0.02:橙线逐渐和绿线重合,近似值越来越接近真值。
  3. 在陡坡上来回移动:导数数字变大,这就是"变化快"。

八、一句话总结

微分就是"此刻变化有多快",在图上就是切线的斜率。电脑用"新值减旧值,再除以步长"来计算它。

微分能做什么: 位置 → 速度 → 加速度 物理运动、弹簧后坐力 高度 → 坡度 → 法线 地形光照、法线贴图 导数 = 0 找最高点、最低点 沿导数反方向走 梯度下降、AI 训练 沿切线逼近 牛顿法求解 起止点导数 = 0 平滑的动画缓动 误差的导数 PID 控制、弹簧阻尼

微分的"反过程"叫积分,也就是从速度还原出位置,弹簧模型后两行做的正是这件事。需要的话,下一次可以用同样的方式(配图加网页小程序)讲积分的实际应用,以及游戏物理中几种积分方法的区别:欧拉法、半隐式欧拉、Verlet 和 RK4。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询