第 1 章练习:Three.js 提供的变量

对应教程:01 Three.js 怎样把数据交给 Shader
起始示例:内置变量可视化,修改 01-builtins.js,必要时修改 01-builtins.html。

请在浏览器中打开示例,并在自己的副本中修改代码。每次只做一道题,观察画面后再继续。

练习 1:交换 UV 对应的颜色

目标:“UV”模式中,红色随 vUv.y 变化,绿色随 vUv.x 变化,蓝色保持 0.25。

**要求:**只修改片元着色器中 uMode == 0 的颜色表达式;保留顶点着色器中的 vUv = uv。

**完成标准:**球体上的红、绿渐变方向与原示例互换;其他模式不变。

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

vec3 构造函数的前两个参数分别对应红、绿通道。

</details>

练习 2:显示到相机的距离

**目标:**增加一个“相机距离”模式:靠近相机的位置更亮,远离相机的位置更暗。

**要求:**新增一个下拉选项;在片元着色器中使用内置 cameraPosition 和已有的 vWorldPosition,把距离映射成灰度。不要把 cameraPosition 与局部空间 position 直接相减。

**完成标准:**切换到新模式后,移动相机或模型会使亮度分布改变;现有五个模式仍可用。

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

两个世界空间位置相减得到方向向量。可以用 length 求其长度,再把较大的距离映射到较小的灰度值。

</details>

练习 3:验证两种矩阵写法

**目标:**把顶点着色器计算 gl_Position 的表达式改用 modelViewMatrix。

**要求:**只改变 gl_Position 的赋值,保留 worldPosition,因为“世界位置”模式仍需要它。

**完成标准:**移动模型和相机时,球体仍出现在与原示例相同的位置,五种原有可视化模式仍可用。

参考解答


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

第 1 章练习参考解答

对应练习:Three.js 提供的变量。以下改动应用于起始示例的对应位置。

练习 1:交换 UV 对应的颜色

在 01-builtins.js 的片元着色器中,把 UV 分支改为:

if ( uMode == 0 ) {
  color = vec3( vUv.y, vUv.x, 0.25 );
}

红色使用 vUv.y,绿色使用 vUv.x。只改变了片元阶段的显示方式,几何体原有的 UV 未改变。

练习 2:显示到相机的距离

在 01-builtins.html 的下拉框中增加:

<option value="5">相机距离</option>

在 01-builtins.js 的片元着色器中,保留原有分支,把最后的 else 改为:

} else if ( uMode == 4 ) {
  color = vWorldPosition * 0.25 + 0.5;
} else {
  float distanceToCamera = length( cameraPosition - vWorldPosition );
  float gray = 1.0 - distanceToCamera / 6.0;
  color = vec3( gray );
}

cameraPosition 和 vWorldPosition 都属于世界空间,可以相减。length 得到两点之间的距离;1.0 - distance / 6.0 让距离越大,灰度越小。这里的 6.0 是本场景选定的显示尺度,在当前控件范围内可保持灰度可见。改变它可使明暗变化更快或更慢;若场景扩大,灰度可能超出 0.0~1.0,第 4 章会用 clamp 处理。

练习 3:验证两种矩阵写法

把顶点着色器最后一行改为:

gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

原式 projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0) 对这个普通网格与新式等价。vWorldPosition 的计算仍保留,因为片元着色器要显示世界位置及相机距离。将新旧代码分别运行并移动滑块,可以检查球体的屏幕位置没有变化。