OpenGL 着色器语言特性

一、GLSL 内置变量(Built-in Variables)

GLSL 提供以 gl_ 前缀的预定义内置变量,作为 Shader 中数据交互的额外方式。

1.1 顶点着色器内置变量

变量 类型 作用
gl_Position vec4 输出裁剪空间顶点位置(必设)
gl_PointSize float 设置点的大小(像素),用于 GL_POINTS 图元
gl_VertexID int 当前顶点 ID(只读)

关键代码示例:

glsl 复制代码
void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);    
    gl_PointSize = gl_Position.z;  // 距离越远,点越大
}

使用前需启用:glEnable(GL_PROGRAM_POINT_SIZE);

1.2 片元着色器内置变量

变量 类型 作用
gl_FragCoord vec3 片元窗口坐标 (x, y) + 深度值 (z)
gl_FrontFacing bool 判断片元是否面向观察者
gl_FragDepth float 输出变量,可手动修改深度值
gl_PointCoord vec2 点图元的局部坐标

gl_FragCoord 示例:

glsl 复制代码
void main()
{             
    if(gl_FragCoord.x < 400)
        FragColor = vec4(1.0, 0.0, 0.0, 1.0);  // 红色 - 左侧
    else
        FragColor = vec4(0.0, 1.0, 0.0, 1.0);         // 绿色 - 右侧        
}

gl_FrontFacing 应用:内外纹理切换

glsl 复制代码
void main()
{
    if(gl_FrontFacing)
        FragColor = vec4(1.0, 0.0, 0.0, 1.0);  // 正面用红色
    else
        FragColor = vec4(0.0, 1.0, 0.0, 1.0);  // 背面用绿色
}

二、接口块(Interface Blocks)

用于组织着色器间的输入输出数据,使代码更清晰。

2.1 基本语法

glsl 复制代码
#version 330 core

// 输出到下一个着色器
out VS_OUT
{
    vec3 textCoord;
} vs_out;

// 输入来自上一个着色器
in VS_OUT
{
    vec3 textCoord;
} fs_in;

void main()
{
    vs_out.textCoord = aTexCoord;
    // ...
}

2.2 与 Uniform 对比

  • 普通 Uniformin float someValue;
  • 接口块in BlockName { type varName; } instanceName;

接口块更易管理大量相关数据,适合传递变换矩阵、材质属性等结构化数据。


三、统一缓冲区对象(UBO - Uniform Buffer Objects)

3.1 为什么需要 UBO?

传统方式每个 shader 都要单独绑定 Uniform,UBO 允许:

  • 一次绑定,多个 Shader 共享
  • 高效更新:减少 CPU-GPU 数据传输
  • 符合标准布局:便于多项目复用

3.2 定义与使用

1. C++ 端定义 Uniform 块:

cpp 复制代码
// 定义 Uniform 块结构
#version 330 core
layout(std140) uniform MatrixBlock
{
    mat4 projection;
    mat4 view;
    mat4 model;
};

2. GLSL 访问:

glsl 复制代码
uniform MatrixBlock matrices;

void main()
{
    gl_Position = matrices.projection * matrices.view * matrices.model * vec4(aPos, 1.0);
}

3. C++ 端创建与绑定:

cpp 复制代码
unsigned int uboExample;
glGenBuffers(1, &uboExample);
glBindBuffer(GL_UNIFORM_BUFFER, uboExample);
glBufferData(GL_UNIFORM_BUFFER, sizeof(matrices), &matrices, GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboExample);  // 绑定到索引 0

3.3 布局限定符

限定符 说明
shared 不同程序共享,需手动设置 offset
packed 运行时优化,需查询 offset
std140 最常用,显式定义内存布局
std430 更紧凑的布局(不常用)

四、实用技巧

4.1 gl_PointCoord 制作点精灵

glsl 复制代码
void main()
{
    vec2 uv = gl_PointCoord;  // 0.0 ~ 1.0
    if(length(uv - vec2(0.5)) > 0.5)
        discard;  // 裁剪圆形外的像素
    FragColor = texture(spriteTexture, uv);
}

4.2 gl_FragDepth 性能注意

使用 gl_FragDepth禁用 Early-Z 测试,可能影响渲染性能,仅在必要时使用。


五、要点总结

类别 要点
内置变量 顶点用 gl_Position/PoinSize/VertexID,片元用 gl_FragCoord/FrontFacing/FragDepth
接口块 in/out BlockName {} instance 组织输入输出
UBO glBindBufferBase + layout(std140) 实现高效 Uniform 管理
相关推荐
threelab1 天前
Three.js 极光效果着色器 | 三维可视化 / AI 提示词
javascript·人工智能·着色器
UTwelve4 天前
【UE】如何手搓一个完美贴合地形的 Mesh Decal(面片贴花)
ue5·材质·贴图·着色器
threelab4 天前
挑战AI辅助从零构建3D模型编辑器:01基于Vue3 + Three.js的现代化架构设计
javascript·人工智能·3d·前端框架·着色器
♡すぎ♡8 天前
ShaderLab:可互动水面(基于RenderTexture,实时生成动态扰动)
计算机图形学·贴图·opengl·着色器
郑寿昌11 天前
UE5与UE6在Lumen和Nanite的差异解析
游戏引擎·图形渲染·着色器
threelab11 天前
Three.js 动态旋转同心圆着色器 | 三维可视化效果
开发语言·javascript·着色器
♡すぎ♡12 天前
ShaderLab:海面——顶点变换,程序化生成无需贴图
计算机图形学·opengl·着色器
UTwelve19 天前
【UE】Gerstner Waves 水体模拟 4 :[颜色构成阶段3、4] - 实现NAP+CDOM
ue5·着色器
Yasin Chen19 天前
Unity TMP_SDF 分析(五)片元着色器
unity·游戏引擎·着色器