Skip to main content

GLSL 编程作业清单

本文件包含所有章节的编程作业,帮助你通过实际编程来掌握 GLSL。

📋 作业说明

  • 难度等级:⭐ 简单 | ⭐⭐ 中等 | ⭐⭐⭐ 困难
  • 预计时间:每个作业建议在 30-60 分钟内完成
  • 提交方式:创建独立的 HTML 文件或使用你的项目环境运行代码

第一阶段:GLSL 语言基础

作业 01:环境搭建与第一个 Shader ⭐

章节01. GLSL 简介与环境搭建

任务

  1. 按照教程搭建原生 Three.js 环境
  2. 创建一个平面(PlaneGeometry),使用 RawShaderMaterial
  3. 实现一个简单的单色平面(比如蓝色)
  4. 添加一个 uTime uniform,让颜色随时间变化(比如 sin(uTime) 控制亮度)

要求

  • 必须使用 RawShaderMaterial(不能用 ShaderMaterial
  • 必须手动声明所有变量(precisionattributeuniform
  • 实现基本的渲染循环

扩展挑战

  • 让颜色在 RGB 三个通道上分别使用不同的时间函数(如 sin(uTime)cos(uTime * 0.5)

作业 02:类型系统与向量操作 ⭐

章节02. 基本数据类型与变量

任务

  1. 创建一个平面,使用 UV 坐标绘制图案
  2. 使用 vec2vec3vec4 进行颜色计算
  3. 实现以下效果(任选 2-3 个):
    • 使用 vec2xy 分量作为 RGB 的前两个通道
    • 使用 vec3 构造颜色,然后用 vec4 添加透明度
    • 使用 vec3(1.0) 创建白色,然后通过 swizzling 创建其他颜色

要求

  • 所有浮点数必须使用 .0 后缀
  • 不能混用 intfloat
  • 展示至少 3 种不同的向量构造方式

代码示例框架

// 片段着色器中
void main() {
vec2 uv = vUv;

// 任务 1:使用 vec2 的 xy 作为颜色
vec3 color1 = vec3(uv.xy, 0.5);

// 任务 2:使用 vec3 和 vec4
vec3 baseColor = vec3(1.0, 0.5, 0.0);
vec4 finalColor = vec4(baseColor, 1.0);

// 任务 3:使用 swizzling
vec3 white = vec3(1.0);
vec3 swapped = white.bgr; // 交换顺序

gl_FragColor = vec4(color1, 1.0);
}

作业 03:向量运算与几何函数 ⭐⭐

章节03. 向量与矩阵操作

任务

  1. 使用 distance()step() 绘制一个圆形
  2. 使用 length()normalize() 创建径向渐变
  3. 使用 dot() 创建方向性光照效果(模拟简单的 Lambert 光照)

要求

  • 圆形中心在屏幕中央,半径可调
  • 径向渐变从中心向外扩散
  • 光照效果需要计算法线(可以使用 normalize(vec3(vUv - 0.5, 0.0)) 作为简单法线)

提示

// 圆形
float d = distance(vUv, vec2(0.5));
float circle = step(d, 0.3); // 半径 0.3

// 径向渐变
float dist = length(vUv - vec2(0.5));
float gradient = 1.0 - dist * 2.0; // 从中心向外变暗

// 简单光照
vec3 normal = normalize(vec3(vUv - vec2(0.5), 0.1));
vec3 lightDir = normalize(vec3(0.5, 0.5, 1.0));
float light = dot(normal, lightDir);

作业 04:attribute、uniform、varying 实战 ⭐⭐

章节04. 输入输出变量

任务

  1. 创建一个立方体(BoxGeometry),在顶点着色器中修改顶点位置
  2. 使用 varying 将自定义数据从顶点着色器传递到片段着色器
  3. 实现以下效果:
    • 使用 uniform 控制立方体的颜色
    • 使用 attribute 读取顶点的 normal,通过 varying 传递到片段着色器
    • 在片段着色器中使用法线信息创建颜色渐变

要求

  • 必须显式声明所有 attributeuniformvarying
  • 在顶点着色器中修改顶点位置(比如添加 sin 波动)
  • 使用法线信息在片段着色器中创建视觉效果

扩展挑战

  • 添加一个 uniform vec3 uMouse,让颜色根据鼠标位置变化

作业 05:控制流与函数 ⭐

章节05. 着色器结构与控制流

任务

  1. 实现一个自定义函数,计算两个颜色的混合
  2. 使用 if-else 创建一个分区域的颜色效果
  3. 重要:将 if-else 改写为使用 step()mix() 的无分支版本
  4. 使用 for 循环创建重复图案(比如条纹)

要求

  • 自定义函数必须使用 inoutinout 修饰符
  • 展示 if-else 和数学函数两种实现方式
  • for 循环次数必须是编译时常量

代码示例

// 任务 1:自定义函数
vec3 mixColors(vec3 color1, vec3 color2, float t) {
return mix(color1, color2, t);
}

// 任务 2:if-else 版本
vec3 color;
if (vUv.x < 0.5) {
color = vec3(1.0, 0.0, 0.0); // 红色
} else {
color = vec3(0.0, 0.0, 1.0); // 蓝色
}

// 任务 3:无分支版本
vec3 color = mix(
vec3(1.0, 0.0, 0.0),
vec3(0.0, 0.0, 1.0),
step(0.5, vUv.x)
);

// 任务 4:for 循环创建条纹
float stripes = 0.0;
for (int i = 0; i < 5; i++) {
float stripe = step(0.5, fract(vUv.x * 10.0 + float(i) * 0.2));
stripes += stripe;
}

作业 06:内置函数综合应用 ⭐⭐

章节06. 常用内置函数详解

任务

  1. 使用 mix() 创建颜色渐变
  2. 使用 smoothstep() 创建平滑过渡的边缘
  3. 使用 fract() 创建重复的图案
  4. 使用 sin()cos() 创建波浪效果
  5. 组合多个函数创建一个复杂的视觉效果

要求

  • 必须使用 mixstepsmoothstepfract 至少各一次
  • 创建一个"综合展示"场景,展示所有效果

创意建议

  • 创建一个"函数画廊",屏幕分成多个区域,每个区域展示不同的函数效果
  • 或者创建一个随时间变化的动画,展示不同函数的组合效果

第二阶段:图形学核心原理

作业 07:理解插值 ⭐⭐

章节07. 从顶点到片段:插值的魔法

任务

  1. 创建一个三角形,三个顶点分别设置为红色、绿色、蓝色
  2. 观察中间区域的自动渐变效果
  3. 创建一个平面,在顶点着色器中为不同区域设置不同的 varying
  4. 在片段着色器中使用这些插值后的值创建渐变效果

要求

  • 必须使用 varying 变量传递数据
  • 展示至少 2 种不同的插值效果(颜色、数值等)
  • 理解为什么三角形中间的颜色是自动计算的

扩展挑战

  • 创建一个自定义的 varying float vElevation,在顶点着色器中根据位置计算高度,在片段着色器中使用高度值控制颜色

作业 08:实现完整的光照模型 ⭐⭐⭐

章节08. 光照模型实战:从 Lambert 到 Phong

任务

  1. 实现基础的 Lambert 漫反射光照
  2. 添加环境光
  3. 添加 Phong 镜面高光
  4. 可选:改进为 Blinn-Phong 模型

要求

  • 必须使用一个 3D 物体(如球体或立方体)
  • 需要正确计算和传递法线、位置、光线方向、视线方向
  • 所有向量必须归一化
  • 实现可交互的光源位置(通过 uniform 控制)

提示

  • 使用 SphereGeometryBoxGeometry
  • 在顶点着色器中计算世界空间位置和法线
  • 在片段着色器中计算所有光照分量

扩展挑战

  • 实现多光源支持
  • 添加阴影效果(高级)

第三阶段:Shader 编程实战

作业 09:第一个动态 Shader ⭐⭐

章节09. 实战:绘制第一个动态 Shader

任务: 参考教程中的"动态色彩波浪"效果,实现以下变体:

  1. 基础版本:实现教程中的波浪效果
  2. 改进版本:修改频率、振幅、方向
  3. 创意版本:添加你自己的创意元素

要求

  • 必须使用 uTime uniform 实现动画
  • 顶点着色器和片段着色器都要有动态效果
  • 代码结构清晰,有注释

创意建议

  • 改变波浪的方向(X、Y、对角线)
  • 添加多个频率的叠加
  • 改变颜色计算方式
  • 添加交互控制(鼠标位置影响效果)

作业 10:三大 WebGL 效果实战 ⭐⭐⭐

章节10. 进阶实战:三大常见 WebGL 效果

任务: 实现以下三个效果(每个效果单独完成):

效果 1:菲涅尔效果

  • 创建一个 3D 物体(球体或复杂模型)
  • 实现边缘发光效果
  • 边缘颜色和中心颜色可配置

效果 2:纹理流动

  • 加载一张纹理图片
  • 实现纹理的滚动动画
  • 可选:添加波浪扭曲效果

效果 3:噪声溶解

  • 实现基础的噪声函数
  • 创建溶解效果(物体逐渐消失)
  • 添加边缘发光(溶解边缘)

要求

  • 每个效果都要有完整的代码和注释
  • 效果参数可以通过 uniform 调整
  • 代码结构清晰,易于理解和修改

扩展挑战

  • 将三个效果组合在一起
  • 添加 GUI 控制面板(如 dat.GUI)

作业 11:屏幕后处理效果 ⭐⭐⭐

章节11. 后期处理艺术:屏幕后处理

任务: 使用 Three.js 的 EffectComposer 实现以下后处理效果:

  1. 灰度效果:将场景转换为黑白
  2. 晕影效果:边缘变暗
  3. 像素化效果:降低分辨率
  4. 色差效果:RGB 通道偏移

要求

  • 必须使用 EffectComposer 和自定义 ShaderPass
  • 每个效果都要可以单独开启/关闭
  • 效果参数可调节

提示

  • 使用 RenderPass 渲染场景
  • 使用 ShaderPass 实现后处理
  • 通过 uniform 控制效果强度

第四阶段:工程化与调试

作业 12:Shader 调试技巧 ⭐⭐

章节12. 调试技巧:像手术刀一样调试 Shader

任务

  1. 创建一个有问题的 Shader(故意引入错误)
  2. 使用可视化调试方法找出问题
  3. 修复问题并验证

常见错误类型

  • 变量未声明
  • 类型不匹配
  • 精度问题
  • 除零错误
  • 向量未归一化

要求

  • 展示至少 3 种不同的调试方法
  • 记录调试过程和解决方案
  • 总结调试经验

调试方法

  • 将中间值输出为颜色(如 gl_FragColor = vec4(vNormal, 1.0)
  • 使用 step() 创建调试网格
  • 逐步简化代码定位问题

作业 13:Three.js Shader 工程化 ⭐⭐⭐

章节13. Three.js 源码级解析:GLSL 的工程化艺术

任务

  1. 研究 Three.js 的 ShaderChunk 系统
  2. 使用 onBeforeCompile 修改内置材质
  3. 创建一个自定义的 Shader 模块系统

要求

  • 理解 ShaderChunk 的工作原理
  • 成功修改至少一个内置材质(如 MeshStandardMaterial
  • 创建可复用的 Shader 代码片段

提示

material.onBeforeCompile = (shader) => {
// 修改顶点着色器
shader.vertexShader = shader.vertexShader.replace(
'#include <worldpos_vertex>',
'#include <worldpos_vertex>\n' + customCode
);

// 添加自定义 uniform
shader.uniforms.uCustom = { value: 1.0 };
};

第五阶段:底层深造

作业 14:纯原生 WebGL ⭐⭐⭐

章节14. 进阶实战:纯原生 WebGL

任务: 不使用 Three.js,直接使用 WebGL API 绘制一个三角形。

要求

  1. 手动创建 WebGL 上下文
  2. 手动编写和编译 Shader
  3. 手动创建和绑定 Buffer
  4. 手动设置 vertexAttribPointer
  5. 手动调用 drawArrays

提示

  • 这是最底层的 WebGL 编程
  • 需要理解 WebGL 的完整流程
  • 代码会比较冗长,但能深刻理解底层原理

作业 15:综合项目 ⭐⭐⭐

章节:综合所有知识

任务: 创建一个完整的 Shader 项目,包含以下特性:

  1. 多个 Shader 效果:至少实现 3 种不同的效果
  2. 交互控制:鼠标或键盘控制参数
  3. 性能优化:注意 Draw Call 和 Shader 复杂度
  4. 代码质量:清晰的注释和结构

项目建议

  • Shader 画廊:展示多个 Shader 效果
  • 交互式 Shader 编辑器:实时修改 Shader 代码
  • 3D 场景:包含光照、后处理等完整效果

📝 作业提交建议

  1. 代码规范:使用清晰的变量命名,添加注释
  2. 文档说明:每个作业附上简短的说明文档
  3. 效果展示:提供截图或 GIF 动画
  4. 问题记录:记录遇到的问题和解决方案

🎯 学习路径建议

  • 初学者:完成 ⭐ 和 ⭐⭐ 的作业
  • 进阶学习者:完成所有 ⭐⭐ 和部分 ⭐⭐⭐ 的作业
  • 专家级:完成所有作业,并尝试扩展挑战

祝你学习愉快!通过实际编程,GLSL 会变得不再神秘! 🚀