使用GLSL来实现实时滤镜的效果

news2024/11/17 10:02:35

1. 先来明确几个概念

1.1 OpenGL

OpenGL 全称为 Open Graphics Library(开放图形库)。

用于渲染 2D 或 3D 图像的跨语言跨平台的应用程序编程接口,用于CPU控制GPU做图像渲染,是一套API

提供设计人员一个共同的硬件驱动标准,让开发者不必为每一品牌的硬件来写不同的驱动程序。

1.1.1 历史

  • 1980年代,开发可以用在各种各样图形硬件上的软件是个真正的挑战。通常,软件开发人员为每种硬件编写自定义的接口和驱动程序。但这非常昂贵并会导致大量工作的重复。
  • 20世纪90年代初,SGI成为工作站3D图形领域的领导者。其IRISGL的API被认为是最先进的科技并成为事实上的行业标准,而基于开放标准的PHIGS则相形见绌。IRIS GL更容易使用,而且还支持即时模式的渲染。相比之下,PHIGS难于使用并且功能老旧。
  • SGI的竞争对手(包括Sun、惠普和IBM)通过扩展PHIGS标准也能将3D硬件投入市场。这反过来导致SGI市场份额的削弱,因为有越来越多的3D图形硬件供应商进入市场。为攻占市场,SGI决定把IRIS GL API转变为一项开放标准,即OpenGL。
  • 1992年,SGI公司领导了OpenGL架构审查委员会(OpenGL ARB)的创建。该委员会由若干公司组成,负责未来OpenGL规范的维护和扩展。
  • 微软在1995年发布Direct3D,Direct 3D最终成为OpenGL的主要竞争对手
  • 2002年微软的DirectX 9提出了全新的Shader绘图功能以及高端着色语言(HLSL),OpenGL霸主地位开始被瓦解。这使得OpenGL了解到必须开发全新的OpenGL 2.0版本,加入支持GLSL的功能。
  • 2008年推出OpenGL 3,2010年3月10日, OpenGL同时推出了3.3和4.0版本,同年7月26日又发布了4.1版本。2011年8月8日发布4.2版本。2013年发布4.3版。

1.1.2 Direct3D

另一种程序接口系统是仅用于Microsoft Windows上的Direct3D

DirectX是由很多API组成的,Direct3DdirectX中的一个功能,主要负责3D效果的显示。

在这里插入图片描述

1.1.3 CPU、OpenGL/DirectX、显卡驱动和GPU之间的关系

OpenGLDirectX这些图像应用编程接口,用于渲染二维或三维图形。

可以说,这些接口架起了上层应用程序和底层GPU的沟通桥梁

一个应用程序向这些接口发送渲染命令,而这些接口会依次向显卡驱动(Graphics Driver)发送渲染命令,这些显卡驱动是真正知道如何和GPU通信的角色,正是它们把OpenGL或者DirectX的函数调用翻译成了GPU能够听懂的语言,同时它们也负责把纹理等数据转换成GPU所支持的格式。

1.2 OpenGL ES

OpenGL ES 全称为 OpenGL for Embedded Systems(嵌入式系统开放图形库)。

OpenGL ES 是 OpenGL 的子集,主要针对**嵌入式系统(设备)**设计,去除了 Open GL 中非必要的特性。

1.3 GLSL

GLSL 全称为 OpenGL Shading LanguageOpenGL 着色语言),它是一种 C 语言的变体,是一款在 OpenGL 着色器(Shader)中使用的编程语言,在GPU上执行。

在渲染图形时,主程序会将顶点等数据发送到 GPU,然后 GPU 会使用图形着色器来计算每个像素的最终颜色。图形着色器的输入是顶点数据,输出是像素颜色。

1.4 GLSL ES

GLSL ES 全称为 OpenGL ES Shading LanguageOpenGL ES 着色语言),是在 OpenGL ES 着色器(Shader)中使用的编程语言。

2.几种着色器类型

在2004年,固定管线中只有两个部分能够被替代,顶点处理单元和片段处理单元。这两个可编程处理单元被称为顶点着色器片段着色器。之后又增加了两个新的部分:几何着色器计算着色器,这两个新的部分分别是2008年和2012年加入到官方的OpenGL规范当中。

