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

转场

什么是转场作用?一般来说,便是两个视频画面之间的过渡衔接作用。在opengl中,图片的转场,其实便是两个纹路的过渡切换,一般会有两个纹路作为输入,一个是逐步消失的纹路,一个是逐步彻底可见的纹路。

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

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

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

Opengl ES之转场动画

上图中的transition便是封装的转场函数,其间参数uv表明的是纹路坐标,getFromColor(uv) 表明对较要消失的纹路进行采样,getToColor(uv)表明对将要出场的方针纹路进行采样。 然后运用mix进行纹路融合输出。

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

转场移植

本着将开源包装一下便是自主研发的学习精神,这儿咱们将这个从上往下的转场作用移植到Opengl ES中去。

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

// Author: Gatan 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之转场动画

结合咱们之前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被移除的兼容性问题