当前位置: 首页 > news >正文

GLSL 3.0简介

1. 概念

着色语言Shading Language

用于调整渲染管线的GPU编程语言。

GLSL 3.0

OpenGL Shading Language 3.0。

顶点Vertex

顶点是构成3D模型的基本单位,包含位置、法线、纹理坐标、颜色等属性。例如,一个立方体由8个顶点定义,每个顶点存储其在三维空间中的坐标。

顶点着色器Vertex Shader

从顶点属性(位置、法线等)生成中间数据的函数。顶点着色器控制几何形态(如动画、变形)。

图元Primitive

图元是由顶点组合成的基础几何形状,如点、线、三角形。例如,两个顶点构成一条线,三个顶点构成一个三角形面片。图元作为中间媒介,连接顶点与片元处理阶段。图元自身没有独立的着色器,几何着色器可以修改图元。

片元Fragment

片元是光栅化后生成的像素候选,包含位置、颜色、深度等信息,但尚未通过最终测试(如深度测试)。例如,一个三角形覆盖的屏幕区域会被拆解为多个片元。

片元着色器Fragment Shader/Pixel Shader

根据顶点着色器输出的中间数据、纹理和全局变量uniform,计算最终色彩候选值。片元着色器控制视觉效果(如材质、光照)。

几何着色器Geometry Shader

可以新建或修改图元。性能开销大,在实时渲染中较少使用。

渲染管线

将3D场景转换为2D图像过程,通常分为以下阶段:应用(准备几何数据、设置渲染状态)、几何处理(变换顶点、细分曲面、修改图元、变换投影)、光栅化阶段(将图元转换为片元)、像素处理阶段(计算像素颜色、混合)。

着色语言Shading Language

GPU编程语言,用于编写在渲染管线的特定阶段执行的程序。

光栅化

将几何图元(主要是三角形)转换为像素或片元的过程。

2. 渲染管线中的协作流程

  1. 顶点着色器处理顶点。每个顶点独立执行,输出裁剪坐标和插值数据。
  2. 图元装配与光栅化。顶点组装为图元(如三角形),再离散化为片元。
  3. 片元着色器上色。对每个片元计算颜色,后续通过深度测试、混合等操作决定最终像素。

3. 对比编程语言

和传统编程语言相比,着色语言在核心对象、核心操作、运行模型、资源管理等方面存在较大不同。

表1  编程语言和着色语言的区别
编程语言着色语言
核心对象原生数据类型和抽象数据结构向量矩阵和纹理采样器
核心操作修改状态、分支、循环和子程序调用线性代数运算、插值和采样
运行模型单一强处理器顺序执行多个弱处理器并发执行
资源管理运行时动态分配编译时静态分配
代码风格过程式函数式

简单来说,编写着色语言是在定义一个(近似)线性变换。

4. GSLS 3.0着色语言

4.1. 示例

代码1  顶点着色器

#version 130  // 声明使用GLSL 3.0版本// 输入属性(使用layout显式指定位置)
layout(location = 0) in vec3 aPosition;  // 顶点位置(属性位置0)
layout(location = 1) in vec3 aNormal;    // 顶点法线(属性位置1)
layout(location = 2) in vec2 aTexCoord;  // 纹理坐标(属性位置2)// 统一变量(由应用程序传入)
uniform mat4 uModel;      // 模型矩阵(局部空间->世界空间)
uniform mat4 uView;       // 视图矩阵(世界空间->观察空间)
uniform mat4 uProjection; // 投影矩阵(观察空间->裁剪空间)// 输出到片元着色器的变量(会被插值)
out vec3 vWorldPos;       // 世界空间顶点位置
out vec3 vNormal;         // 世界空间法线向量
out vec2 vTexCoord;       // 纹理坐标void main()
{
    // 计算完整的模型视图投影矩阵
    mat4 mvp = uProjection * uView * uModel;    // 将顶点位置转换到裁剪空间(必须赋值给gl_Position)
    gl_Position = mvp * vec4(aPosition, 1.0);    // 计算世界空间位置(用于光照计算)
    vWorldPos = vec3(uModel * vec4(aPosition, 1.0));    // 转换法线到世界空间(注意使用法线矩阵)
    vNormal = mat3(transpose(inverse(uModel))) * aNormal;    // 直接传递纹理坐标
    vTexCoord = aTexCoord;
}

