这儿定义的滤镜是一种表,输入源的每像素颜色,也就是RGB共256*256*256那么多种颜色,每种都能在滤镜表中找到一个替换色,从而实现画面观感的改变。
这里是一张滤镜表(64*64*64):
在OpenGL中,纹理颜色的定位规则和通常的数组操作不同。纹理无论宽高比例如何,有多长,有多宽,都是长为1,宽为1的一个对象,要定位纹理某个位置的颜色,需要使用比例的方式。
所以,在这里,RGB三个通道中,
R控制可以去到纵向的第几面,这儿有64面,即整个纵向可以分为64份,第一分为0,最后一份为63,即定位公式为Y1 = (R/255) * (1/63)
G可以控制R到达的面的第几行,每面有64行Y2 = (G/255) * (1/63/63)
最终Y = Y1+Y2 (先定位面,再定位行)
B通道大小决定选择滤镜表x轴的哪个位置,即(B / 255)* 63,如果滤镜表是更细腻的256*256*256一一对应的话,即直接是(B/255)*255即可。
(最后定位某行的第几个位置的颜色)
按照以上规则,shader编写如下。故意使得只有左半边纹理应用滤镜规则,方便观察效果:
#version 300 es
precision highp float;
uniform sampler2D sTexture;
uniform sampler2D lutTexture;
in highp vec2 vTextureCoord;
out vec4 fragColor;
void main()
{
if(vTextureCoord[0] < 0.5f) {//输入纹理,左半边使用滤镜规则替换像素
vec4 srcColor = texture(sTexture, vec2(vTextureCoord[0], vTextureCoord[1]));
float z = (floor(srcColor[0] * 64.0f) - 1.0f) * 0.015625f; //Z轴控制可以去到 64面 * 百分之几,控制可以去到的面,每面单位为1/64 = 0.015625
float y = (floor(srcColor[1] * 64.0f) - 1.0f) * 0.015625f * 0.015625f; //Y轴控制可以去到其中一面的百分之几 1/64=0.015625
float x = floor(srcColor[2] * 64.0f) * 0.015625f;
if(z < 0.0f) z = 0.0f;
if(y < 0.0f) y = 0.0f;
float offsetY = (z + y);
vec4 fragColorLut = texture(lutTexture, vec2(x, offsetY));
fragColor = fragColorLut;
} else {//右半边使用原图
fragColor = texture(sTexture, vec2(vTextureCoord[0], vTextureCoord[1]));
}
}
其中sTexture是原图,lutTexture是滤镜映射表。
最终效果:
当然作为手机预览来说,这样的精度可以说是足够了,但是如果要出精细的图,则需要更复杂的规则,例如256是64的4倍,每4个单位映射为1个单位,所以必须要计算出其是滤镜两个颜色之间的4个阶梯颜色,再进行替换。出图版本的滤镜shader下次再贴原理和代码,先下班,有点晚了。