中EN
精修课概念页

塑形函数:在 0 到 1 之间掰弯一条线

Shaping Functions

更新于 2026-10-15 约 15 分钟GLSL插值smoothstep程序化动画

先从一条直线开始

片元着色器对屏幕上的每个像素运行一次,输入是这个像素的位置,输出是它的颜色。把位置除以画布尺寸,就得到 0 到 1 之间的归一化坐标 st。

最简单的一件事:把 st.x 直接当作亮度。左边是 0(黑),右边是 1(白),中间是一条均匀的渐变。如果再把 y = x 这条线画在上面,你会看到一条从左下到右上的对角线。

《着色器之书》把这一步比作宫城先生的「篱笆课」:在继续把二维坐标映射到四维颜色之前,先得把一维练熟——在 0 到 1 这个小区间里,学会把一条线随心所欲地掰弯。

篱笆:用亮度和曲线同时显示 y = f(x)
改一改

也可以直接改右边的代码:停手约 0.3 秒会自动重新运行;改坏了点「还原代码」。

vec3(y) 会把三个颜色通道都设成同一个值;vec4(color, 1.0) 则是三维颜色加上不透明度。

x 和 y(或亮度)一一对应,这就是线性插值。接下来要做的,是用数学函数把这条线弯过来。

幂:给数据流「针灸」

把 x 升到 5 次方,直线会变成一条贴着底部、最后才猛然抬头的曲线;指数小于 1 时正好反过来,一开始就冲上去。

pow(x, 0.2)xpow(x, 5.0)01
同一段 [0,1]:指数大于 1 时曲线先慢后快,小于 1 时先快后慢,等于 1 就是直线。

拖动下面的滑块改指数,依次试试书里建议的 20、2、1、0、0.2、0.02,体会「值」和「指数」的关系:

y = pow(x, k)

直接改上面的表达式就能重画:x 是 0 到 1 的横坐标,可以用 sin、pow、smoothstep 等函数。

背景亮度就是 y 的值:曲线压低的地方画面也更暗。

pow 是 GLSL 的内建函数,和 exp、log、sqrt 一样大多有硬件加速——用对了地方,它们比自己手写的级数更快。

step 与 smoothstep:硬开关和软开关

这两个是 GLSL 里特别常用的插值函数。

  • step(edge, x):x 小于阈值时返回 0,否则返回 1。一刀切。
  • smoothstep(edge0, edge1, x):在 [edge0, edge1] 之间做平滑过渡,两端的斜率都是 0,所以接缝处看不出折角。
step(0.5, x)smoothstep(0.3, 0.7, x)0.30.7
step 在阈值处直接跳变;smoothstep 在 [0.3, 0.7] 内用一条 S 形曲线过渡,两端与水平线相切。

两个 smoothstep 相减 = 一个凸起

前面「篱笆」里画线用的 plot() 正是这个技巧:让一个 smoothstep 早一点升起,另一个晚一点升起,两者相减,中间就剩下一个窄窄的凸起。

ABA − B
A = smoothstep(0.2, 0.5, x),B = smoothstep(0.5, 0.8, x)。A − B 只在 0.2 到 0.8 之间不为 0,像竖着切下的一片亮带。

在下面的绘图器里点一点预设,或者直接改表达式:

试试这些塑形函数

直接改上面的表达式就能重画:x 是 0 到 1 的横坐标,可以用 sin、pow、smoothstep 等函数。

正弦与余弦:会动的曲线

给定一个弧度角,cos 和 sin 分别给出单位圆上那一点的 x 和 y。它们的值在 −1 和 1 之间平滑往返,天生适合做动画。书里给了一串练习,每一个都值得亲手试一下:

把 sin 掰成各种样子

直接改上面的表达式就能重画:x 是 0 到 1 的横坐标,可以用 sin、pow、smoothstep 等函数。

依次是:随时间沿 x 平移;乘 π 改变周期;u_time × x 让频率越来越密;abs 像弹跳的球;fract 只留小数部分;ceil + floor 得到 ±1 的数字波(这里缩放到了 0~1 好看清)。

再把 mod、clamp、min、max、sign 这些函数组合进来,就是生成艺术里常见的一维「调料架」。

在游戏里怎么用

塑形函数在游戏里随处可见,只是平时它们叫别的名字。

