shadertoy
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseShadertoy Shader Development
Shadertoy 着色器开发
Overview
概述
Shadertoy is a platform for creating and sharing GLSL fragment shaders that run in the browser using WebGL. This skill provides comprehensive guidance for writing shaders including GLSL ES syntax, common patterns, mathematical techniques, and best practices specific to real-time procedural graphics.
Shadertoy是一个用于创建和分享GLSL片段着色器的平台,这些着色器可通过WebGL在浏览器中运行。本技能为编写着色器提供全面指导,包括GLSL ES语法、常见模式、数学技巧,以及实时过程化图形的最佳实践。
When to Use This Skill
适用场景
Activate this skill when:
- Writing or editing shader files
.glsl - Creating procedural graphics, generative art, or visual effects
- Working with Shadertoy.com projects or WebGL fragment shaders
- Implementing ray marching, distance fields, or procedural textures
- Debugging shader code or optimizing shader performance
- Need GLSL ES syntax reference or Shadertoy input variables
在以下场景中启用该技能:
- 编写或编辑着色器文件
.glsl - 创建过程化图形、生成式艺术或视觉效果
- 处理Shadertoy.com项目或WebGL片段着色器
- 实现光线步进、距离场或过程化纹理
- 调试着色器代码或优化着色器性能
- 需要GLSL ES语法参考或Shadertoy输入变量
Core Concepts
核心概念
Shader Entry Point
着色器入口点
Every Shadertoy shader implements the function:
mainImageglsl
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
// fragCoord: pixel coordinates (0 to iResolution.xy)
// fragColor: output color (RGBA, typically alpha = 1.0)
vec2 uv = fragCoord / iResolution.xy;
fragColor = vec4(uv, 0.0, 1.0);
}每个Shadertoy着色器都需要实现函数:
mainImageglsl
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
// fragCoord: pixel coordinates (0 to iResolution.xy)
// fragColor: output color (RGBA, typically alpha = 1.0)
vec2 uv = fragCoord / iResolution.xy;
fragColor = vec4(uv, 0.0, 1.0);
}Shadertoy Built-in Inputs
Shadertoy内置输入变量
Always available in shaders:
| Type | Name | Description |
|---|---|---|
| | Viewport resolution (x, y, aspect ratio) |
| | Current time in seconds (primary animation driver) |
| | Time to render one frame |
| | Current frame number |
| | Mouse: xy = current position, zw = click position |
| | Input textures/buffers |
| | Resolution of each input channel |
| | Year, month, day, time in seconds (.xyzw) |
着色器中始终可用的内置变量:
| 类型 | 名称 | 描述 |
|---|---|---|
| | 视口分辨率(x, y, 宽高比) |
| | 当前时间(秒,主要动画驱动变量) |
| | 单帧渲染耗时 |
| | 当前帧编号 |
| | 鼠标:xy为当前位置,zw为点击位置 |
| | 输入纹理/缓冲区 |
| | 每个输入通道的分辨率 |
| | 年、月、日、秒级时间(.xyzw) |
Coordinate System Setup
坐标系设置
Standard patterns for normalizing coordinates:
glsl
// Aspect-corrected UV centered at origin (-1 to 1, aspect-preserved)
vec2 uv = (fragCoord.xy - 0.5 * iResolution.xy) / min(iResolution.y, iResolution.x);
// Alternative compact form:
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / min(iResolution.x, iResolution.y);
// Simple normalized (0 to 1)
vec2 uv = fragCoord / iResolution.xy;标准化坐标的常用模式:
glsl
// 校正宽高比的UV,以原点为中心(范围-1到1,保持宽高比)
vec2 uv = (fragCoord.xy - 0.5 * iResolution.xy) / min(iResolution.y, iResolution.x);
// 简化写法:
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / min(iResolution.x, iResolution.y);
// 基础标准化(范围0到1)
vec2 uv = fragCoord / iResolution.xy;Common Shader Patterns
常见着色器模式
1. Procedural Color Palettes
1. 过程化调色板
Use Inigo Quilez's cosine palette for smooth color gradients:
glsl
vec3 palette(float t, vec3 a, vec3 b, vec3 c, vec3 d) {
return a + b * cos(6.28318 * (c * t + d));
}
// Example usage:
vec3 col = palette(
t,
vec3(0.5, 0.5, 0.5), // base
vec3(0.5, 0.5, 0.5), // amplitude
vec3(1.0, 1.0, 0.5), // frequency
vec3(0.8, 0.90, 0.30) // phase
);使用Inigo Quilez的余弦调色板实现平滑颜色渐变:
glsl
vec3 palette(float t, vec3 a, vec3 b, vec3 c, vec3 d) {
return a + b * cos(6.28318 * (c * t + d));
}
// 示例用法:
vec3 col = palette(
t,
vec3(0.5, 0.5, 0.5), // base
vec3(0.5, 0.5, 0.5), // amplitude
vec3(1.0, 1.0, 0.5), // frequency
vec3(0.8, 0.90, 0.30) // phase
);2. Hash Functions (Pseudo-Random)
2. 哈希函数(伪随机)
Simple 2D hash for noise and randomness:
glsl
float hash21(vec2 p) {
p = fract(p * vec2(234.34, 435.345));
p += dot(p, p + 34.23);
return fract(p.x * p.y);
}用于噪声和随机效果的简单2D哈希函数:
glsl
float hash21(vec2 p) {
p = fract(p * vec2(234.34, 435.345));
p += dot(p, p + 34.23);
return fract(p.x * p.y);
}3. Ray Marching
3. 光线步进
Standard pattern for 3D rendering via sphere tracing:
glsl
// Distance field function
float map(vec3 p) {
return length(p) - 1.0; // Sphere at origin, radius 1
}
// Normal calculation
vec3 calcNormal(vec3 p) {
vec2 e = vec2(0.001, 0.0);
return normalize(vec3(
map(p + e.xyy) - map(p - e.xyy),
map(p + e.yxy) - map(p - e.yxy),
map(p + e.yyx) - map(p - e.yyx)
));
}
// Ray marching loop
vec3 render(vec3 ro, vec3 rd) {
float t = 0.0;
for (int i = 0; i < 100; i++) {
vec3 p = ro + rd * t;
float d = map(p);
if (d < 0.001) {
// Hit - calculate lighting
vec3 n = calcNormal(p);
return n * 0.5 + 0.5; // Normal visualization
}
if (t > 10.0) break;
t += d * 0.5; // Step (0.5 factor for safety)
}
return vec3(0.0); // Miss
}通过球体追踪实现3D渲染的标准模式:
glsl
// 距离场函数
float map(vec3 p) {
return length(p) - 1.0; // Sphere at origin, radius 1
}
// 法线计算
vec3 calcNormal(vec3 p) {
vec2 e = vec2(0.001, 0.0);
return normalize(vec3(
map(p + e.xyy) - map(p - e.xyy),
map(p + e.yxy) - map(p - e.yxy),
map(p + e.yyx) - map(p - e.yyx)
));
}
// 光线步进循环
vec3 render(vec3 ro, vec3 rd) {
float t = 0.0;
for (int i = 0; i < 100; i++) {
vec3 p = ro + rd * t;
float d = map(p);
if (d < 0.001) {
// Hit - calculate lighting
vec3 n = calcNormal(p);
return n * 0.5 + 0.5; // Normal visualization
}
if (t > 10.0) break;
t += d * 0.5; // Step (0.5 factor for safety)
}
return vec3(0.0); // Miss
}4. Rotations
4. 旋转
2D rotation:
glsl
mat2 rot2d(float a) {
float c = cos(a), s = sin(a);
return mat2(c, -s, s, c);
}
// Usage: p.xy *= rot2d(iTime);3D axis-angle rotation (modifies in-place):
glsl
void rot(inout vec3 p, vec3 axis, float angle) {
axis = normalize(axis);
float s = sin(angle), c = cos(angle), oc = 1.0 - c;
mat3 m = mat3(
oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c
);
p = m * p;
}2D旋转:
glsl
mat2 rot2d(float a) {
float c = cos(a), s = sin(a);
return mat2(c, -s, s, c);
}
// Usage: p.xy *= rot2d(iTime);3D轴角旋转(原地修改):
glsl
void rot(inout vec3 p, vec3 axis, float angle) {
axis = normalize(axis);
float s = sin(angle), c = cos(angle), oc = 1.0 - c;
mat3 m = mat3(
oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c
);
p = m * p;
}5. Domain Repetition and Folding
5. 域重复与折叠
Create fractal-like structures:
glsl
vec3 foldRotate(vec3 p, float timeOffset) {
for (int i = 0; i < 5; i++) {
p = abs(p); // Mirror fold
rot(p, vec3(0.707, 0.707, 0.0), 0.785);
p -= 0.5; // Translate
}
return p;
}创建分形结构:
glsl
vec3 foldRotate(vec3 p, float timeOffset) {
for (int i = 0; i < 5; i++) {
p = abs(p); // Mirror fold
rot(p, vec3(0.707, 0.707, 0.0), 0.785);
p -= 0.5; // Translate
}
return p;
}6. Post-Processing
6. 后期处理
Vignette:
glsl
float vignette(vec2 uv) {
uv *= 1.0 - uv.yx;
return pow(uv.x * uv.y * 15.0, 0.25);
}Film grain/dithering (reduces banding):
glsl
float dither = hash21(fragCoord + iTime) * 0.001;
finalCol += dither;Gamma correction:
glsl
finalCol = pow(finalCol, vec3(0.45)); // ~1/2.2暗角效果:
glsl
float vignette(vec2 uv) {
uv *= 1.0 - uv.yx;
return pow(uv.x * uv.y * 15.0, 0.25);
}胶片颗粒/抖动(减少色带):
glsl
float dither = hash21(fragCoord + iTime) * 0.001;
finalCol += dither;伽马校正:
glsl
finalCol = pow(finalCol, vec3(0.45)); // ~1/2.2Multi-Pass Rendering
多通道渲染
For complex effects requiring temporal feedback or multiple rendering stages:
适用于需要时间反馈或多渲染阶段的复杂效果:
Buffer A (Computation):
缓冲区A(计算):
glsl
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
// Generate or compute values
fragColor = vec4(computedColor, 1.0);
}glsl
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
// Generate or compute values
fragColor = vec4(computedColor, 1.0);
}Buffer B (Feedback/Blending):
缓冲区B(反馈/混合):
glsl
#define BUFFER_A iChannel0
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
vec4 current = texture(BUFFER_A, uv);
vec4 previous = texture(iChannel1, uv); // Self-reference
fragColor = mix(previous, current, 0.1); // Temporal blend
}glsl
#define BUFFER_A iChannel0
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
vec4 current = texture(BUFFER_A, uv);
vec4 previous = texture(iChannel1, uv); // Self-reference
fragColor = mix(previous, current, 0.1); // Temporal blend
}Main (Final Output):
主通道(最终输出):
glsl
#define BUFFER_B iChannel1
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
fragColor = texture(BUFFER_B, uv);
}glsl
#define BUFFER_B iChannel1
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
fragColor = texture(BUFFER_B, uv);
}Critical GLSL ES Rules
GLSL ES 关键规则
ALWAYS follow these rules to avoid compilation errors:
- NO suffix: Use
fNOT1.01.0f - NO : Use
saturate()insteadclamp(x, 0.0, 1.0) - Protect pow/sqrt: Wrap arguments: ,
pow(max(x, 0.0), p)sqrt(abs(x)) - Avoid division by zero: Check denominators or add epsilon
- Initialize variables: Don't assume default values
- Avoid name conflicts: Don't name functions like variables
- NO interactive commands: Avoid ,
find- use Glob/Grep tools insteadgrep
必须遵守以下规则以避免编译错误:
- 禁止后缀:使用
f而非1.01.0f - 无函数:改用
saturate()clamp(x, 0.0, 1.0) - 保护pow/sqrt函数:对参数进行包裹:、
pow(max(x, 0.0), p)sqrt(abs(x)) - 避免除零:检查分母或添加极小值(epsilon)
- 初始化变量:不要依赖默认值
- 避免命名冲突:函数名与变量名不可重复
- 无交互命令:避免使用、
find,改用Glob/Grep工具grep
Workflow Guide
工作流指南
Creating a New Shader
创建新着色器
- Set up coordinate system - Choose appropriate UV normalization
- Define core effect - Implement main visual algorithm
- Add animation - Use for temporal variation
iTime - Apply color palette - Use cosine palette or custom scheme
- Add post-processing - Vignette, dither, gamma correction
- Optimize - Reduce iterations, use early exits, minimize branches
- 设置坐标系 - 选择合适的UV标准化方式
- 定义核心效果 - 实现主要视觉算法
- 添加动画 - 使用实现时间变化效果
iTime - 应用调色板 - 使用余弦调色板或自定义配色方案
- 添加后期处理 - 暗角、抖动、伽马校正
- 优化性能 - 减少迭代次数、使用提前退出、最小化分支判断
Common Tasks
常见任务
Visualizing complex numbers:
- Use the complex math functions in
references/common-patterns.md - Plot with ,
cx_log(), or polynomial evaluationcx_pow() - Map complex results to color via palette
Ray marching 3D scenes:
- Define distance field in function
map() - Set up camera (ray origin , ray direction
ro)rd - March using standard loop pattern
- Calculate normals with tetrahedron method
- Apply lighting and material properties
Creating noise/organic effects:
- Use for random values
hash21() - Implement (fractional Brownian motion) for natural variation
fbm() - Combine with /
sin()for structured patternscos() - Apply domain warping for organic distortion
Multi-layer composition:
- Render multiple passes with different parameters
- Blend layers using or custom blend modes
mix() - Add interference patterns by comparing layer differences
- Use for soft transitions
smoothstep()
复数可视化:
- 使用中的复数数学函数
references/common-patterns.md - 通过、
cx_log()或多项式求值进行绘图cx_pow() - 通过调色板将复数结果映射为颜色
3D场景光线步进:
- 在函数中定义距离场
map() - 设置相机(射线起点、射线方向
ro)rd - 使用标准循环模式进行光线步进
- 用四面体法计算法线
- 应用光照和材质属性
创建噪声/有机效果:
- 使用生成随机值
hash21() - 实现(分形布朗运动)模拟自然变化
fbm() - 结合/
sin()创建结构化图案cos() - 应用域扭曲实现有机变形
多层合成:
- 使用不同参数渲染多通道
- 通过或自定义混合模式融合图层
mix() - 通过比较图层差异添加干涉图案
- 使用实现柔和过渡
smoothstep()
Debugging Strategies
调试策略
Visualize intermediate values:
glsl
fragColor = vec4(vec3(distanceField), 1.0); // Show distance
fragColor = vec4(normal * 0.5 + 0.5, 1.0); // Show normals
fragColor = vec4(fract(uv), 0.0, 1.0); // Show UV tilingSimplify progressively:
- Comment out post-processing
- Reduce iteration counts
- Replace complex functions with simple placeholders
- Check coordinate transformations step-by-step
Check for NaN/Inf:
- Add guards:
if (isnan(value) || isinf(value)) return vec3(1.0, 0.0, 0.0); - Validate divisions and roots
可视化中间值:
glsl
fragColor = vec4(vec3(distanceField), 1.0); // Show distance
fragColor = vec4(normal * 0.5 + 0.5, 1.0); // Show normals
fragColor = vec4(fract(uv), 0.0, 1.0); // Show UV tiling逐步简化:
- 注释掉后期处理代码
- 减少迭代次数
- 用简单占位符替换复杂函数
- 逐步检查坐标变换逻辑
检查NaN/Inf值:
- 添加防护:
if (isnan(value) || isinf(value)) return vec3(1.0, 0.0, 0.0); - 验证除法和开根操作
Performance Optimization
性能优化
- Fixed iteration counts - Avoid dynamic loops
- Early exit conditions - Break when threshold met
- Step multiplier tuning - Balance quality vs speed (0.5 to 1.0)
- Minimize texture reads - Cache repeated lookups
- Avoid conditionals - Use ,
mix(),step()instead ofsmoothstep()if - Reduce precision - Use or
mediumpwhere appropriate (mobile)lowp
- 固定迭代次数 - 避免动态循环
- 提前退出条件 - 达到阈值时终止循环
- 调整步长系数 - 平衡画质与速度(范围0.5到1.0)
- 减少纹理读取 - 缓存重复查找结果
- 避免条件判断 - 用、
mix()、step()替代smoothstep()if - 降低精度 - 在移动端适当使用或
mediumplowp
Naming Conventions
命名规范
Based on observed patterns in creative work:
- Poetic/evocative names - "alien-water", "heavenly-wisp", "comprehension"
- Technical descriptors - "complex-plot", "noise-circuits", "ray-marching-demo"
- Compound phrases - "coming-apart-at-the-seams", "form-without-form"
- Lowercase with hyphens -
my-shader-name.glsl
基于创意作品中的常见模式:
- 诗意/唤起式名称 - "alien-water", "heavenly-wisp", "comprehension"
- 技术描述性名称 - "complex-plot", "noise-circuits", "ray-marching-demo"
- 复合短语 - "coming-apart-at-the-seams", "form-without-form"
- 小写连字符格式 -
my-shader-name.glsl
Attribution and Forking
署名与复刻
When forking or remixing shaders:
glsl
// Fork of "Original Name" by AuthorName. https://shadertoy.com/view/XxXxXx
// Date: YYYY-MM-DD
// License: Creative Commons (CC BY-NC-SA 4.0) [or other]复刻或修改着色器时:
glsl
// Fork of "Original Name" by AuthorName. https://shadertoy.com/view/XxXxXx
// Date: YYYY-MM-DD
// License: Creative Commons (CC BY-NC-SA 4.0) [or other]Resources
资源
references/glsl-reference.md
references/glsl-reference.md
Complete GLSL ES syntax reference including:
- Built-in functions (trig, math, vectors, matrices, textures)
- Shadertoy input variables specification
- Type conversions and swizzling
- Common pitfalls and corrections
Search with: for complete language reference.
Read /references/glsl-reference.md完整的GLSL ES语法参考,包括:
- 内置函数(三角函数、数学函数、向量、矩阵、纹理)
- Shadertoy输入变量规范
- 类型转换与分量选择
- 常见陷阱与修正方法
可通过以下命令查看: 获取完整语言参考。
Read /references/glsl-reference.mdreferences/common-patterns.md
references/common-patterns.md
Comprehensive pattern library including:
- Complex number mathematics (cx_mul, cx_div, cx_sin, cx_cos, cx_log, cx_pow)
- Color palette functions (cosine palette, multi-layer palettes)
- Hash functions (hash21, PCG hash)
- Ray marching templates (render loop, normal calculation)
- 3D transformations (rotations, domain folding)
- Distance fields (sphere, box, octahedron)
- Noise functions (simplex, FBM)
- Post-processing (vignette, blur, film grain, gamma)
- Blend modes (soft light, hard light, vivid light)
- Multi-pass rendering patterns
Search with: for specific techniques.
Grep "pattern" references/common-patterns.md全面的模式库,包括:
- 复数数学(cx_mul, cx_div, cx_sin, cx_cos, cx_log, cx_pow)
- 调色板函数(余弦调色板、多层调色板)
- 哈希函数(hash21, PCG hash)
- 光线步进模板(渲染循环、法线计算)
- 3D变换(旋转、域折叠)
- 距离场(球体、立方体、八面体)
- 噪声函数( simplex噪声、FBM)
- 后期处理(暗角、模糊、胶片颗粒、伽马校正)
- 混合模式(柔光、强光、艳光)
- 多通道渲染模式
可通过以下命令搜索: 查找特定技术。
Grep "pattern" references/common-patterns.mdreferences/example-compact-shader.glsl
references/example-compact-shader.glsl
Reference implementation showing:
- Compact, algorithmic shader coding style
- Efficient ray marching in minimal code
- Advanced matrix operations and transformations
- Creative Commons licensed example
参考实现示例,展示:
- 简洁的算法风格着色器编码
- 高效的极简代码光线步进
- 高级矩阵运算与变换
- 知识共享许可示例
Quick Reference
快速参考
glsl
#define PI 3.1415926535897932384626433832795
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
// 1. Normalize coordinates
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / min(iResolution.x, iResolution.y);
// 2. Compute effect
float d = length(uv) - 0.5; // Circle distance field
vec3 col = vec3(smoothstep(0.01, 0.0, d)); // Sharp edge
// 3. Animate with time
col *= 0.5 + 0.5 * sin(iTime + uv.xyx * 3.0);
// 4. Apply palette
col = palette(col.x, vec3(0.5), vec3(0.5), vec3(1.0), vec3(0.0));
// 5. Post-process
col = pow(col, vec3(0.45)); // Gamma
col *= vignette(fragCoord / iResolution.xy);
// 6. Output
fragColor = vec4(col, 1.0);
}glsl
#define PI 3.1415926535897932384626433832795
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
// 1. Normalize coordinates
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / min(iResolution.x, iResolution.y);
// 2. Compute effect
float d = length(uv) - 0.5; // Circle distance field
vec3 col = vec3(smoothstep(0.01, 0.0, d)); // Sharp edge
// 3. Animate with time
col *= 0.5 + 0.5 * sin(iTime + uv.xyx * 3.0);
// 4. Apply palette
col = palette(col.x, vec3(0.5), vec3(0.5), vec3(1.0), vec3(0.0));
// 5. Post-process
col = pow(col, vec3(0.45)); // Gamma
col *= vignette(fragCoord / iResolution.xy);
// 6. Output
fragColor = vec4(col, 1.0);
}Common Shader Types in Collection
集合中的常见着色器类型
- Mathematical Visualizations - Complex number plots, function graphs
- Ray Marched 3D - Distance field rendering, folded geometries
- Procedural Textures - Noise-based patterns, organic effects
- Multi-Pass Effects - Temporal feedback, buffer composition
- Particle Systems - Point-based simulations
- 2D Patterns - Geometric, kaleidoscopic, interference effects
- 数学可视化 - 复数绘图、函数图像
- 光线步进3D - 距离场渲染、折叠几何体
- 过程化纹理 - 噪声图案、有机效果
- 多通道效果 - 时间反馈、缓冲区合成
- 粒子系统 - 基于点的模拟
- 2D图案 - 几何、万花筒、干涉效果
Tips for Creative Coding
创意编码技巧
- Start simple - Get basic structure working, then iterate
- Use time creatively - ,
sin(iTime),mod(iTime, period)transitionssmoothstep() - Layer effects - Combine multiple techniques for richness
- Embrace accidents - Bugs often lead to interesting visuals
- Study references - Learn from existing shaders, understand techniques
- Optimize later - Prioritize visual quality first, then performance
- 从简入手 - 先实现基础结构,再逐步迭代
- 创意运用时间变量 - 、
sin(iTime)、mod(iTime, period)过渡smoothstep() - 叠加效果 - 结合多种技术丰富视觉层次
- 拥抱意外 - 错误往往能带来有趣的视觉效果
- 参考学习 - 研究现有着色器,理解其技术原理
- 先优化效果再优化性能 - 优先保证视觉质量,再进行性能优化