第 6 章练习:取整与重复图案

对应教程:06 floor、ceil、fract 与重复图案
起始示例:UV 重复与取整,修改 06-repeat.js 和需要时的 06-repeat.html。

练习 1:手算单元编号和局部位置

设 uRepeat = 4.0,某片元 vUv = vec2(0.37, 0.62)。

**目标:**分别计算 grid、cell = floor(grid)、localUv = fract(grid)。再计算单个数值 -0.2 的 floor、ceil 和 fract。

**完成标准:**能说明哪个结果用于识别单元,哪个结果用于在单元内部画图案,并正确处理负数。

练习 2:棋盘格改成横条

**目标:**让同一行的所有单元颜色相同,相邻行交替变色。

**要求:**只修改棋盘格模式中 parity 的表达式,不改动颜色和 mix。

**完成标准:**改变重复次数后,横向仍不交替,纵向依次交替。

练习 3:每个单元画一个小方块

**目标:**新增模式:每个重复单元的中央 0.25~0.75 区域为亮色,其余为暗色。

**要求:**使用 localUv,而非原始 vUv,用第 4 章的 step 组合方形遮罩;新增一个模式选项。

**完成标准:**每个单元都有相同位置、相同大小的亮色方块;改变重复次数只改变方块数量。

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

先对 localUv.x 求一条宽为 0.5 的带,再对 localUv.y 做同样的事。

</details>

练习 4:隔行错位的棋盘格

**目标:**新增模式:仍然让单元交替着色,但每隔一行把竖向单元边界水平错开半个单元。

**要求:**先从原始 cell.y 求行奇偶,再在计算该行的列号前偏移 grid.x。

**完成标准:**偶数行边界与原棋盘格相同;奇数行的竖向边界相对移动半个单元,颜色仍交替。

参考解答


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

第 6 章练习参考解答

对应练习:取整与重复图案。

练习 1:手算单元编号和局部位置

grid    = (0.37, 0.62) * 4.0 = (1.48, 2.48)
cell    = floor(grid)        = (1.0, 2.0)
localUv = fract(grid)        = (0.48, 0.48)

floor(-0.2) = -1.0
ceil(-0.2)  =  0.0
fract(-0.2) =  0.8

cell 是从 0 开始的单元编号,localUv 是当前单元内的位置。负数的 floor 向更小的整数走,所以不是 0。

练习 2:棋盘格改成横条

棋盘格分支中的行改为:

float parity = mod( cell.y, 2.0 );

不再使用 cell.x,横向所有单元保持同色;每往上一行,cell.y 加 1,颜色翻转。

练习 3:每个单元画一个小方块

在 06-repeat.html 的下拉框中增加:

<option value="4">每格一个方块</option>

保留原有的 uMode == 0、1、2 分支,把最后的 else 改成 else if (uMode == 3),然后增加:

} else if ( uMode == 4 ) {
  float bandX = step( 0.25, localUv.x ) - step( 0.75, localUv.x );
  float bandY = step( 0.25, localUv.y ) - step( 0.75, localUv.y );
  float square = min( bandX, bandY );
  color = mix( vec3( 0.04, 0.14, 0.28 ), vec3( 0.9, 0.7, 0.35 ), square );
}

关键是从每个单元重新归零的 localUv 上取阈值。若用 vUv,只会在整个平面上画一个方块。

练习 4:隔行错位的棋盘格

再给下拉框增加:

<option value="5">错位棋盘格</option>

接在上一题新分支后:

} else if ( uMode == 5 ) {
  float oddRow = mod( cell.y, 2.0 );
  float shiftedColumn = floor( grid.x + 0.5 * oddRow );
  float parity = mod( shiftedColumn + cell.y, 2.0 );
  color = mix( vec3( 0.04, 0.14, 0.28 ), vec3( 0.9, 0.7, 0.35 ), parity );
}

偶数行 oddRow = 0.0,列号仍是 floor(grid.x);奇数行先偏移 grid.x 半个单元,再求列号,于是边界错开。单元右端的 vUv == 1.0 正好落在边界上,最外缘一条像素可能呈现下一单元的颜色;这不影响内部规律。