代码2  片元着色器

#version 130  // 声明使用GLSL 3.0版本// 从顶点着色器输入的变量(经过插值)
in vec3 vWorldPos;    // 插值后的世界空间位置
in vec3 vNormal;      // 插值后的世界空间法线
in vec2 vTexCoord;    // 插值后的纹理坐标// 统一变量
uniform sampler2D uTexture;    // 纹理采样器
uniform vec3 uLightPos;        // 光源位置(世界空间)
uniform vec3 uLightColor;      // 光源颜色
uniform vec3 uViewPos;         // 摄像机位置(世界空间)// 片段着色器输出(可输出到多个渲染目标)
layout(location = 0) out vec4 fragColor;  // 主颜色输出(位置0)void main()
{
    // 从纹理采样基础颜色
    vec4 texColor = texture(uTexture, vTexCoord);    // 丢弃透明度过低的片段
    if(texColor.a < 0.1) discard;    // 归一化法线(插值后长度可能不为1)
    vec3 norm = normalize(vNormal);    // 计算光照方向
    vec3 lightDir = normalize(uLightPos - vWorldPos);    // 漫反射计算(兰伯特光照)
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * uLightColor;    // 镜面反射计算(布林-冯光照)
    vec3 viewDir = normalize(uViewPos - vWorldPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0);
    vec3 specular = spec * uLightColor;    // 环境光(简单常量)
    vec3 ambient = vec3(0.1);    // 组合所有光照分量
    vec3 result = (ambient + diffuse + specular) * texColor.rgb;    // 输出最终颜色(RGBA)
    fragColor = vec4(result, texColor.a);
}

4.2. 基本类型和结构体

标量boolintuintfloag
double
矩阵vec2/3/4ivec2/3/4uvec2/3/4mat2/3/4
mat2x3
不透明类型sampler2DsamplerCubeisampler2D

代码3  结构体

struct Light {
    vec3 position;
    vec3 color;
    float intensity;
};
Light mainLight;

4.3. 存储限定符

in输入
out输出
inout输入输出
uniform全局变量
const常量
precision精度

4.4. 流程控制

代码4  分支

if (condition) {
    // 代码块
} else if (anotherCondition) {
    // 代码块
} else {
    // 代码块
}switch(intValue) {
    case 0:
        // 代码
        break;
    default:
        // 代码
}

代码5  循环语句

for (int i = 0; i < 10; i++) {
    if (i == 5) continue;
    // 代码
    if (i == 8) break;
}while (condition) {
    // 代码
}do {
    // 代码
} while (condition);

4.5. 内置变量

表2  内置变量
变量说明类型示例
顶点着色器输入变量
gl_VertexID当前顶点索引intint idx = gl_VertexID;
gl_InstanceID实例化渲染中当前实例的索引intint instanceIdx = gl_InstanceID;
顶点着色器输出变量
gl_Position​必须设置的顶点裁剪空间坐标vec4gl_Position = MVP * aPosition;
gl_PointSize点大小floatgl_PointSize = 10.0;
片段着色器输入变量
gl_FragCoord片元窗口坐标vec4vec2 pos = gl_FragCoord.xy;
gl_FrontFacing片元朝向boolif (gl_FrontFacing) {…}
gl_PointCoord点内坐标vec2vec2 uv = gl_PointCoord;
片段着色器输出变量
gl_FragColor片元颜色值vec4gl_FragColor = vec4(1,0,0,1);
gl_FragDepth可修改的片元深度值floatgl_FragDepth = 0.5;
fragColor​自定义颜色输出变量vec4out vec4 fragColor;
几何着色器变量
gl_PrimitiveIDIn输入图元的IDintint id = gl_PrimitiveIDIn;
gl_Layer指定渲染目标层intgl_Layer = 1;
计算着色器变量
gl_GlobalInvocationID全局调用IDuvec3uint idx = gl_GlobalInvocationID.x;
gl_LocalInvocationID局部工作组内IDuvec3uint localIdx = gl_LocalInvocationID.y;
废弃变量
gl_Vertex
gl_Normal
gl_MultiTexCoord0-7
gl_ModelViewMatrix
gl_FragData[]

