第 4 章练习:阈值与遮罩

对应教程:04 数值映射与阈值
起始示例:阈值与遮罩,修改 04-threshold.js 和需要时的 04-threshold.html。

每道题都从起始示例开始;也可以保留上一题的改动,依次增加新模式。先观察默认效果,再修改代码。

练习 1:反向分界

**目标:**在默认的左右分界模式中,让阈值左侧为亮色、右侧为暗色。

**要求:**只修改 uMode == 0 分支中的遮罩表达式,不交换 darkColor 与 lightColor。

**完成标准:**拖动阈值时,亮色区域从左向右扩大或缩小,边界仍是硬边。

<details> <summary>提示</summary>

原遮罩只有 0 和 1;考虑如何把 0 变成 1、把 1 变成 0。

</details>

练习 2:画一个空心矩形框

**目标:**新增一个模式,在 UV 的 0.2~0.8 正方形区域画出一个框,并挖去中央 0.35~0.65 的正方形。

**要求:**用 step 构造内外两个 0/1 矩形遮罩,再相减;给下拉框新增选项。框外和中央都应为暗色。

**完成标准:**新模式显示四边亮、中间暗的封闭方框;原模式不变。

<details> <summary>提示</summary>

可以分别求 x、y 方向的带,再用 min 求交集。外矩形减去内矩形。

</details>

练习 3:由半宽控制线性过渡

**目标:**新增一个颜色渐变模式,以 uThreshold 为中心,过渡从 uThreshold - uHalfWidth 开始,到 uThreshold + uHalfWidth 结束。

**要求:**用 clamp 和 mix,使“条带半宽”滑块同时成为过渡的半宽控制。不要使用下一章的 smoothstep。

**完成标准:**改变阈值只移动过渡区;增大半宽使过渡更宽;阈值处恰好是两色的中间值。

参考解答


<a id=“reference-answers”></a>

第 4 章练习参考解答

对应练习:阈值与遮罩。改动基于第 4 章示例。

练习 1:反向分界

把默认分支改为:

if ( uMode == 0 ) {
  mask = 1.0 - step( uThreshold, vUv.x );
}

原本左侧为 0、右侧为 1;减去后正好反过来。mix(darkColor, lightColor, mask) 的颜色顺序没有改变。

练习 2:画一个空心矩形框

在 04-threshold.html 的下拉框中增加:

<option value="5">空心矩形框</option>

在片元着色器原有 uMode == 3 分支后,保留旧的过渡模式为 uMode == 4,再增加新分支:

} else if ( uMode == 4 ) {
  mask = clamp( ( vUv.x - uThreshold ) * 4.0 + 0.5, 0.0, 1.0 );
} else if ( uMode == 5 ) {
  float outerX = step( 0.2, vUv.x ) - step( 0.8, vUv.x );
  float outerY = step( 0.2, vUv.y ) - step( 0.8, vUv.y );
  float innerX = step( 0.35, vUv.x ) - step( 0.65, vUv.x );
  float innerY = step( 0.35, vUv.y ) - step( 0.65, vUv.y );
  float outerMask = min( outerX, outerY );
  float innerMask = min( innerX, innerY );
  mask = outerMask - innerMask;
}

内矩形完全在外矩形内,因而相减不会得到负值。框内部为 1 - 0 = 1,中央为 1 - 1 = 0,框外为 0 - 0 = 0。这个方案的边界是硬边。

练习 3:由半宽控制线性过渡

继续在下拉框增加:

<option value="6">可调宽度的线性过渡</option>

接在上一题的 uMode == 5 分支后:

} else if ( uMode == 6 ) {
  float start = uThreshold - uHalfWidth;
  mask = clamp( ( vUv.x - start ) / ( 2.0 * uHalfWidth ), 0.0, 1.0 );
}

滑块的最小半宽为 0.02,分母始终大于 0。vUv.x == start 时结果为 0;到 uThreshold + uHalfWidth 时为 1;恰在 uThreshold 时为 0.5。示例末尾已有的 mix(darkColor, lightColor, mask) 完成颜色混合。如果独立完成本题,模式编号和分支位置可以不同,只需保证原模式仍可用。