最终效果如下(旋转效果和膨胀放大效果作为例子):

使用OpenGL双FBO加FragShader模仿PS的液化工具

FragShader文件:

#version 300 es
precision highp float;
uniform sampler2D sTexture;//纹理输入
uniform int frame;//第几帧
uniform int funChoice; //功能代码块选择
uniform float effectR; //作用半径
uniform vec2 targetXY; //作用位置,使用纹理分辨率坐标
uniform vec2 prevTargetXY; //上一次的作用位置。
uniform vec2 resolution;//纹理分辨率
in vec4 fragObjectColor;//接收vertShader处理后的颜色值给片元程序
in vec2 fragVTexCoord;//接收vertShader处理后的纹理内坐标给片元程序
out vec4 fragColor;//输出到的片元颜色#define PINCH_VECTOR vec2( sin(10. * frame / 10.0), cos(20. * frame / 10.0)) * .03 // 挤压向量mat2 rotate(float a) // 旋转矩阵
{float s = sin(a);float c = cos(a);return mat2(c,-s,s,c);
}vec2 twirl(vec2 uv, vec2 center, float range, float angle, bool cw) {float d = distance(uv, center);uv -=center;// d = clamp(-angle/range * d + angle,0.,angle); // 线性方程d = smoothstep(0., range, range-d) * angle;if (cw) {uv *= rotate(d);} else {uv *= rotate(-d);}uv+=center;return uv;
}vec2 inflate(vec2 uv, vec2 center, float range, float strength) {float dist = distance(uv , center);vec2 dir = normalize(uv - center);float scale = 1.-strength + strength * smoothstep(0., 1. ,dist / range);float newDist = dist * scale;return center + newDist * dir;
}vec2 pinch(vec2 uv, vec2 targetPoint, vec2 prevTargetXY, float range)
{float dist = distance(uv, prevTargetXY);vec2 point = prevTargetXY +  smoothstep(0., 1., dist / range) * (targetPoint - prevTargetXY);  //(targetPoint - prevTargetXY)前后两次触摸点之间的x,y距离return uv - targetPoint + point;
}//vec2 pinch(vec2 uv, vec2 targetPoint, vec2 prevTargetXY, float range)
//{
//    float dist = distance(uv, targetPoint);  //目标点和当前采样点的距离
//    float distBetweenTwoPoint = distance(targetPoint, prevTargetXY);
//    float dist3 = distance(uv, prevTargetXY);
//    vec2 point = targetPoint +  smoothstep(0.0, 1.0, dist / range) * prevTargetXY;
//    return uv - distBetweenTwoPoint * (dist / dist3) * smoothstep(0., 1., dist / range);
//    //1、算采样点uv和tagetPoint、prevTargetXy构成的线段的夹角。用于确定挤压的方向和挤压的强大
//    //2
//}void main() {vec2 targetXYToOne = targetXY / resolution; //归1化处理vec2 prevTargetXYToOne = prevTargetXY / resolution; //归1化处理targetXYToOne.y = 1.0 - targetXYToOne.y;prevTargetXYToOne.y = 1.0 - prevTargetXYToOne.y;
//    vec2 texCoord = vec2(fragVTexCoord.y, fragVTexCoord.x);vec2 texCoord = fragVTexCoord;switch (funChoice) {case 0: //采集纹理图片像素vec4 color = texture(sTexture, texCoord);//采样纹理中对应坐标颜色,进行纹理渲染color.a = color.a * fragObjectColor.a;//利用顶点透明度信息控制纹理透明度fragColor = color;break;//已经采集了纹理图片像素并留下残迹在Framebuffer了,可以进行图像处理了:case 1: //绘制点float d = distance(texCoord, targetXY);if (distance(targetXYToOne, texCoord) < effectR) {fragColor = vec4(1.0, 0.0, 0.0, 1.0);}break;case 2: //旋转形变1vec2 newST = twirl(texCoord, targetXYToOne, effectR, 0.05, true);color = texture(sTexture, newST);//采样纹理中对应坐标颜色,进行纹理渲染color.a = color.a * fragObjectColor.a;//利用顶点透明度信息控制纹理透明度fragColor = color;break;case 3: //旋转形变2newST = twirl(texCoord, targetXYToOne, effectR, 0.05, false);color = texture(sTexture, newST);//采样纹理中对应坐标颜色,进行纹理渲染color.a = color.a * fragObjectColor.a;//利用顶点透明度信息控制纹理透明度fragColor = color;break;case 4: //膨胀:newST = inflate(texCoord, targetXYToOne, effectR, 0.02);color = texture(sTexture, newST);//采样纹理中对应坐标颜色,进行纹理渲染color.a = color.a * fragObjectColor.a;//利用顶点透明度信息控制纹理透明度fragColor = color;break;case 5: //收缩:newST = inflate(texCoord, targetXYToOne, effectR, -0.02);color = texture(sTexture, newST);//采样纹理中对应坐标颜色,进行纹理渲染color.a = color.a * fragObjectColor.a;//利用顶点透明度信息控制纹理透明度fragColor = color;break;case 6: //挤压
//            newST = pinch(texCoord, targetXYToOne, vec2(0.1, 0.2), effectR);newST = pinch(texCoord, targetXYToOne, prevTargetXYToOne, effectR);color = texture(sTexture, newST);//采样纹理中对应坐标颜色,进行纹理渲染color.a = color.a * fragObjectColor.a;//利用顶点透明度信息控制纹理透明度fragColor = color;break;default:case -1: //鼠标抬起时要切换到这里,避免持续刷新break;}
}

