Opengl ES之转场动画

本文正在参加「金石计划」

转场

什么是转场效果?一般来说,就是两个视频画面之间的过渡衔接效果。在opengl中,图片的转场,其实就是两个纹理的过渡切换,一般会有两个纹理作为输入,一个是逐渐消失的纹理,一个是逐渐完全可见的纹理。

在这里推荐一个开源项目,该项目主要用来收集各种GL转场特效及其 GLSL 实现代码,开发者可以很方便地移植到自己的项目中,而且该这个项目网站甚至还支持GLSL的在线编译运行,真是学习GLSL的不二之选。
这个项目网站就是GLTransitions:gl-transitions.com/gallery

这个项目有一百多张转场特效,这些特效对于想要学习opengl转场的童鞋们来说确是首选推荐。

比如在这里必须按随便选一个从上往下出现的转场特效点进进去,即可查阅看到相关的着色器代码以及参数说明:

上图中的transition就是封装的转场函数,其中参数uv表示的是纹理坐标,getFromColor(uv) 表示对较要消失的纹理进行采样,getToColor(uv)表示对将要进场的目标纹理进行采样。
然后使用mix进行纹理融合输出。

我的天,开源就是这么简单…

转场移植

本着将开源包装一下就是自主研发的学习精神,这里我们将这个从上往下的转场效果移植到Opengl ES中去。

首先我们在GLTransitions中找到该转场特效,然后点击选中Editor菜单,看到它的着色器转场函数如下:

// Author: Gaëtan Renaudeau
// License: MIT

uniform vec2 direction; // = vec2(0.0, 1.0)

vec4 transition (vec2 uv) {
  vec2 p = uv + progress * sign(direction);
  vec2 f = fract(p);
  return mix(
    getToColor(f),
    getFromColor(f),
    step(0.0, p.y) * step(p.y, 1.0) * step(0.0, p.x) * step(p.x, 1.0)
  );
}

可以看到该特效比较简单,只有两个控制参数,分别是directionprogress,文如其义,direction表示方向,通过这个变量可以控制特效的方向,例如从上往下,从左往右,甚至从右上角到左下角等,
progress则表示转场的进度,这个值应该在0到1之间,比如该转场持续30帧画面,当第15帧时progress的值应该是0.5,progress=15/30=0.5。

按照以上意思,那么在Opengl ES中该特效移植后完整的着色器代码如下:

#version 300 es
precision mediump float;
uniform vec2 direction;
uniform float progress;
uniform sampler2D u_texture_01;
uniform sampler2D u_texture_02;
in vec2 TexCoord;
out vec4 FragColor;
vec4 transition (vec2 uv) {
    vec2 p = uv + progress * sign(direction);
    vec2 f = fract(p);
    return mix(
        texture(u_texture_01, f),
        texture(u_texture_02, f),
        step(0.0, p.y) * step(p.y, 1.0) * step(0.0, p.x) * step(p.x, 1.0)
    );
}

void main(){
    FragColor = transition(TexCoord);
}

放码过来

结合我们之前Opengl ES系列教程封装好的开发环境,完整的转场渲染代码如下:

TransitionOpengl.cpp


#include "TransitionOpengl.h"
#include "../utils/Log.h"

// 顶点着色器
static const char *ver = "#version 300 es\n"
                         "in vec4 aPosition;\n"
                         "in vec2 aTexCoord;\n"
                         "out vec2 TexCoord;\n"
                         "void main() {\n"
                         "  TexCoord = aTexCoord;\n"
                         "  gl_Position = aPosition;\n"
                         "}";

// 片元着色器
static const char *fragment = "#version 300 es\n"
                              "precision mediump float;\n"
                              "uniform vec2 direction;\n"
                              "uniform float progress;\n"
                              "uniform sampler2D u_texture_01;\n"
                              "uniform sampler2D u_texture_02;\n"
                              "in vec2 TexCoord;\n"
                              "out vec4 FragColor;\n"
                              "vec4 transition (vec2 uv) {\n"
                              "    vec2 p = uv + progress * sign(direction);\n"
                              "    vec2 f = fract(p);\n"
                              "    return mix(\n"
                              "        texture(u_texture_01, f),\n"
                              "        texture(u_texture_02, f),\n"
                              "        step(0.0, p.y) * step(p.y, 1.0) * step(0.0, p.x) * step(p.x, 1.0)\n"
                              "    );\n"
                              "}\n"
                              "\n"
                              "void main(){\n"
                              "    FragColor = transition(TexCoord);\n"
                              "}";

// 动画总帧数
static const long ALL_FRAME = 60;

// 使用绘制两个三角形组成一个矩形的形式(三角形带)
// 第一第二第三个点组成一个三角形,第二第三第四个点组成一个三角形
const static GLfloat VERTICES[] = {
        0.5f,-0.5f, // 右下
        0.5f,0.5f, // 右上
        -0.5f,-0.5f, // 左下
        -0.5f,0.5f // 左上
};

const static GLfloat TEXTURE_COORD[] = {
        1.0f,1.0f, // 右下
        1.0f,0.0f, // 右上
        0.0f,1.0f, // 左下
        0.0f,0.0f // 左上
};