4.6. 内置函数

表3  内置函数
分类函数说明示例
数学函数trunc向零取整(去除小数部分)trunc(2.7) = 2.0 trunc(-1.3) = -1.0
roundEven四舍五入到最接近的偶整数roundEven(2.5) = 2.0 roundEven(3.5) = 4.0
sin正弦函数(参数为弧度)sin(radians(90.0)) = 1.0
cos余弦函数(参数为弧度)cos(radians(180.0)) = -1.0
tan正切函数(参数为弧度)tan(radians(45.0)) ~= 1.0
sqrt平方根sqrt(4.0) = 2.0
inversesqrt平方根的倒数(比1.0/sqrt(x)更快)inversesqrt(4.0) = 0.5
pow幂运算(x的y次方)pow(2.0, 3.0) = 8.0
log自然对数(底数为e)log(exp(2.0)) ~= 2.0
radians角度转弧度radians(180.0) = 3.14159
degrees弧度转角度degrees(3.14159) ~= 180.0
fract获取小数部分(x - floor(x))fract(2.7) = 0.7
mod取模运算(浮点数兼容)mod(5.2, 3.0) = 2.2
smoothstep埃尔米特插值(在edge0和edge1间平滑过渡)smoothstep(0.0, 1.0, 0.5) = 0.5
向量运算length计算向量长度(模)length(vec3(0,3,4)) = 5.0
normalize单位化向量(方向不变,模长为1)normalize(vec2(1,1)) ~= vec2(0.707,0.707)
dot点积(返回两向量夹角的cos值)dot(vec3(1,0,0), vec3(0,1,0)) = 0.0
cross叉积(仅支持vec3,返回垂直向量)cross(vec3(1,0,0), vec3(0,1,0)) = vec3(0,0,1)
lessThan逐元素比较(<,返回bvec)bvec2 res = lessThan(vec2(1,3), vec2(2,2));
any/all检查向量元素是否存在/全部为真if(any(bvec2(true, false))) {…}
纹理函数texture通用纹理采样(替换旧版texture2D)[9](@ref)texture(sampler2D, vec2(0.5,0.5))
textureSize获取纹理尺寸(返回整数向量)ivec2 size = textureSize(sampler, 0)
texelFetch用整数坐标直接获取纹素(不进行滤波)[11](@ref)texelFetch(sampler, ivec2(10,20), 0)
textureLod指定LOD层级的纹理采样(常用于计算着色器)textureLod(sampler, coord, 1.2)
textureGrad指定梯度采样的纹理(避免自动计算LOD)textureGrad(sampler, uv, ddx, ddy);
textureProj投影纹理采样(坐标自动除以w分量)textureProj(sampler, vec3(uv, 1.0));
textureOffset带偏移量的纹理采样(需常量偏移)textureOffset(sampler, uv, ivec2(1,0));
几何函数transpose矩阵转置(行列互换)transpose(mat2(1,2,3,4)) = mat2(1,3,2,4)
determinant矩阵行列式(用于判断可逆性)determinant(mat2(1,0,0,1)) = 1.0
inverse逆矩阵(要求行列式非零)inverse(mat2(1,0,0,1)) = mat2(1,0,0,1)
distance计算两点间欧氏距离distance(vec2(0,0), vec2(3,4)) = 5.0
reflect反射向量(I - 2·dot(N,I)·N)reflect(vec3(1,0,0), vec3(0,1,0)) = vec3(-1,0,0)
refract折射向量(需提供折射率)refract(I, N, 0.9)
导数函数dFdx屏幕空间x方向偏导数(仅片段着色器)float dx = dFdx(uv.x);
dFdy屏幕空间y方向偏导数(仅片段着色器)float dy = dFdy(uv.y);
fwidth偏导数绝对值之和(abs(dFdx) + abs(dFdy))float edge = fwidth(color);
浮点处理frexp分解浮点数为尾数和指数(x = m * 2^e)frexp(8.0, m, e); // m=0.5, e=4
ldexp重构浮点数(x = m * 2^e)ldexp(0.5, 4) = 8.0
整数函数floatBitsToInt浮点数位表示转整数(保留二进制不变)int i = floatBitsToInt(1.0);
intBitsToFloat整数位表示转浮点数float f = intBitsToFloat(0x3f800000); // =1.0
矩阵函数outerProduct外积(生成矩阵M = colVec * rowVec)mat2 M = outerProduct(vec2(1,2), vec2(3,4));

