第 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 的计算仍保留,因为片元着色器要显示世界位置及相机距离。将新旧代码分别运行并移动滑块,可以检查球体的屏幕位置没有变化。