OpenGL Shader-色差效果实现

638 阅读2分钟

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战

前期练习

色值变化

已知纹理对象texturevec4向量表示了RGBA四个值。在之前已经了解过彩色图像由RGB三原色组成,一个图片纹理可以根据需要调节单个色值大小来观察图片最终呈现效果的变化。例如加载纹理前对RGB中的R值进行调整,观察从[0,1]过程中的变化。

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    vec3 col;
    col = texture(iChannel2,uv).rgb;
    col.r -= abs(sin(iTime));
    gl_FragColor = vec4(col,1.0);
}

当R值从1向0变化过程中会发现纹理图片中红色会越来越不明显最终图片中不再有红色。这也就是红色在图片的比重越来越少而导致图片只有GB两个色值量,最终图片呈现上会往青色上变化(绿色和蓝色混合后是青色)。

原图R值变化
image.pngwecom-temp-82716bd3e36cddf4108a424a8f2407de.gif

单色效果

了解了色值变化效果后,单色效果也很好理解。纹理图片只取RGB其中一种色值,其他色值通道都为0,图像中只有一个色值通道且占比最高,最终图片呈现出来效果就是单色图片了。

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    vec3 col;
    col.r = texture(iChannel2,uv).r;
    gl_FragColor = vec4(col,1.0);
}
原图红色绿色蓝色
image.pngimage.pngimage.pngimage.png

色差实现

在图片处理平台上经常可以看到图片色差效果滤镜。在了解色值变化和单色效果之后就知道如何自行实现色差效果了。色差效果实现比较简单原理就是将每个通道色值单独取出并对坐标系做偏移处理,从而导致偏移后没重合坐标上的色值只有一种色值或是只有两种色值的效果,最终造成一种色差特殊效果。

红绿效果

红绿色差实现原理是将红色通道色值往后偏移,绿色通道色值往前偏移。

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    float diff = 0.02;
    vec3 col;
    col.r = texture(iChannel3,vec2(uv.x + diff,uv.y)).r;
    col.g = texture(iChannel3,vec2(uv.x - diff,uv.y)).g;
    col.b = texture(iChannel3,uv).b;
    gl_FragColor = vec4(col,1.0);
	
}

绿红蓝效果

红蓝绿色差实现原理是将红色通道色值往前偏移,蓝色通道色值往前偏移(偏移值大于红色),绿色通道色值往后偏移。

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    float diff = 0.008;
    vec3 col;
    col.r = texture(iChannel3,vec2(uv.x - diff,uv.y)).r;
    col.g = texture(iChannel3,vec2(uv.x + diff,uv.y)).g;
    col.b = texture(iChannel3,vec2(uv.x - diff * 3.,uv.y)).b;
    gl_FragColor = vec4(col,1.0);
}
红绿效果红蓝绿效果
image.pngimage.png

特殊算法

另外还有其他色差计算偏移量算法,通过一个公式算出较为可靠偏移量实现色差效果,同样也能相似于前面的色差效果。

公式实现的函数绘制值如下所示: 0.05((1.0+sin(x27.0))0.5)(1.0+sin(x6.0))0.5((1.0+sin(x16.0))0.5)((1.0+sin(x19.0))0.5)30.05\cdot\sqrt[3]{\left((1.0+\sin(x*27.0))*0.5\right)\cdot(1.0+\sin(x*6.0))*0.5\cdot\left((1.0+\sin(x*16.0))*0.5\right)\cdot\left((1.0+\sin(x*19.0))*0.5\right)}

image.png

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    float amount = 0.0;
    float value =  0.001;
    amount = (1.0 + sin(value*6.0)) * 0.5;
    amount *= 1.0 + sin(value*16.0) * 0.5;
    amount *= 1.0 + sin(value*19.0) * 0.5;
    amount *= 1.0 + sin(value*27.0) * 0.5;
    amount = pow(amount, 3.0);
    amount *= 0.05;
    vec3 col;
    col.r = texture(iChannel3,vec2(uv.x+amount,uv.y) ).r;
    col.g = texture( iChannel3, uv ).g;
    col.b = texture( iChannel3, vec2(uv.x-amount,uv.y) ).b;
    col *= (1.0 - amount * 0.5);
    gl_FragColor = vec4(col,1.0);
}

image.png