怎么使用Android OpenGL ES实现抖音传送带特效(android,es,opengl,开发技术)

时间:2024-05-03 05:09:10 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

抖音传送带特效原理

抖音传送带特效推出已经很长一段时间了,前面也实现了下,最近把它整理出来了,如果你有仔细观测传送带特效,就会发现它的实现原理其实很简单。

怎么使用Android OpenGL ES实现抖音传送带特效

通过仔细观察抖音的传送带特效,你可以发现左侧是不停地更新预览画面,右侧看起来就是一小格一小格的竖条状图像区域不断地向右移动,一直移动到右侧边界位置。

预览的时候每次拷贝一小块预览区域的图像送到传送带,这就形成了源源不断地向右传送的效果。

原理图进行了简化处理, 实际上右侧的竖条图像更多,效果会更流畅,每来一帧预览图像,首先拷贝更新左侧预览画面,然后从最右侧的竖条图像区域开始拷贝图像(想一想为什么?)。

例如将区域 2 的像素拷贝到区域 3 ,然后将区域 1 的像素拷贝到区域 2,以此类推,最后将来源区域的像素拷贝到区域 0 。

这样就形成了不断传送的效果,最后将拷贝好的图像更新到纹理,利用 OpenGL 渲染到屏幕上。

抖音传送带特效实现

上节原理分析时,将图像区域从左侧到右侧拷贝并不高效,可能会导致一些性能问题,好在 Android 相机出图都是横向的(旋转了 90 或 270 度),这样图像区域上下拷贝效率高了很多,最后渲染的时候再将图像旋转回来。

Android 相机出图是 YUV 格式的,这里为了拷贝处理方便,先使用 OpenCV 将 YUV 图像转换为 RGBA 格式,当然为了追求性能直接使用 YUV 格式的图像问题也不大。

cv::Matmati420=cv::Mat(pImage->height*3/2,pImage->width,CV_8UC1,pImage->ppPlane[0]);cv::MatmatRgba=cv::Mat(m_SrcImage.height,m_SrcImage.width,CV_8UC4,m_SrcImage.ppPlane[0]);cv::cvtColor(mati420,matRgba,CV_YUV2RGBA_I420);

用到的着色器程序就是简单的贴图:

#version300eslayout(location=0)invec4a_position;layout(location=1)invec2a_texCoord;uniformmat4u_MVPMatrix;outvec2v_texCoord;voidmain(){gl_Position=u_MVPMatrix*a_position;v_texCoord=a_texCoord;}#version300esprecisionmediumpfloat;invec2v_texCoord;layout(location=0)outvec4outColor;uniformsampler2Du_texture;voidmain(){outColor=texture(u_texture,v_texCoord);}

传送带的核心就是图像拷贝操作:

memcpy(m_RenderImage.ppPlane[0],m_SrcImage.ppPlane[0],m_RenderImage.width*m_RenderImage.height*4/2);//左侧预览区域像素拷贝intbannerHeight=m_RenderImage.height/2/m_bannerNum;//一个banner的高(小竖条)intbannerPixelsBufSize=m_RenderImage.width*bannerHeight*4;//一个banner占用的图像内存uint8*pBuf=m_RenderImage.ppPlane[0]+m_RenderImage.width*m_RenderImage.height*4/2;//传送带分界线//从最右侧的竖条图像区域开始拷贝图像for(inti=m_bannerNum-1;i>=1;--i){memcpy(pBuf+i*bannerPixelsBufSize,pBuf+(i-1)*bannerPixelsBufSize,bannerPixelsBufSize);}//将来源区域的像素拷贝到竖条图像区域0memcpy(pBuf,pBuf-bannerPixelsBufSize,bannerPixelsBufSize);

渲染操作:

glUseProgram(m_ProgramObj);glBindVertexArray(m_VaoId);glUniformMatrix4fv(m_MVPMatLoc,1,GL_FALSE,&m_MVPMatrix[0][0]);//图像拷贝,传送带拷贝memcpy(m_RenderImage.ppPlane[0],m_SrcImage.ppPlane[0],m_RenderImage.width*m_RenderImage.height*4/2);intbannerHeight=m_RenderImage.height/2/m_bannerNum;intbannerPixelsBufSize=m_RenderImage.width*bannerHeight*4;uint8*pBuf=m_RenderImage.ppPlane[0]+m_RenderImage.width*m_RenderImage.height*4/2;//传送带分界线for(inti=m_bannerNum-1;i>=1;--i){memcpy(pBuf+i*bannerPixelsBufSize,pBuf+(i-1)*bannerPixelsBufSize,bannerPixelsBufSize);}memcpy(pBuf,pBuf-bannerPixelsBufSize,bannerPixelsBufSize);//更新纹理glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D,m_TextureId);glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,m_RenderImage.width,m_RenderImage.height,0,GL_RGBA,GL_UNSIGNED_BYTE,m_RenderImage.ppPlane[0]);glBindTexture(GL_TEXTURE_2D,GL_NONE);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D,m_TextureId);GLUtils::setInt(m_ProgramObj,"u_texture",0);glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,(constvoid*)0);glBindVertexArray(GL_NONE);
 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:怎么使用Android OpenGL ES实现抖音传送带特效的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:JavaScript实现继承的常用方式有哪些下一篇:

5 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18