You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

新手求教:如何在GLSL着色器中实现颜色矩阵滤镜?

嘿,完全不用不好意思!新手刚接触着色器的时候,术语搞混太正常了~我来一步步给你讲清楚怎么在GLSL里实现颜色矩阵滤镜,保证你能看懂!

先搞懂颜色矩阵的核心逻辑

你说的没错,颜色矩阵是4行5列的结构,每行对应输出颜色的一个通道(R、G、B、A),每列的作用如下:

  • 前4列:分别和输入颜色的红、绿、蓝、Alpha值相乘,用来控制颜色通道的混合比例
  • 第5列:是该通道的偏移量(可以理解为给这个通道加一个固定值)

用公式直白点说,就是:

输出R = 输入R * 矩阵[0][0] + 输入G * 矩阵[0][1] + 输入B * 矩阵[0][2] + 输入A * 矩阵[0][3] + 矩阵[0][4]
输出G = 输入R * 矩阵[1][0] + 输入G * 矩阵[1][1] + 输入B * 矩阵[1][2] + 输入A * 矩阵[1][3] + 矩阵[1][4]
输出B = 输入R * 矩阵[2][0] + 输入G * 矩阵[2][1] + 输入B * 矩阵[2][2] + 输入A * 矩阵[2][3] + 矩阵[2][4]
输出A = 输入R * 矩阵[3][0] + 输入G * 矩阵[3][1] + 输入B * 矩阵[3][2] + 输入A * 矩阵[3][3] + 矩阵[3][4]
GLSL里的具体实现

因为你是新手,我直接给你完整的代码示例,分顶点着色器和片段着色器两部分——顶点着色器不用太复杂,重点看片段着色器的颜色计算逻辑。

顶点着色器(基础款)

这个部分主要是把纹理坐标传递给片段着色器,几乎所有2D纹理着色器都可以用这个模板:

attribute vec4 a_position;
attribute vec2 a_texCoord;

varying vec2 v_texCoord;

void main() {
    gl_Position = a_position;
    v_texCoord = a_texCoord;
}

片段着色器(核心逻辑)

这里我们把4x5的颜色矩阵作为uniform传入,然后对每个像素的颜色做矩阵运算:

precision mediump float;

// 输入的纹理像素坐标
varying vec2 v_texCoord;
// 要处理的纹理
uniform sampler2D u_texture;

// 4x5颜色矩阵:按行存储,顺序是[R行(R,G,B,A,偏移), G行(R,G,B,A,偏移), B行(R,G,B,A,偏移), A行(R,G,B,A,偏移)]
uniform float u_colorMatrix[20];

void main() {
    // 获取当前像素的原始颜色
    vec4 srcColor = texture2D(u_texture, v_texCoord);
    
    // 计算每个通道的输出值
    float r = srcColor.r * u_colorMatrix[0] + 
              srcColor.g * u_colorMatrix[1] + 
              srcColor.b * u_colorMatrix[2] + 
              srcColor.a * u_colorMatrix[3] + 
              u_colorMatrix[4];
    
    float g = srcColor.r * u_colorMatrix[5] + 
              srcColor.g * u_colorMatrix[6] + 
              srcColor.b * u_colorMatrix[7] + 
              srcColor.a * u_colorMatrix[8] + 
              u_colorMatrix[9];
    
    float b = srcColor.r * u_colorMatrix[10] + 
              srcColor.g * u_colorMatrix[11] + 
              srcColor.b * u_colorMatrix[12] + 
              srcColor.a * u_colorMatrix[13] + 
              u_colorMatrix[14];
    
    float a = srcColor.r * u_colorMatrix[15] + 
              srcColor.g * u_colorMatrix[16] + 
              srcColor.b * u_colorMatrix[17] + 
              srcColor.a * u_colorMatrix[18] + 
              u_colorMatrix[19];
    
    // 把颜色值限制在0.0-1.0之间,避免颜色溢出导致显示异常
    gl_FragColor = clamp(vec4(r, g, b, a), 0.0, 1.0);
}
几个实用的滤镜矩阵例子

给你几个常用的矩阵,直接替换u_colorMatrix的值就能看到效果:

  • 原始颜色(单位矩阵):完全不改变颜色
    1.0, 0.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 0.0, 1.0, 0.0
    
  • 灰度滤镜(标准公式):把彩色转成黑白
    0.299, 0.587, 0.114, 0.0, 0.0,
    0.299, 0.587, 0.114, 0.0, 0.0,
    0.299, 0.587, 0.114, 0.0, 0.0,
    0.0,   0.0,   0.0,   1.0, 0.0
    
  • 颜色反转:类似底片效果
    -1.0, 0.0, 0.0, 0.0, 1.0,
    0.0, -1.0, 0.0, 0.0, 1.0,
    0.0, 0.0, -1.0, 0.0, 1.0,
    0.0, 0.0, 0.0, 1.0, 0.0
    
新手必看注意事项
  • 一定要用clamp()限制输出颜色的范围:GLSL里颜色值超过1.0或者低于0.0会显示异常(比如变成纯白色或者透明),这个函数能帮你把值牢牢锁在0.0-1.0之间
  • 矩阵的值可以是负数或者大于1的数:比如反转滤镜用了-1,提亮滤镜可以把系数设为1.2,只要最后clamp就行
  • 如果是用WebGL调用的话,要通过gl.uniform1fv()方法把矩阵数组传递给着色器的u_colorMatrix变量

内容的提问来源于stack exchange,提问作者solub

火山引擎 最新活动