4.7. 预处理指令

#version 130#define PI 3.141592653589793#ifdef USE_TEXTURE
    // 纹理相关代码
#else
    // 后备代码
#endif#extension GL_ARB_explicit_attrib_location : enable

5. 其他着色语言

表4  主流着色语言
着色语言平台语法
GLSL,OpenGL Shading LanguageOpenGL/OpenGL ES/WebGL类C语言
SPIR-V,Standard Portable Intermediate Representation跨平台中间字节码
HLSL,High-Level Shading Language微软DirectX类C语言
Metal Shading Language苹果Metal框架类C++
AGSL,Android Graphics Shading LanguageAndroid 12+类C
SKSL,Skia Shading LanguageGoogle SkiaGPU无关中间代码
ShaderLabUnity
WEBSL,WebGPU Shading LanguageWebGPU类TypeScript
Slang多平台

6. 参考资料

https://registry.khronos.org/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf

http://www.dtcms.com/a/300274.html

相关文章:

  • [RPA] 日期时间练习案例
  • Xinference vs SGLang:详细对比分析
  • 最优估计准则与方法(4)最小二乘估计(LS)_学习笔记
  • 【补题】Codeforces Global Round 15 B. Running for Gold
  • P1019 [NOIP 2000 提高组] 单词接龙
  • 从Python编程到AI大模型:GeoAI大模型驱动的地球科学智能计算——涵盖随机森林、CNN、LSTM、Transformer及科研绘图实战
  • linux mmc驱动精讲-1、引言
  • UNet改进(25):集成可变形注意力的高效图像分割方法
  • python 检测蜂窝网络,实现掉网自动拨号
  • nacos启动报错:Unable to start embedded Tomcat。
  • ChatIm项目文件上传与获取
  • 配置nodejs
  • 面试150 数据流的中位数
  • 6.数组和字符串
  • 从稀疏数据(CSV)创建非常大的 GeoTIFF(和 WMS)
  • 【时时三省】(C语言基础)返回指针值的函数
  • TRIM功能
  • 《代码随想录》刷题记录
  • 速通python加密之MD5加密
  • Datawhale AI 夏令营:让AI理解列车排期表 Notebook(Baseline拆解)
  • JVM常见工具
  • Java 对象秒变 Map:字段自由伸缩的优雅实现
  • KTO:基于行为经济学的大模型对齐新范式——原理、应用与性能突破
  • 2025测绘程序设计国赛实战 | 基于统计滤波算法的点云去噪
  • 使用binutils工具分析目标文件(贰)
  • U514565 连通块中点的数量
  • 缓存一致性:从单核到异构多核的演进之路
  • HarmonyOS中的PX、 VP、 FP 、LPX、Percentage、Resource 详细区别是什么
  • HCIP--MGRE实验
  • CT、IT、ICT 和 DICT区别