Android OpenGL ES 實現(xiàn)抖音傳送帶特效(原理解析)
抖音 APP 真是個好東西,不過也容易上癮,老實說你的抖音是不是反復卸載又反復安裝了,后來我也發(fā)現(xiàn)我的幾個 leader 都不刷抖音,這令我挺吃驚的。
我刷抖音主要是為了看新聞,聽一些大 V 講歷史,研究抖音的一些算法特效,最重要的是抖音提供了一個年輕人的視角去觀察世界。另外,自己感興趣的內容看多了,反而訓練抖音推送更多類似的優(yōu)質內容,大家可以反向利用抖音的這一特點。
至于我的 leader 老是強調刷抖音不好,對此我并不完全認同。
抖音傳送帶特效原理
抖音傳送帶特效推出已經(jīng)很長一段時間了,前面也實現(xiàn)了下,最近把它整理出來了,如果你有仔細觀測傳送帶特效,就會發(fā)現(xiàn)它的實現(xiàn)原理其實很簡單。
通過仔細觀察抖音的傳送帶特效,你可以發(fā)現(xiàn)左側是不停地更新預覽畫面,右側看起來就是一小格一小格的豎條狀圖像區(qū)域不斷地向右移動,一直移動到右側邊界位置。
預覽的時候每次拷貝一小塊預覽區(qū)域的圖像送到傳送帶,這就形成了源源不斷地向右傳送的效果。
原理圖進行了簡化處理, 實際上右側的豎條圖像更多,效果會更流暢,每來一幀預覽圖像,首先拷貝更新左側預覽畫面,然后從最右側的豎條圖像區(qū)域開始拷貝圖像(想一想為什么?)。
例如將區(qū)域 2 的像素拷貝到區(qū)域 3 ,然后將區(qū)域 1 的像素拷貝到區(qū)域 2,以此類推,最后將來源區(qū)域的像素拷貝到區(qū)域 0 。
這樣就形成了不斷傳送的效果,最后將拷貝好的圖像更新到紋理,利用 OpenGL 渲染到屏幕上。
抖音傳送帶特效實現(xiàn)
上節(jié)原理分析時,將圖像區(qū)域從左側到右側拷貝并不高效,可能會導致一些性能問題,好在 Android 相機出圖都是橫向的(旋轉了 90 或 270 度),這樣圖像區(qū)域上下拷貝效率高了很多,最后渲染的時候再將圖像旋轉回來。
Android 相機出圖是 YUV 格式的,這里為了拷貝處理方便,先使用 OpenCV 將 YUV 圖像轉換為 RGBA 格式,當然為了追求性能直接使用 YUV 格式的圖像問題也不大。
cv::Mat mati420 = cv::Mat(pImage->height * 3 / 2, pImage->width, CV_8UC1, pImage->ppPlane[0]); cv::Mat matRgba = cv::Mat(m_SrcImage.height, m_SrcImage.width, CV_8UC4, m_SrcImage.ppPlane[0]); cv::cvtColor(mati420, matRgba, CV_YUV2RGBA_I420);
用到的著色器程序就是簡單的貼圖:
#version 300 es layout(location = 0) in vec4 a_position; layout(location = 1) in vec2 a_texCoord; uniform mat4 u_MVPMatrix; out vec2 v_texCoord; void main() { gl_Position = u_MVPMatrix * a_position; v_texCoord = a_texCoord; } #version 300 es precision mediump float; in vec2 v_texCoord; layout(location = 0) out vec4 outColor; uniform sampler2D u_texture; void main() { outColor = texture(u_texture, v_texCoord); }
傳送帶的核心就是圖像拷貝操作:
memcpy(m_RenderImage.ppPlane[0], m_SrcImage.ppPlane[0], m_RenderImage.width * m_RenderImage.height * 4 / 2); //左側預覽區(qū)域像素拷貝 int bannerHeight = m_RenderImage.height / 2 / m_bannerNum;//一個 banner 的高(小豎條) int bannerPixelsBufSize = m_RenderImage.width * bannerHeight * 4;//一個 banner 占用的圖像內存 uint8 *pBuf = m_RenderImage.ppPlane[0] + m_RenderImage.width * m_RenderImage.height * 4 / 2; //傳送帶分界線 //從最右側的豎條圖像區(qū)域開始拷貝圖像 for (int i = m_bannerNum - 1; i >= 1; --i) { memcpy(pBuf + i*bannerPixelsBufSize, pBuf + (i - 1)*bannerPixelsBufSize, bannerPixelsBufSize); } //將來源區(qū)域的像素拷貝到豎條圖像區(qū)域 0 memcpy(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); int bannerHeight = m_RenderImage.height / 2 / m_bannerNum; int bannerPixelsBufSize = m_RenderImage.width * bannerHeight * 4; uint8 *pBuf = m_RenderImage.ppPlane[0] + m_RenderImage.width * m_RenderImage.height * 4 / 2; //傳送帶分界線 for (int i = 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, (const void *)0); glBindVertexArray(GL_NONE);
詳細實現(xiàn)代碼見項目:github.com/githubhaoha…
到此這篇關于Android OpenGL ES 實現(xiàn)抖音傳送帶特效的文章就介紹到這了,更多相關Android 抖音傳送帶特效內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Android Studio preview 不固定及常見問題的解決辦法
preview 可以幫助您預覽您的布局文件將如何在用戶的設備上呈現(xiàn)。這篇文章主要介紹了Android Studio preview 不固定及常見問題的解決辦法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05Android調用系統(tǒng)拍照裁剪圖片模糊的解決方法
這篇文章主要為大家詳細介紹了Android調用系統(tǒng)拍照裁剪圖片模糊的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-01-01Android通過自定義view實現(xiàn)刮刮樂效果詳解
這篇文章主要介紹了如何在Android中利用自定義的view實現(xiàn)刮刮樂的效果,文中的示例代碼講解詳細,感興趣的小伙伴可以跟上小編一起動手試一試2022-03-03android 仿微信demo——登錄功能實現(xiàn)(移動端)
本篇文章主要介紹了微信小程序-閱讀小程序實例(demo),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望能給你們提供幫助2021-06-06