android 特效相机实现,安卓特效相机(三) OpenGL ES 特效渲染

本文详细介绍了如何使用OpenGL ES 2.0在Android上实现特效相机,包括渲染到纹理(RTT)技术、顶点着色器和片元着色器的编写,以及如何利用纹理坐标和变换矩阵实现特效处理。通过创建渲染器、设置顶点信息和颜色特效矩阵,最后实现图像的绘制和双缓冲,从而达到实时的图像特效效果。
摘要由CSDN通过智能技术生成

系列文章:

特效的实现原理

接下来这篇文章我们讲下特效的具体实现原理。

由于预览画面的渲染是将Surface传给CameraDevice由它去绘制的,而且我没有找到什么可以接管或者添加渲染效果的接口,所以并不能直接去处理摄像头的画面。

于是这里我们只能用一种游戏中常用的手段去处理,这种手段的名字叫做RTT(render to texture),中文名叫做渲染到纹理。

玩法是先将我们想要处理的画面,不直接绘制到屏幕,而是绘制成一张图片,然后我们再拿这张图片去做一些特殊的处理,或者特殊的用途:

317ee9355974

5.png

例如游戏中水面的倒影一种比较古老的实现方法就是先将岸上的画面绘制成一张图片,然后倒过来然后做一些扭曲、模糊、淡化等处理,然后贴到水面上。

又例如下面这种狙击镜的实现原理就是先将摄像头位置调到远处,将远处的画面绘制到一张贴图上,然后将摄像头位置再调回角色处,把刚刚得到的远处的画面的图片直接贴到狙击镜上:

317ee9355974

4.jpeg

所以在这个特效相机的例子里面我们的实现原理如下:

317ee9355974

6.png

OpenGL实现

我们使用OpenGL ES 2.0版本,这个版本要求我们用GLSL实现顶点着色器和片元着色器。这两个着色器其实是两个运行在GPU的程序。

GLSL全称是OpenGL Shading Language即OpenGL着色语言,它在语法上和C语言有点像。只是看的话相信大家都能看懂,我就不仔细介绍语法了。

OpenGL可编程渲染管线的整个流程比较复杂,作为初学者我们只要理解其中的顶点着色器和和片元着色器就可以了。简单来讲就是OpenGL会在顶点着色器确定顶点的位置,然后这些顶点连起来就是我们想要的图形。接着在片元着色器里面给这些图形上色:

317ee9355974

1.png

我们直接看看两个着色器的代码。

顶点着色器

OpenGL会将每个顶点的坐标传递给顶点着色器,我们可以在这里改变顶点的位置。例如我们给每个顶点都加上一个偏移,就能实现整个图形的移动。

在这个demo里面我们不改变顶点的坐标,只是简单的将它从二维转换成四维。现实世界里面都是三维的,那为什么要装换成四维呢?原因是我们可以用4*4的矩阵对坐标进行旋转、缩放、平移等变换,但是4*4的矩阵只能和四维向量相乘,所以需要在xyz之外加多一个维度,我们一般情况下直接把这个维度的值设成1就好。然后将计算得到的四维坐标放到gl_Position作为最终结果值:

attribute vec2 vPosition;

attribute vec2 vCoord;

varying vec2 vPreviewCoord;

uniform mat4 matTransform;

void main() {

gl_Position = vec4(vPosition, 0, 1);

vPreviewCoord = (matTransform * vec4(vCoord.xy, 0, 1)).xy;

}

然后除了vPosition这个顶点的坐标,大家还会看到vCoord,它是纹理坐标。什么是纹理坐标呢?

纹理其实可以理解成图片,我们将图片的左下角定义成原点(0,0),左上角、右上角、右下角分别为(0,1)、(1,1)、(1,0):

317ee9355974

2.png

我们的每个顶点,除了携带顶点坐标之外,还携带了纹理坐标的信息,顶点坐标确定了这个图形的形状,而纹理坐标则确定贴图要怎么样贴到这个图形上。然后在片元着色器里面就可以根据这个纹理坐标去给图形贴上贴图了:

317ee9355974

3.png

不过看到代码可以看到,我们这里还用matTransform这个矩阵对纹理坐标进行了变换。这里是由于我们的图片不是普通的图片,而是将摄像头的画面画到另外一个surface之后拿过来的,需要进行变换。这块等下再仔细讲解。

片元顶点着色器

#extension GL_OES_EGL_image_external : require

precision highp float;

varying vec2 vPreviewCoord;

uniform samplerExternalOES texPreview;

uniform mat4 uColorMatrix;

void main() {

gl_FragColor = uColorMatrix * texture2D(texPreview, vPreviewCoord).rgba;

}

片元着色器就比较简单了,第一行是由于我们使用了samplerExternalOES需要开启特殊配置,这个是由于在安卓上我们只能用samplerExternalOES类型的纹理去接收摄像头的画面,而使用samplerExternalOES需要开启GL_OES_EGL_image_external功能。

然后这个texPreview就是我们摄像头画面绘制成的那张图片了,我们用texture2D这个方法去读取图片某个像素的颜色值,它的第一个参数就是我们的纹理,第二个参数就是我们的纹理坐标,也就是上一步顶点着色器计算的到的纹理坐标:

vPreviewCoord = (matTransform * vec4(vCoord.xy, 0, 1)).xy;

这里有同学可能会疑问我们在顶点着色器不是只计算了顶点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值