下面这个例子把同一段运动交给四条不同的曲线:从上到下依次是线性、smoothstep、pow(t, 3.0),以及用 abs(cos) 做出的回弹。看看哪一个最「顺手」。

同一段位移,四种缓动0.0s
改一改

也可以直接改右边的代码:停手约 0.3 秒会自动重新运行;改坏了点「还原代码」。

取舍与常见的坑

小结与练习

  • 在 [0,1] 这一小段里,pow 控制快慢,step / smoothstep 控制开关,sin / cos 带来周期和动画;
  • 两个 smoothstep 相减能画出一条细线或一片亮带,这是后面画形状的基础;
  • 缓动、溶解边、呼吸灯——游戏里很多「手感」其实就是一条塑形曲线。

练习:找一份 Kynd 的方程表,挑几条用上面的绘图器复刻出来,留意它们是怎么把函数组合起来、把值控制在 0 到 1 之间的。工具箱里可以收藏 LYGIA 的数学分区,以及 Íñigo Quilez 做的 GraphToy。

  1. The Book of Shaders: Shaping functions
  2. thebookofshaders.com/05

相关页面

图形学片元着色器与 GLSL 基础Fragment Shaders & GLSL Basics片元着色器(fragment shader)是在每个像素(片元)上并行执行的小程序:输入位置等信息,输出颜色。GLSL 是 OpenGL / OpenGL ES / WebGL 共用的着色语言;本书用全屏 billboard 上的像素着色练习,建立程序化图形的基础心智模型。图形学着色器中的颜色Color in Shaders在 GLSL 里颜色与空间坐标共用 vec2/vec3/vec4:可用 .rgba / .xyzw / .stpq 或下标访问,并 swizzle 任意重排。mix 在 [0,1] 上混合;HSB(HSV)比 RGB 更直观,还可映到极坐标色轮。图形学二维 SDF 形状2D SDF Shapes在片元着色器里画形,不是发三角形图元,而是对每个像素问「我在形的里面还是外面」。矩形用 step/smoothstep 做轴对齐边界;圆与更复杂形用距离场 (distance field)——到特征点的距离再阈值。这是 2D SDF 程序化造型的入门路径。图形学程序化图案Procedural Patterns片元着色器按像素执行:形状重复多少次,计算量几乎不变,因此特别适合平铺图案。核心手法是放大 st 再 fract 得到重复的 [0,1] 子空间,再在格子内画形、做矩阵变换,或按奇偶行错位、按格子旋转拼 Truchet。图形学噪声函数Noise FunctionsKen Perlin 为电影《电子世界争霸战》(Tron) 设计的噪声,解决「看起来随机却不像电视雪花」的程序纹理问题。入门路径是值噪声 (value noise):格子角点取伪随机,格内用平滑曲线插值;进阶有梯度噪声 (gradient noise)、五次插值改进版,以及用单纯形网格降复杂度的 Simplex Noise。图形学分形布朗运动Fractional Brownian Motion分形布朗运动 (fBm) / 分形噪声:把多「八度 (octave)」噪声叠加——频率按空隙度 (lacunarity) 步进升高,振幅按增益 (gain) 衰减——得到跨尺度自相似细节。变体包括湍流(绝对值尖谷)、脊状噪声、乘性/多重分形,以及用噪声扭曲采样坐标的域扭曲 (domain warping)。图形学着色器二维矩阵变换2D Matrix Transforms in Shaders在片元里「移动形状」其实是移动坐标系:平移加向量;旋转与缩放用 mat2 乘到坐标上。绕画布中心变换时,要先把空间挪到原点、变换、再挪回。矩阵乘法顺序有关;同一套矩阵也可拿来做 YUV↔RGB 等颜色空间线性变换。图形学着色器伪随机Shader Pseudorandom片元着色器里没有真正的「每次调用都不同」的随机:rand(x) 必须是确定性伪随机——同一输入永远同一输出。常用手法是 fract(sin(x)大数);二维则用 dot 把 vec2 压成标量再喂给同一套路。把空间 floor 成格子后,格子共享一个随机值,就能在秩序与混沌之间做生成设计。

被这些页面引用1 篇

输入关键词开始搜索

滚轮或双指缩放 · 拖动平移 · 双击放大 / 还原