直接靠本fragShader的纹理采样圈算法可以实现各种图片扭曲效果,而且是完全基于GPU不需要一丁点GPU的,性能非常高,但如果每次都用图片纹理绑定上去,那么每帧只有目标值会产生效果,无法使效果暂留和叠加。所以我使用了两个FBO对象开辟两个可以装载图像纹理的空间,使用swapBuffer的思路互为纹理绑定,也就是:

第一帧渲染图片到fbo_0,然后fbo_1的texture绑为fbo_0,然后做纹理采样圈处理;再下帧切换为fbo_0绑定的texture为fbo_1。除了第一帧,两个fbo互相绑定对方为纹理,即可使得每一步的片元特效都可以叠加,做出类似PS中液化的效果。

即可把每帧的处理效果暂留和叠加:

具体代码比较长就不贴出来了,可以访问我的GitHub直接看这几个文件:

learnopengl/app/src/main/java/com/cjz/littleps at main · cjzjolly/learnopengl · GitHub

https://github.com/cjzjolly/learnopengl/blob/main/app/src/main/java/com/cjztest/glShaderEffect/GLFrameBufferEffectPingPongSave.java

其实最重要的还是fragShader的实现和FBO的巧妙利用。

利用OpenGL高效实现类似PhotoShop液化工具的教程比较少,这个也是我在学习OpenGL的过程中突发奇想的成功实验产物,希望能帮到有需要的读者吧:

使用两个FBO互相绑定实现PS液化效果相关推荐

  1. 使用两个FBO互相绑定实现PS液化效果(2)_使用PBO保存FBO当前画面

    之前的文章(11条消息) 使用两个FBO互相绑定实现PS液化效果_cjzcjl的博客-CSDN博客 基于两个FBO之间,互相错开使用,互为纹理和输出FrameBuffer,实现效果在两个FBO之间不断 ...

  2. [FFMpeg开发]视频转高质量GIF优化方案(接近ps生成效果),从原理剖析

    摘要 虽然此前有人发过了,但是这个博主没有分析原理并且没有提炼出来.不适合开发者学习. 所以我只是进行二次优化,原文高质量视频转gif 此前,做产品的时候,产品用到了ffmpeg框架,手上几个ffmp ...

  3. layui table 表格两种赋值方式下,data分页效果有效, url分页效果的失效 问题的解决。

    layui table 表格两种赋值方式下,data分页效果有效, url分页效果的失效 问题的解决. 参考文章: (1)layui table 表格两种赋值方式下,data分页效果有效, url分页 ...

  4. js + jquery 两栏Tab鼠标移入显示/隐藏的效果(详)

    学习文献: 必须要掌握的原生JS实现JQuery 了解了这些才能开始发挥jQuery的威力 - 谦行 – JavaScript和jQuery两款TAB选项卡示例 -- 西门 jquery原创分享社区 ...

  5. php下雨效果源码,ps下雨效果制作步骤

    ps下雨效果制作步骤:首先打开ps软件,并导入一张图片素材:然后新建一个透明图层,并选择填充工具,将填充图层为白色:接着点击菜单栏的滤镜选项,并在弹出的列表选择像素化:最后在点状化的设置窗口中调整参数 ...

  6. matlab ps液化,photoshop液化工具崩溃怎么办 ps液化工具崩溃解决方法

    photoshop液化工具崩溃怎么办?photoshop液化工具在使用过程中遇到问题了该怎么解决呢?下文小乐哥给大家介绍ps液化工具崩溃解决方法,一起来了解下吧! photoshop液化工具可以令图像 ...

  7. ps国画效果案例制作教程和思路介绍

    内容提要:本文讲述PS国画效果的制作步骤和制作国画效果思路供借鉴使用.对PS感兴趣的朋友可加ps学习交流群:142574315 绘制并拥有一幅国画一直以来都是我的梦想,遗憾的是自己并没有美术功底,此时 ...

  8. html实现纸张撕边效果,PS图片处理教程:PS撕边效果,脸部撕纸效果

    在前面小编给大家讲解了许多关于PS的教程,相信大家已经学到了很多知识吧,今天小编接着给大家带来PS图片处理教程:PS撕边效果,脸部撕纸效果.如何让脸部利用PS处理产生想撕纸一样的效果.下面小编就详细给 ...

  9. PS卡通效果插件Photobacks Cartoon Mac汉化破解教程(含注册码)

    Photobacks Cartoon for Mac是一款适用于Mac操作系统的PS卡通漫画效果插件,可以帮您轻松创建想要的漫画效果.使用Photobacks Cartoon插件您可以轻松地折叠和打开 ...

  10. php实现图片液化,ps液化滤镜怎么用 ps液化滤镜功能教程

    ps液化滤镜主要是用来实现图像的各种特殊效果.滤镜的操作是非常简单的,但是真正用起来却很难恰到好处它在Photoshop 具有神奇的作用.ps液化滤镜可用于推.拉.旋转.反射.折叠和膨胀图像的任意区域 ...

最新文章

  1. docker mysql 生产环境_Docker构建MySQL环境
  2. 元宇宙和我有什么关系?
  3. Paxos与zookeeper
  4. Windows 下 Nginx + PHP5 的安装与配置
  5. [机器学习] 分类 --- Naive Bayes(朴素贝叶斯)
  6. linux添加自己的键盘映射,Linux 键盘映射
  7. zepto为什么不支持animate,报animate is not a function
  8. 举例说明TCP/IP
  9. 超酷的界面原型设计工具Balsamiq Mockups
  10. fastclick.js插件使用简单说明
  11. 怎么改变图片的尺寸?教你在线修改图片尺寸大小
  12. 什么叫弹性计算云服务器,弹性云服务器
  13. Python学习笔记(24)——Greatchao资讯网理财公告信息的selenium挖掘
  14. 用C语言/C++实现一个基础的电话簿
  15. Redis 配置开机自动启动
  16. Transitive attribute传递属性
  17. 大厂 Java 后端经典面试题:Redis 为什么这么快?
  18. 技术点:前端缓存分类及使用
  19. 终极解决重启服务器后mysql启动失败 报 ERROR! The server quit without updating PID file (/var/run/mysqld/mysqld.pid).
  20. KafkaManager安装教程

热门文章

  1. 以数据为中心的路由协议_腰部零售企业如何以数据中台为中心,加速数字化落地...
  2. 有翅膀的java游戏_翅膀只是为了拉风?在这几款游戏中,带上翅膀真的能飞
  3. python打印列表元素_Python打印输出数组中全部元素
  4. 《设计模式:可复用面向对象软件的基础》——引言(笔记)
  5. Typora安装 Pandoc实现导出功能
  6. Begging_Rust(译):做算术(第二章)
  7. kafka报错Error while fetching metadata with correlation
  8. C-NCAP主动安全 ADAS 系统试验方法——相关术语与定义
  9. BigDecimal精度丢失处理
  10. 64位系统装32位计算机,64位电脑装32位系统,教您64位电脑怎么装32位系统