GLSL
数据类型详解
GLSL(OpenGL Shading Language)
中的数据类型主要分为七种类型:标量、向量、矩阵、采样器、结构体、数组和空类型。下面将详细介绍每种类型的特点和用法。
1. 标量类型
标量表示只有大小没有方向的量,GLSL
中包含以下标量类型:
bool
:布尔值,可以是true
或false
int
:整型,32
位整数float
:浮点型,32
位浮点数
整型数值可以用不同进制表示:
// 不同进制表示同一个值(16)
int decimal = 16; // 十进制
int octal = 020; // 八进制
int hexadecimal = 0x10; // 十六进制
注意事项:
- 在进行标量运算时,需要注意精度问题,防止溢出
float
类型数据建议始终加小数点,如1.0
而不是1
2. 向量类型
向量可以看作是数组,在GLSL
中通常用于存储颜色、坐标等数据。向量类型根据维数和存储的标量类型分类:
- 浮点向量
vec2:二维浮点向量
vec3:三维浮点向量
vec4:四维浮点向量
- 整型向量
ivec2:二维整型向量
ivec3:三维整型向量
ivec4:四维整型向量
- 布尔向量
bvec2:二维布尔向量
bvec3:三维布尔向量
bvec4:四维布尔向量
- 向量分量访问方式:
vec4 color = vec4(1.0, 0.5, 0.3, 1.0);
// 以下四种访问方式等价
float red1 = color[0];
float red2 = color.r;
float red3 = color.x;
float red4 = color.s;
- 向量分量可以通过不同的命名约定访问:
颜色访问:使用r, g, b, a分量
vec4 color;
color.r; // 红色分量
color.g; // 绿色分量
color.b; // 蓝色分量
color.a; // 透明度分量
位置访问:使用x, y, z, w分量
vec4 position;
position.x; // x坐标
position.y; // y坐标
position.z; // z坐标
position.w; // 齐次坐标
纹理访问:使用s, t, p, q分量
vec4 texCoord;
texCoord.s; // 水平纹理坐标
texCoord.t; // 垂直纹理坐标
texCoord.p; // 深度纹理坐标
texCoord.q; // 第四个纹理坐标
向量还支持分量重组(swizzling):
vec4 color = vec4(1.0, 0.5, 0.3, 1.0);
vec3 rgb = color.rgb; // 提取rgb分量
vec3 bgr = color.bgr; // 反转rgb分量
vec2 rr = color.rr; // 创建只有红色分量的向量
注意:GLSL
中的向量是列向量,与矩阵相乘时,矩阵在前,向量在后
3. 矩阵类型
- GLSL提供三种基本矩阵类型:
mat2:2×2浮点矩阵
mat3:3×3浮点矩阵
mat4:4×4浮点矩阵
- 矩阵的声明和使用:
矩阵声明
mat4 transform;
单位矩阵初始化
mat4 identity = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
);
// 访问矩阵元素 - 列优先存储
float element = transform[1][2]; // 第2列第3行的元素
矩阵可以与向量或其他矩阵进行乘法运算:
mat4 modelMatrix;
vec4 position;
vec4 transformedPosition = modelMatrix * position;
4. 采样器类型
采样器类型用于访问纹理数据,主要包括:
sampler2D:2D纹理采样器
samplerCube:立方体纹理采样器
sampler3D:3D纹理采样器
sampler2DShadow:2D阴影纹理采样器
采样器使用示例:
uniform sampler2D diffuseTexture;
void main() {
// 使用texture函数从纹理中采样颜色
vec4 texColor = texture(diffuseTexture, vec2(0.5, 0.5));
}
采样器变量通常声明为uniform
,表示一副或一套纹理贴图,可以理解为物体表面的"皮肤"
5. 结构体类型
GLSL
中的结构体与C
语言类似,用struct
关键字定义:
struct Light {
vec3 position;
vec3 color;
float intensity;
};
// 使用结构体
Light mainLight;
mainLight.position = vec3(0.0, 10.0, 0.0);
mainLight.color = vec3(1.0, 1.0, 1.0);
mainLight.intensity = 0.8;
结构体可以包含任何基本类型、数组或其他结构体
6. 数组类型
GLSL
支持一维数组,声明方式与C
语言类似:
// 固定大小数组
float values[4];
vec3 positions[10];
// 数组初始化
float factors[3] = float[3](1.0, 0.5, 0.2);
// 访问数组元素
float factor = factors[1];
注意事项:
GLSL
中数组下标从0开始
在某些GLSL
版本中,数组声明可以不指定大小,但建议总是指定大小以提高可读性和兼容性
数组索引必须是常量表达式或均匀循环索引,不支持动态索引(在某些较新版本中有所放宽)
7. 空类型
空类型用void
表示,主要用于声明不返回任何值的函数:
void main() {
// 函数体
}
void setColor(vec4 color) {
// 没有返回值的函数
}
Demo
代码
以下是一个综合使用多种数据类型的片段着色器示例:
#version 300 es
precision mediump float;
// 结构体定义
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
// 采样器
uniform sampler2D diffuseMap;
uniform sampler2D normalMap;
// 矩阵
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
// 向量数组
uniform vec3 lightPositions[4];
uniform vec3 lightColors[4];
// 结构体
uniform Material material;
// 输入和输出
in vec2 texCoord;
in vec3 normal;
in vec3 fragPos;
out vec4 fragColor;
void main() {
// 标量
float ambientStrength = 0.1;
// 向量
vec3 norm = normalize(normal);
vec3 viewDir = normalize(vec3(0.0, 0.0, 1.0) - fragPos);
// 纹理采样
vec4 texColor = texture(diffuseMap, texCoord);
// 颜色计算(使用向量运算)
vec3 result = material.ambient * ambientStrength;
// 循环和数组访问
for(int i = 0; i < 4; i++) {
vec3 lightDir = normalize(lightPositions[i] - fragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * material.diffuse * lightColors[i];
result += diffuse;
}
// 最终输出
fragColor = vec4(result, 1.0) * texColor;
}
这个示例展示了GLSL
中各种数据类型的使用方式,包括标量、向量、矩阵、采样器、结构体和数组