TransitionOpengl::TransitionOpengl() {
    initGlProgram(ver,fragment);
    positionHandle = glGetAttribLocation(program,"aPosition");
    textureHandle = glGetAttribLocation(program,"aTexCoord");
    textureSampler_01 = glGetUniformLocation(program,"u_texture_01");
    textureSampler_02 = glGetUniformLocation(program,"u_texture_02");
    directionHandle = glGetUniformLocation(program,"direction");
    progressHandle = glGetUniformLocation(program,"progress");
    LOGD("program:%d",program);
    LOGD("positionHandle:%d",positionHandle);
    LOGD("textureHandle:%d",textureHandle);
}

TransitionOpengl::~TransitionOpengl() noexcept {
    LOGD("TransitionOpengl析构函数");
    glDeleteTextures(1,&textureId_01);
    glDeleteTextures(1,&textureId_02);
}

void TransitionOpengl::setPixel(void *data, int width, int height, int length) {
    LOGD("texture setPixel");
    glGenTextures(1, &textureId_01);

    // 绑定纹理
    glBindTexture(GL_TEXTURE_2D, textureId_01);
    // 为当前绑定的纹理对象设置环绕、过滤方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    // 生成mip贴图
    glGenerateMipmap(GL_TEXTURE_2D);
    // 解绑定
    glBindTexture(GL_TEXTURE_2D, 0);
}

void TransitionOpengl::setPixel2(void *data, int width, int height, int length) {
    LOGD("texture setPixel2");
    LOGD("texture setPixel");
    glGenTextures(1, &textureId_02);

    // 绑定纹理
    glBindTexture(GL_TEXTURE_2D, textureId_02);
    // 为当前绑定的纹理对象设置环绕、过滤方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    // 生成mip贴图
    glGenerateMipmap(GL_TEXTURE_2D);
    // 解绑定
    glBindTexture(GL_TEXTURE_2D, 0);
}


void TransitionOpengl::onDraw() {
    glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(program);

    // 控制方向 下往上
//    glUniform2f(directionHandle,0 ,1);

    // 控制方向 上往下
    glUniform2f(directionHandle,0 ,-1);

    // 控制进度 0到1之间
    float progress = (currentFrame % ALL_FRAME) * 1.0f / ALL_FRAME;
    currentFrame++;
    glUniform1f(progressHandle,progress);

    // 激活纹理
    glActiveTexture(GL_TEXTURE1);
    glUniform1i(textureSampler_01, 1);

    // 绑定纹理
    glBindTexture(GL_TEXTURE_2D, textureId_01);

    // 激活纹理
    glActiveTexture(GL_TEXTURE2);
    glUniform1i(textureSampler_02, 2);

    // 绑定纹理
    glBindTexture(GL_TEXTURE_2D, textureId_02);

    /**
     * size 几个数字表示一个点,显示是两个数字表示一个点
     * normalized 是否需要归一化,不用,这里已经归一化了
     * stride 步长,连续顶点之间的间隔,如果顶点直接是连续的,也可填0
     */
    // 启用顶点数据
    glEnableVertexAttribArray(positionHandle);
    glVertexAttribPointer(positionHandle,2,GL_FLOAT,GL_FALSE,0,VERTICES);

    // 纹理坐标
    glEnableVertexAttribArray(textureHandle);
    glVertexAttribPointer(textureHandle,2,GL_FLOAT,GL_FALSE,0,TEXTURE_COORD);

    // 4个顶点绘制两个三角形组成矩形
    glDrawArrays(GL_TRIANGLE_STRIP,0,4);

    glUseProgram(0);

    // 禁用顶点
    glDisableVertexAttribArray(positionHandle);
    if(nullptr != eglHelper){
        eglHelper->swapBuffers();
    }

    glBindTexture(GL_TEXTURE_2D, 0);
}

思考

以上是单个转场的特效效果,如今的短视频编辑软件对于转场的处理都是特别的炫酷的,细细研究分解不难发现其实它们都是多种转场的融合,而不仅仅是使用单一的转场特效,那么针对GLTransitions
中的转场特效,作为开发者的你怎么将多个转场特效融合成一个,打造出一个数据自己的炫酷特效转场呢?

Opengl ES系列入门介绍

Opengl ES之EGL环境搭建
Opengl ES之着色器
Opengl ES之三角形绘制
Opengl ES之四边形绘制
Opengl ES之纹理贴图
Opengl ES之VBO和VAO
Opengl ES之EBO
Opengl ES之FBO
Opengl ES之PBO
Opengl ES之YUV数据渲染
YUV转RGB的一些理论知识
Opengl ES之RGB转NV21
Opengl ES之踩坑记
Opengl ES之矩阵变换(上)
Opengl ES之矩阵变换(下)
Opengl ES之水印贴图
Opengl ES之纹理数组
OpenGL ES之多目标渲染(MRT
Opengl ES之LUT滤镜(上)
Opengl ES之LUT滤镜(下)-3DLUT
OpenglES之分屏滤镜
Opengl中GL_LUMINANCE被移除的兼容性问题

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MY5mqbSS' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片