OpenGL 3.0中有四种着色器

  • 顶点着色器(Vertex Shader

  • 片段着色器(Fragment Shader

  • 几何着色器(Geometry Shader

  • 计算着色器(Compute Shader

在这里插入图片描述

OpenGL 2.0中只有顶点着色器和片段着色器

  • 顶点着色器(Vertex Shader):用于处理顶点(Vertex)变换,即图形上每个顶点的变换(旋转、平移、缩放),主要作用是指定形状。
  • 片段着色器(Fragment Shader):用于处理片段(Fragment)变换,即图形上每个像素点的颜色计算和填充,主要作用是指定颜色。

OpenGL ES 2.0中,顶点着色器和片段着色器是相互独立的,分别由不同的着色器程序实现。着色器程序是OpenGL ES 2.0中的核心计算单元,负责管理图形上每个顶点和像素的变换,以及对每个像素进行颜色计算和填充。

在这里插入图片描述

img

3. GLSL的修饰符与基本数据类型

GLSL的语法与C语言非常类似,对于GLSL,其数据类型表示具体如下

3.1 修饰符

  • const:用于声明非可写的编译时常量变量。

  • attribute:用于经常更改的信息,只能在顶点着色器中使用。

  • uniform:用于不经常更改的信息,可用于顶点着色器和片元着色器。

  • varying:用于修饰从顶点着色器向片元着色器传递的变量。

3.2 基本数据类型

int、float、bool,这些与C语言都是一致的。

需要强调的一点就是,这里面的float是有一个修饰符的,即可以指定精度。三种修饰符的范围(范围一般视显卡而定)和应用情况具体如下。

  • highp:32bit,一般用于顶点坐标(vertex Coordinate)。
  • medium:16bit,一般用于纹理坐标(texture Coordinate)。
  • lowp:8bit,一般用于颜色表示(color)。

3.3 向量类型

向量类型是Shader中非常重要的一个数据类型,因为在做数据传递的时候需要经常传递多个参数,相较于写多个基本数据类型,使用向量类型是非常好的选择。

  • vec2 : 是一个二维向量容器,表示一个包含两个浮点数的向量
  • vec3: 是一个三维向量容器,表示一个包含三个浮点数的向量
  • vec4 : 是一个四维向量容器,表示一个包含四个浮点数的向量

列举一个最经典的例子,要将物体坐标和纹理坐标传递到Vertex Shader中,用的就是向量类型,每一个顶点都是一个四维向量,在Vertex Shader中利用这两个四维向量即可完成自己的纹理坐标映射操作。声明方式如下:

    attribute vec4 position;

3.4 矩阵类型

矩阵类型在Shader的语法中也是一个非常重要的类型,有一些效果需要开发者传入矩阵类型的数据。声明方式如下

    uniform lowp mat4 colorMatrix;

上面的代码表示了一个4×4的浮点矩阵,如果是mat2就是2×2的浮点矩阵,如果是mat3就是3×3的浮点矩阵。

若要传递一个矩阵到实际的Shader中,则可以直接调用如下函数(客户端代码):

    glUniformMatrix4fv(mColorMatrixLocation, 1, false, mColorMatrix);

3.5 纹理类型

一般仅在片段着色器(Fragment Shader)中使用这个类型,二维纹理的声明方式如下 :

    uniform sampler2D texSampler;

当客户端接收到这个句柄时,就可以为它绑定一个纹理,代码如下(客户端代码):

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texId);
    glUniform1i(mGLUniformTexture, 0);

注意上述代码中第一行激活的是哪一个纹理句柄,第三行代码中的第二个参数需要传递对应的Index,就像代码中激活的纹理句柄是GL_TEXTURE0,对应的Index就是0,如果激活的纹理句柄是GL_TEXTURE1,那么对应的Index就是1,在不同的平台上句柄的个数也不一样,但是一般都会在32个以上。

3.6 传递类型

GLSL中有一个特殊的修饰符就是varying,这个修饰符修饰的变量均用于在Vertex ShaderFragment Shader之间传递参数。

首先在顶点着色器中声明这个类型的变量代表纹理的坐标点,并且对这个变量进行赋值

    attribute vec2 texcoord;
    varying vec2 v_texcoord;
    void main(void)
    {
        // 计算顶点坐标
        v_texcoord = texcoord;
    }

紧接着在Fragment Shader中也声明同名的变量,然后使用texture2D方法取出二维纹理中该纹理坐标点上的纹理像素值

    varying vec2 v_texcoord;
    vec4 texel = texture2D(texSampler, v_texcoord);

取出了该坐标点上的像素值之后,就可以进行像素变化操作了,比如说提高对比度,最终将改变的像素值赋值给gl_FragColor

3.7 GLSL的内置函数与内置变量

3.7.1 顶点着色器的内置变量

    vec4 gl_position;

上述代码用来设置顶点转换到屏幕坐标的位置,Vertex Shader一定要去更新这个数值。另外还有一个内置变量,代码如下

    float gl_pointSize;

在粒子效果的场景下,需要为粒子设置大小,改变该内置变量的值就是为了设置每一个粒子矩形的大小。

3.7.2 片段着色器的内置变量

    vec4 gl_FragColor;

上述代码用于指定当前纹理坐标所代表的像素点的最终颜色值。

4. 实现的滤镜效果

原图

在这里插入图片描述

温暖

precision mediump float;
uniform sampler2D uTextureSampler;
varying vec2 vTextureCoord;

const highp vec3 WARM = vec3(0.1, 0.1, 0.0);

void main()
{
    vec4 tempColor = texture2D(uTextureSampler, vTextureCoord);
    gl_FragColor = tempColor+vec4(WARM,0.0);
}

在这里插入图片描述

寒冷

precision mediump float;
uniform sampler2D uTextureSampler;
varying vec2 vTextureCoord;

const highp vec3 COOL = vec3(0.0, 0.0, 0.1);

void main()
{
    vec4 tempColor = texture2D(uTextureSampler, vTextureCoord);
    gl_FragColor = tempColor+vec4(COOL,0.0);
}

在这里插入图片描述

底片

precision mediump float;
uniform sampler2D uTextureSampler;
varying vec2 vTextureCoord;
void main()
{
    vec4 tempColor = texture2D(uTextureSampler, vTextureCoord);
    gl_FragColor = vec4((1.0 - tempColor.rgb), tempColor.w);
}

在这里插入图片描述

旧照

precision mediump float;
uniform sampler2D uTextureSampler;
varying vec2 vTextureCoord;
const lowp float intensityone = 1.0;
const lowp mat4 colorMatrix = mat4(0.3588, 0.7044, 0.1368, 0.0,0.2990, 0.5870, 0.1140, 0.0,0.2392, 0.4696, 0.0912, 0.0,0, 0, 0, 1.0);
void main()
{
    vec4 tempColor = texture2D(uTextureSampler, vTextureCoord);
    lowp vec4 outputColor = tempColor * colorMatrix;
    gl_FragColor = (intensityone * outputColor) + ((1.0 - intensityone) * tempColor);
}

在这里插入图片描述

梦幻

precision mediump float;
uniform sampler2D uTextureSampler;
varying vec2 vTextureCoord;

void main() {
    vec4 textureColor = texture2D(uTextureSampler, vTextureCoord);

    float redCurveValue = texture2D(uTextureSampler, vec2(textureColor.r, 0.0)).r;
    float greenCurveValue = texture2D(uTextureSampler, vec2(textureColor.g, 0.0)).g;
    float blueCurveValue = texture2D(uTextureSampler, vec2(textureColor.b, 0.0)).b;

    gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a);
}

在这里插入图片描述

浮雕

precision mediump float;
uniform sampler2D uTextureSampler;
varying vec2 vTextureCoord;

const vec2 texSize = vec2(1920,1080);

void main() {
    vec4 textureColor = texture2D(uTextureSampler, vTextureCoord);

    vec2 tex = vTextureCoord;
    vec2 upLeftUV = vec2(tex.x - 1.0/texSize.x, tex.y - 1.0/texSize.y);
    vec4 upLeftColor = texture2D(uTextureSampler,upLeftUV);
    vec4 delColor = textureColor - upLeftColor;
    float h = 0.3*delColor.x + 0.59*delColor.y + 0.11*delColor.z;
    vec4 bkColor = vec4(0.5, 0.5, 0.5, 1.0);
    gl_FragColor = vec4(h,h,h,0.0) + bkColor;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-885DPHJk-1683115513180)(D:\文档\GLSL\GLSL.assets\cameo.jpg)]

黑白

precision mediump float;
uniform sampler2D uTextureSampler;
varying vec2 vTextureCoord;
void main()
{
    vec4 tempColor = texture2D(uTextureSampler, vTextureCoord);
    // Get the grayscale value of each pixel
    float luminance = tempColor.r * 0.299 + tempColor.g * 0.584 + tempColor.b * 0.114;
    gl_FragColor = vec4(vec3(luminance), tempColor.a);
}

在这里插入图片描述

5. 参考

一张图搞懂CPU、OpenGL/DirectX、显卡驱动和GPU之间的关系_opengl和gpu的关系_王 炸的博客-CSDN博客

GLSL基础概念(绝对看得懂)_我想要身体健康的博客-CSDN博客

GLSL基础(上)(OpenGL Shading Language) - 知乎 (zhihu.com)

GLSL简介 - 哔哩哔哩 (bilibili.com)

OpenGL(一) OpenGL入门 - 简书 (jianshu.com)

GLSL - 百度百科

《音视频开发进阶指南》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/486242.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

虚函数、静态绑定和动态绑定

静态绑定 class Base { public:Base(int data) :ma(data) {}void show() { cout << "Base::show()" << endl; }void show(int) { cout << "Base::show(int)" << endl; }protected:int ma; };class Derive : public Base { public…

Go | 一分钟掌握Go | 10 - 反射

作者&#xff1a;Mars酱 声明&#xff1a;本文章由Mars酱编写&#xff0c;部分内容来源于网络&#xff0c;如有疑问请联系本人。 转载&#xff1a;欢迎转载&#xff0c;转载前先请联系我&#xff01; 前言 反射你以为只在Java中有吗&#xff1f;Go也有反射机制&#xff0c;很多…

【JavaEE】应用层自定义协议及UDP协议

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 本篇文章将为大家介绍应用层中UDP协议~~ 在应用层这里&#xff0c;虽然存在一些现有的协议&#xff08;HTTP&#xff09;&#xff0c;但是也有很多情况&#xff0c;需要程序猿自定制协议&a…

OJ 功能介绍 使用手册

目录 服务器配置 OJ界面展示 用户管理 一、批量导入&#xff08;从方便管理角度建议以 学生姓名 作为 用户名 &#xff09; 二、批量生成临时用户 后期修改成需要的用户名和密码 &#xff08;学生登录后修改密码&#xff09; 三、用户自行注册&#xff08;填写邮箱获取验证码…

Nmap入门到高级【第九章】

预计更新Nmap基础知识 1.1 Nmap简介和历史 1.2 Nmap安装和使用方法 1.3 Nmap扫描技术和扫描选项 Nmap扫描技术 2.1 端口扫描技术 2.2 操作系统检测技术 2.3 服务和应用程序检测技术 2.4 漏洞检测技术 Nmap扫描选项 3.1 扫描类型选项 3.2 过滤器选项 3.3 探测选项 3.4 输出选项…

【致敬未来的攻城狮计划】— 连续打卡第二十天:RA2E1_UART —— 串口通信例程

系列文章目录 1.连续打卡第一天&#xff1a;提前对CPK_RA2E1是瑞萨RA系列开发板的初体验&#xff0c;了解一下 2.开发环境的选择和调试&#xff08;从零开始&#xff0c;加油&#xff09; 3.欲速则不达&#xff0c;今天是对RA2E1 基础知识的补充学习。 4.e2 studio 使用教程 5.…

Docker consul服务注册与发现

目录 一、服务注册与发现 1、什么是服务注册与发现 2、什么是consul 3、consul提供的一些关键特性 4、容器更新与发现 二、基于nginx与consul构建自动发现即高可用的Docker服务架构 consul服务器部署 1、建立consul 2、查看集群信息 3、通过http获取集群信息 regist…

SpringBoot+vue文件上传下载预览分片上传

学习链接 Blob & File 上传文件 前台 整个过程&#xff0c;就是在使用FormData 添加 上File&#xff08;这个Blob&#xff09;&#xff0c;并且key要和后台的名字对应上在点击上传按钮开始上传之前&#xff0c;使用了URL.createObjectURL(File)创建blobUrl&#xff0c;…

MySQL数据库之库表管理

一、常用的数据类型&#xff1a; 类型含义tinyint(n)1个字节&#xff0c;范围(-128~127)smallint(n)2个字节&#xff0c;范围(-32768~32767)mediumint(n)3个字节&#xff0c;范围(-8388608~8388607)int(n)4个字节(32个比特位)&#xff0c;整数型&#xff0c;范围(-2147483648~…

JavaEE - 网络编程

一、网络编程基础 为什么需要网络编程&#xff1f; 用户在浏览器中&#xff0c;打开在线视频网站&#xff0c;如优酷看视频&#xff0c;实质是通过网络&#xff0c;获取到网络上的一个视频资源。 与本地打开视频文件类似&#xff0c;只是视频文件这个资源的来源是网络。 相比本…

KALI入门到高级【第五章】

预计更新第一章 入门 1.1 什么是Kali Linux&#xff1f; 1.2 安装Kali Linux 1.3 Kali Linux桌面环境介绍 1.4 基本命令和工具 第二章 信息收集 1.1 网络扫描 1.2 端口扫描 1.3 漏洞扫描 1.4 社交工程学 第三章 攻击和渗透测试 1.1 密码破解 1.2 暴力破解 1.3 漏洞利用 1.4 特…

模糊PID(模糊规则表)

模糊PID的模糊化相关内容,请参看下面的博客文章: PLC模糊控制模糊PID(梯形图实现+算法分析)_RXXW_Dor的博客-CSDN博客博途PLC的模糊PID控制详细内容请查看下面的博客文章:Matlab仿真+博途PLC模糊PID控制完整SCL源代码参考(带模糊和普通PID切换功能)_博途怎么实现模糊pid_…

后端程序员的前端必备【Vue】 - 05 class与style绑定、表单输入绑定、Vue生命周期

class与style绑定、表单输入绑定、Vue生命周期 1 class与style绑定1.1 绑定class1.2 绑定style1.3 练习 2 表单输入绑定3 Vue生命周期3.1 vue生命周期3.2 组件的生命周期钩子 1 class与style绑定 操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是 attri…

【操作系统】操作系统内核

图灵机 当系统中有一个CPU的时候 &#xff0c;MR就是它的状态 当系统中有n个CPU的时候&#xff0c;MR1,MR2…MRn 是它的状态 IRQ和NMI是低电平有效信号 NMI不可屏蔽中断 6502的CPU一共40个引脚 eflags寄存器里的 IF 表示 interrupt enable 1表示可以响应中断&#xff0c;0表示…

破解马赛克有多「容易」?

刷短视频时&#xff0c;估计大家都看过下面这类视频&#xff0c;各家营销号争相曝光「一分钟解码苹果笔刷背后内容」的秘密。换汤不换药&#xff0c;自媒体们戏称其为「破解马赛克」&#xff0c;殊不知让多少不明真相的用户建立起了错误的认知&#xff0c;也让苹果笔刷第 10086…

【网络编程】demo版UDP网络服务器实现

文章目录 一、引入二、服务端实现2.1 创建套接字socket2.2 绑定bind2.3 启动服务器2.4 IP的绑定2.5 读取数据recvfrom 三、用户端实现3.1 绑定问题3.2 发送数据sendto 四、源码 一、引入 在上一章【网络编程】socket套接字中我们讲述了TCP/UDP协议&#xff0c;这一篇就是简单实…

保护移动设备免受恶意软件侵害优秀方法

几天前&#xff0c;移动恶意软件攻击增加了500%显然&#xff0c;我们大多数人都不知道不能很好地保护我们的手机下面小编揭秘有效保护移动设备免受恶意软件侵害的最佳方法。 1、使用移动反恶意软件 恶意软件很容易感染智能手机和平板电脑&#xff0c;因此在设备上安装可靠的…

douyin 之xgorgon0404参数

如果我们想要看抖音的数据&#xff0c;在抓包的时候&#xff0c;会发现有一个xgorgon参数,在请求接口的时候&#xff0c;只需要在请求头携带xgorgon参数&#xff0c;就能获得响应后的数据。 目前抖音的xgorgon0404算法已经还原了&#xff0c; 下面是一个请求的demo。代码如下:…

计算机网络可靠传输的三种基本实现机制

可靠传输的means 在数据链路层会给上层网络层提供可靠传输或者不可靠传输&#xff0c;不可靠传输是指检测到传输差错的时候只是丢弃该分组而不进行任何处理&#xff0c;而可靠传输会给发送者一个信号进行重发该分组。 以下给出的三种基本实现机制是提出一些问题&#xff0c;慢…

截图的背景色如何去除?这里介绍一个小工具

屏幕截图&#xff0c;是方便常用的功能。例如从网页或者视频中截图。但是有时候想去除截图中的背景颜色&#xff0c;怎么办&#xff1f;下面这个案例介绍如何去掉截图中的蓝色背景色。 这个小工具就能帮你方便实现。Web端的便捷小工具链接: http://www.artvily.com/renderCase…