第2.2章:GLSL基础语法
GLSL(OpenGL Shading Language)是专为图形计算设计的着色器语言,它包含针对向量和矩阵操作的特性,使渲染管线具有可编程性。本章将详细介绍在Cocos Creator Shader开发中常用的GLSL语法知识。
🎯 学习目标
通过本章学习,你将掌握:
- GLSL变量类型和数据结构
- 控制流程语句的使用
- 函数定义和调用方法
- 存储限定符的作用和用法
- 精度限定符的设置和优化
- 预处理宏定义的高级技巧
📊 变量和数据类型
基本数据类型
GLSL支持多种数据类型,每种都有其特定的用途和默认值:
变量类型 | 说明 | 默认值 | Cocos Shader可选项 |
---|
bool | 布尔型标志 | false | ✓ |
int/ivec2/ivec3/ivec4 | 整型向量(1-4维) | 0/[0,0]/[0,0,0]/[0,0,0,0] | ✓ |
float/vec2/vec3/vec4 | 浮点型向量(1-4维) | 0.0/[0,0]/[0,0,0]/[0,0,0,0] | ✓ |
sampler2D | 2D纹理采样器 | default | black, grey, white, normal, default |
samplerCube | 立方体纹理采样器 | default-cube | black-cube, white-cube, default-cube |
mat2/mat3/mat4 | 矩阵(2x2/3x3/4x4) | 单位矩阵 | ✓ |
标量操作
标量的构造和操作与C语言类似:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| float timeValue = 1.0; float speed = 2.5;
int count = 10; int maxItems = 100;
bool isVisible = true; bool hasTexture = false;
float result = timeValue * speed + 1.0; bool condition = count < maxItems;
|
向量操作详解
向量是GLSL中最重要的数据类型,支持多种构造和访问方式。
向量构造
1 2 3 4 5 6 7 8 9 10 11 12
| vec4 color1 = vec4(1.0); vec3 position = vec3(0.5);
vec4 color2 = vec4(1.0, 0.5, 0.2, 1.0); vec3 velocity = vec3(1.0, -2.0, 0.0);
vec2 uv = vec2(0.5, 0.8); vec4 color3 = vec4(color2.rgb, 0.5); vec4 transform = vec4(uv, 0.0, 1.0);
|
向量分量访问
GLSL提供多种向量分量访问方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| vec4 color = vec4(1.0, 0.5, 0.2, 1.0);
float red = color.r; float alpha = color.a;
float x = color.x; float w = color.w;
vec3 rgb = color.rgb; vec3 bgr = color.bgr; vec2 rg = color.rg; vec4 rgba = color.rgba;
vec3 rrr = color.rrr; vec2 xy = color.xy;
color.rgb = vec3(0.8, 0.6, 0.4); color.xy = vec2(0.0, 1.0);
|
矩阵操作详解
矩阵在3D变换中至关重要,GLSL提供完整的矩阵支持:
矩阵构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| mat4 identity = mat4(1.0);
mat3 transform = mat3( 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 );
vec3 col1 = vec3(1.0, 0.0, 0.0); vec3 col2 = vec3(0.0, 1.0, 0.0); vec3 col3 = vec3(0.0, 0.0, 1.0); mat3 matrix = mat3(col1, col2, col3);
|
矩阵访问和操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| mat4 transform = mat4(1.0);
vec4 firstColumn = transform[0]; vec4 secondColumn = transform[1];
float element = transform[0][0]; transform[1][1] = 2.0;
mat4 modelMatrix = mat4(1.0); mat4 viewMatrix = mat4(1.0); mat4 mvpMatrix = projectionMatrix * viewMatrix * modelMatrix;
vec4 position = vec4(1.0, 2.0, 3.0, 1.0); vec4 transformedPos = mvpMatrix * position;
|
⚠️ 重要提醒:为避免内存对齐问题,引擎要求使用Uniform限定符的矩阵必须是4阶矩阵(mat4),2阶和3阶矩阵不能作为Uniform变量使用。
结构体定义
结构体允许组合不同类型的数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| struct Material { vec3 diffuse; vec3 specular; float shininess; sampler2D diffuseMap; };
struct Light { vec3 position; vec3 color; float intensity; float range; };
Material material = Material( vec3(0.8, 0.6, 0.4), vec3(1.0, 1.0, 1.0), 32.0, mainTexture );
vec3 materialColor = material.diffuse; float gloss = material.shininess;
|
数组操作
GLSL的数组使用有特定规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| float weights[4]; vec3 positions[8]; mat4 boneMatrices[64];
for(int i = 0; i < 4; i++) { weights[i] = 0.25; }
const int MAX_LIGHTS = 8; Light lights[MAX_LIGHTS];
for(int i = 0; i < MAX_LIGHTS; i++) { if(lights[i].intensity > 0.0) { } }
|
🔄 控制流程语句
条件语句
GLSL支持标准的条件控制结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| float lightIntensity = 0.8; vec3 finalColor;
if(lightIntensity > 0.5) { finalColor = vec3(1.0, 1.0, 0.0); } else if(lightIntensity > 0.2) { finalColor = vec3(0.5, 0.5, 0.0); } else { finalColor = vec3(0.0, 0.0, 0.0); }
vec3 resultColor = (lightIntensity > 0.5) ? vec3(1.0) : vec3(0.0);
float threshold = step(0.5, lightIntensity); vec3 optimizedColor = mix(vec3(0.0), vec3(1.0), threshold);
|
循环语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| vec3 accumColor = vec3(0.0); for(int i = 0; i < 4; i++) { accumColor += texture(inputTexture, uv + offset[i]).rgb; } accumColor /= 4.0;
int counter = 0; float value = 1.0; while(value > 0.01 && counter < 10) { value *= 0.5; counter++; }
int iteration = 0; do { iteration++; } while(iteration < maxIterations);
|
⚠️ 性能提示:在片元着色器中避免使用过多循环,特别是嵌套循环,这会严重影响GPU性能。
分支控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| for(int i = 0; i < MAX_SAMPLES; i++) { vec4 sample = texture(inputTexture, sampleUV[i]); if(sample.a < 0.01) { break; } }
vec3 totalColor = vec3(0.0); int validSamples = 0; for(int i = 0; i < SAMPLE_COUNT; i++) { vec4 sample = texture(inputTexture, sampleUV[i]); if(sample.a < 0.1) { continue; } totalColor += sample.rgb; validSamples++; }
vec4 frag() { vec4 texColor = texture(mainTexture, v_uv); if(texColor.a < alphaThreshold) { discard; } return texColor; }
|
🎭 函数定义与调用
函数定义语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| float calculateDistance(vec3 pointA, vec3 pointB) { vec3 diff = pointA - pointB; return length(diff); }
void transformUV(in vec2 uv, in vec2 tiling, in vec2 offset, out vec2 result) { result = uv * tiling + offset; }
struct LightingResult { vec3 diffuse; vec3 specular; };
LightingResult calculateLighting(vec3 normal, vec3 lightDir, vec3 viewDir) { LightingResult result; float NdotL = max(0.0, dot(normal, lightDir)); result.diffuse = vec3(NdotL); vec3 halfVector = normalize(lightDir + viewDir); float NdotH = max(0.0, dot(normal, halfVector)); result.specular = vec3(pow(NdotH, 32.0)); return result; }
|
函数参数修饰符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| float processValue(in float input) { return input * 2.0; }
void getColorComponents(vec3 color, out float r, out float g, out float b) { r = color.r; g = color.g; b = color.b; }
void adjustBrightness(inout vec3 color, float factor) { color *= factor; }
vec3 myColor = vec3(0.5, 0.7, 0.9); adjustBrightness(myColor, 1.5);
|
函数重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| float blend(float base, float overlay) { return base * overlay; }
vec3 blend(vec3 base, vec3 overlay) { return base * overlay; }
vec4 blend(vec4 base, vec4 overlay) { return vec4(base.rgb * overlay.rgb, base.a); }
float result1 = blend(0.5, 0.8); vec3 result2 = blend(vec3(0.5), vec3(0.8));
|
📏 存储限定符详解
顶点着色器输入输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| CCProgram vs-main %{ precision highp float; in vec3 a_position; in vec3 a_normal; in vec2 a_texCoord; in vec4 a_color; in vec4 a_tangent; out vec3 v_worldPos; out vec3 v_worldNormal; out vec2 v_uv; out vec4 v_color; out vec3 v_tangent; out vec3 v_bitangent; vec4 vert() { vec4 pos = vec4(a_position, 1.0); v_worldPos = (cc_matWorld * pos).xyz; v_worldNormal = normalize((cc_matWorldIT * vec4(a_normal, 0.0)).xyz); v_uv = a_texCoord; v_color = a_color; return cc_matViewProj * cc_matWorld * pos; } }%
|
片元着色器输入输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| CCProgram fs-main %{ precision highp float; in vec3 v_worldPos; in vec3 v_worldNormal; in vec2 v_uv; in vec4 v_color; uniform sampler2D mainTexture; uniform sampler2D normalMap; uniform Properties { vec4 mainColor; float metallic; float roughness; float normalScale; }; vec4 frag() { vec4 baseColor = texture(mainTexture, v_uv) * mainColor * v_color; vec3 normal = normalize(v_worldNormal); vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0)); float NdotL = max(0.0, dot(normal, lightDir)); baseColor.rgb *= NdotL; return baseColor; } }%
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| uniform MaterialProperties { vec4 albedoColor; vec4 emissionColor; float metallic; float roughness; float normalScale; float aoIntensity; } u_material;
uniform LightingData { vec3 lightDirection; vec3 lightColor; float lightIntensity; vec3 ambientColor; } u_lighting;
vec4 frag() { vec3 baseColor = u_material.albedoColor.rgb; float metallic = u_material.metallic; vec3 lightColor = u_lighting.lightColor * u_lighting.lightIntensity; return vec4(baseColor * lightColor, 1.0); }
|
📐 精度限定符
精度声明
1 2 3 4 5 6 7 8 9
| precision highp float; precision mediump int; precision lowp sampler2D;
highp vec3 worldPosition; mediump vec2 textureCoord; lowp vec4 vertexColor;
|
精度选择指南
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
highp vec3 v_worldPos; highp mat4 u_mvpMatrix;
mediump vec3 v_normal; mediump vec2 v_uv; mediump float u_time;
lowp vec4 v_color; lowp float u_alpha;
|
平台兼容性处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #ifdef GL_ES precision mediump float; #else precision highp float; #endif
#ifdef HIGH_PRECISION #define PRECISION highp #else #define PRECISION mediump #endif
PRECISION vec3 worldPosition; PRECISION float metallicValue;
|
🔧 预处理器指令
宏定义
1 2 3 4 5 6 7 8 9 10 11 12 13
| #define PI 3.14159265359 #define TWO_PI (2.0 * PI) #define HALF_PI (PI * 0.5)
#define saturate(x) clamp(x, 0.0, 1.0) #define lerp(a, b, t) mix(a, b, t) #define square(x) ((x) * (x))
#define TRANSFORM_TEX(tex, name) (tex.xy * name##_ST.xy + name##_ST.zw) #define SAMPLE_TEXTURE_LOD(tex, sampler, coord, lod) textureLod(tex, coord, lod)
|
条件编译
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #ifdef USE_NORMAL_MAP vec3 tangentNormal = texture(normalMap, v_uv).xyz * 2.0 - 1.0; vec3 normal = normalize(TBN * tangentNormal); #else vec3 normal = normalize(v_normal); #endif
#if QUALITY_LEVEL >= 2 vec3 reflection = reflect(viewDir, normal); vec3 envColor = textureLod(envMap, reflection, roughness * maxLod).rgb; #elif QUALITY_LEVEL == 1 vec3 envColor = texture(envMap, normal).rgb; #else vec3 envColor = vec3(0.1, 0.1, 0.2); #endif
#ifdef GL_ES precision mediump float; #define SAMPLE_COUNT 4 #else precision highp float; #define SAMPLE_COUNT 16 #endif
|
Include指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <builtin/uniforms/cc-global> #include <builtin/uniforms/cc-local> #include <builtin/functions/common>
#include <common/lighting-functions> #include <common/noise-functions> #include <common/color-space>
vec3 calculateDirectionalLight(vec3 normal, vec3 lightDir, vec3 lightColor) { float NdotL = max(0.0, dot(normal, lightDir)); return lightColor * NdotL; }
vec3 calculatePointLight(vec3 worldPos, vec3 normal, vec3 lightPos, vec3 lightColor, float range) { vec3 lightVector = lightPos - worldPos; float distance = length(lightVector); float attenuation = 1.0 - smoothstep(0.0, range, distance); vec3 lightDir = normalize(lightVector); float NdotL = max(0.0, dot(normal, lightDir)); return lightColor * NdotL * attenuation; }
|
📚 小结
本章全面介绍了GLSL的基础语法:
- 数据类型:标量、向量、矩阵、结构体、数组的定义和使用
- 控制流程:条件语句、循环语句、分支控制的语法和最佳实践
- 函数系统:函数定义、参数修饰符、函数重载的使用方法
- 存储限定符:in/out/uniform等限定符的作用和使用场景
- 精度控制:不同精度级别的选择和平台兼容性处理
- 预处理器:宏定义、条件编译、文件包含的高级用法
掌握这些GLSL基础语法后,你就可以开始编写更复杂的着色器程序了。
下一章: 第3.1章:创建和使用着色器
💡 学习建议
- 循序渐进:先掌握基本数据类型,再学习复杂的控制结构
- 动手实践:每个语法点都要通过实际代码验证
- 注意精度:合理选择精度级别,平衡性能和质量
- 学会调试:使用宏定义和条件编译进行调试
🔗 参考资源
继续深入学习,你将掌握强大的着色器编程能力!