使用两个FBO互相绑定实现PS液化效果
最终效果如下(旋转效果和膨胀放大效果作为例子):
使用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液化效果相关推荐
- 使用两个FBO互相绑定实现PS液化效果(2)_使用PBO保存FBO当前画面
之前的文章(11条消息) 使用两个FBO互相绑定实现PS液化效果_cjzcjl的博客-CSDN博客 基于两个FBO之间,互相错开使用,互为纹理和输出FrameBuffer,实现效果在两个FBO之间不断 ...
- [FFMpeg开发]视频转高质量GIF优化方案(接近ps生成效果),从原理剖析
摘要 虽然此前有人发过了,但是这个博主没有分析原理并且没有提炼出来.不适合开发者学习. 所以我只是进行二次优化,原文高质量视频转gif 此前,做产品的时候,产品用到了ffmpeg框架,手上几个ffmp ...
- layui table 表格两种赋值方式下,data分页效果有效, url分页效果的失效 问题的解决。
layui table 表格两种赋值方式下,data分页效果有效, url分页效果的失效 问题的解决. 参考文章: (1)layui table 表格两种赋值方式下,data分页效果有效, url分页 ...
- js + jquery 两栏Tab鼠标移入显示/隐藏的效果(详)
学习文献: 必须要掌握的原生JS实现JQuery 了解了这些才能开始发挥jQuery的威力 - 谦行 – JavaScript和jQuery两款TAB选项卡示例 -- 西门 jquery原创分享社区 ...
- php下雨效果源码,ps下雨效果制作步骤
ps下雨效果制作步骤:首先打开ps软件,并导入一张图片素材:然后新建一个透明图层,并选择填充工具,将填充图层为白色:接着点击菜单栏的滤镜选项,并在弹出的列表选择像素化:最后在点状化的设置窗口中调整参数 ...
- matlab ps液化,photoshop液化工具崩溃怎么办 ps液化工具崩溃解决方法
photoshop液化工具崩溃怎么办?photoshop液化工具在使用过程中遇到问题了该怎么解决呢?下文小乐哥给大家介绍ps液化工具崩溃解决方法,一起来了解下吧! photoshop液化工具可以令图像 ...
- ps国画效果案例制作教程和思路介绍
内容提要:本文讲述PS国画效果的制作步骤和制作国画效果思路供借鉴使用.对PS感兴趣的朋友可加ps学习交流群:142574315 绘制并拥有一幅国画一直以来都是我的梦想,遗憾的是自己并没有美术功底,此时 ...
- html实现纸张撕边效果,PS图片处理教程:PS撕边效果,脸部撕纸效果
在前面小编给大家讲解了许多关于PS的教程,相信大家已经学到了很多知识吧,今天小编接着给大家带来PS图片处理教程:PS撕边效果,脸部撕纸效果.如何让脸部利用PS处理产生想撕纸一样的效果.下面小编就详细给 ...
- PS卡通效果插件Photobacks Cartoon Mac汉化破解教程(含注册码)
Photobacks Cartoon for Mac是一款适用于Mac操作系统的PS卡通漫画效果插件,可以帮您轻松创建想要的漫画效果.使用Photobacks Cartoon插件您可以轻松地折叠和打开 ...
- php实现图片液化,ps液化滤镜怎么用 ps液化滤镜功能教程
ps液化滤镜主要是用来实现图像的各种特殊效果.滤镜的操作是非常简单的,但是真正用起来却很难恰到好处它在Photoshop 具有神奇的作用.ps液化滤镜可用于推.拉.旋转.反射.折叠和膨胀图像的任意区域 ...
最新文章
- docker mysql 生产环境_Docker构建MySQL环境
- 元宇宙和我有什么关系?
- Paxos与zookeeper
- Windows 下 Nginx + PHP5 的安装与配置
- [机器学习] 分类 --- Naive Bayes(朴素贝叶斯)
- linux添加自己的键盘映射,Linux 键盘映射
- zepto为什么不支持animate,报animate is not a function
- 举例说明TCP/IP
- 超酷的界面原型设计工具Balsamiq Mockups
- fastclick.js插件使用简单说明
- 怎么改变图片的尺寸?教你在线修改图片尺寸大小
- 什么叫弹性计算云服务器,弹性云服务器
- Python学习笔记(24)——Greatchao资讯网理财公告信息的selenium挖掘
- 用C语言/C++实现一个基础的电话簿
- Redis 配置开机自动启动
- Transitive attribute传递属性
- 大厂 Java 后端经典面试题:Redis 为什么这么快?
- 技术点:前端缓存分类及使用
- 终极解决重启服务器后mysql启动失败 报 ERROR! The server quit without updating PID file (/var/run/mysqld/mysqld.pid).
- KafkaManager安装教程
热门文章
- 以数据为中心的路由协议_腰部零售企业如何以数据中台为中心,加速数字化落地...
- 有翅膀的java游戏_翅膀只是为了拉风?在这几款游戏中,带上翅膀真的能飞
- python打印列表元素_Python打印输出数组中全部元素
- 《设计模式:可复用面向对象软件的基础》——引言(笔记)
- Typora安装 Pandoc实现导出功能
- Begging_Rust(译):做算术(第二章)
- kafka报错Error while fetching metadata with correlation
- C-NCAP主动安全 ADAS 系统试验方法——相关术语与定义
- BigDecimal精度丢失处理
- 64位系统装32位计算机,64位电脑装32位系统,教您64位电脑怎么装32位系统