转场
什么是转场效果?一般来说,就是两个视频画面之间的过渡衔接效果。在opengl中,图片的转场,其实就是两个纹理的过渡切换,一般会有两个纹理作为输入,一个是逐渐消失的纹理,一个是逐渐完全可见的纹理。
在这里推荐一个开源项目,该项目主要用来收集各种GL转场特效及其 GLSL 实现代码,开发者可以很方便地移植到自己的项目中,而且该这个项目网站甚至还支持GLSL的在线编译运行,真是学习GLSL的不二之选。 这个项目网站就是GLTransitions:https://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)
);
}
可以看到该特效比较简单,只有两个控制参数,分别是direction
和progress
,文如其义,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中的转场特效,作为开发者的你怎么将多个转场特效融合成一个,打造出一个数据自己的炫酷特效转场呢?
关注我,一起进步,人生不止coding!!!
本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/28215.html