新手求教:如何在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




