# 实验二实现与验证说明

## 1. 数据更新策略

Task A 的 Level 改变会导致三角形数量和顶点数组变化，因此重新生成数组并用 `bufferData` 上传；颜色仅是片元着色器的 `uColor`，改变颜色时无需改变几何数据。当前实现为保持事件流程统一，颜色事件也调用 `render()`，但几何与颜色在概念上仍是两类状态。

Task B 使用 `LINE_LOOP`。缓冲区只保存每条连续线段的起点，共 `3×4^n` 个顶点；WebGL 自动连接相邻点并把末点连回首点。Level 0—4 的结果为 3、12、48、192、768，增长率和计算量均为 `O(4^n)`。

## 2. Koch 外凸方向

初始三角形按逆时针顺序排列，轮廓内部位于每条有向边左侧，外侧位于右侧。于是将向量 `Q-P` 旋转 `-60°`：

```text
R.x = P.x + cos60°·dx + sin60°·dy
R.y = P.y - sin60°·dx + cos60°·dy
```

每段按 `A→P、P→R、R→Q、Q→B` 递归，终止时输出起点，可保持连续顺序。

## 3. 动画状态

Task C 的顶点 Buffer 在初始化时上传一次。每帧只根据时间差更新 `theta`，再上传 `uTheta` 并重绘。`speed` 决定角速度，`direction` 取 `1/-1`，`paused` 决定是否累加角度。若重复启动多个 rAF 链，角度会被多次更新并造成转速异常；本实现只有一个从初始化开始的动画链。

## 4. 交互绘图板

鼠标 `clientX/clientY` 是窗口 CSS 坐标，不能直接作为 NDC。实现先减去 Canvas 边界，再按 Canvas 内部像素尺寸缩放，最后映射到 `[-1,1]` 并翻转 Y 轴。线段和矩形必须跨两次点击保存 `firstPoint`；工具切换和清空都会取消该状态。

JavaScript 端保存 `objects`，因为对象类型、颜色和语义不适合只从 GPU 顶点反推。这样以后增加撤销、选择、删除也更直接。对象变化后，本实现重新上传当前对象顶点并按 `POINTS/LINES/LINE_LOOP` 绘制，逻辑清楚且本实验数据量很小。

## 5. 主题作品

“节律星轨”复用 Koch 递归、uniform 旋转和鼠标 NDC 定位。独立新增三层同心轨道、辐射连接线与节点、三枚运动标志点。Level 改变几何量；尺度、脉冲强度、点击定位、开始/暂停和反向均会改变画面或程序状态。

## 6. 验收记录

- A：Level 1 为 3 个三角形/9 个顶点；Level 4 为 81 个三角形/243 个顶点，颜色控件即时更新。
- B：Level 0、1、2、4 的线段数为 3、12、48、768，图形连续闭合且外凸。
- C：暂停时角度不变；反向后角度变化符号相反；速度 0 时保持静止。
- D：点、线、矩形可共存；四角和中心点击方向正确；切换工具会清除半成品；清空后对象数为 0。
- E：初始与交互后画面均包含至少三类新增几何；点击、脉冲和旋转控件均有效。
