2012-11-14 45 views
9

我想用一些疊加紋理混合相機預覽SurfaceTexture。我正在使用這些着色器進行處理:Android OpenGL SurfaceTexture(外部圖像)和普通紋理的組合

private final String vss = "attribute vec2 vPosition;\n" 
     + "attribute vec2 vTexCoord;\n" 
     + "varying vec2 texCoord;\n" 
     + "void main() {\n" 
     + " texCoord = vTexCoord;\n" 
     + " gl_Position = vec4 (vPosition.x, vPosition.y, 0.0, 1.0);\n" 
     + "}"; 

private final String fss = "#extension GL_OES_EGL_image_external : require\n" 
     + "precision mediump float;\n" 
     + "uniform samplerExternalOES sTexture;\n" 
     + "uniform sampler2D filterTexture;\n" 
     + "varying vec2 texCoord;\n" 
     + "void main() {\n" 
     +" vec4 t_camera = texture2D(sTexture,texCoord);\n" 
     //+" vec4 t_overlayer = texture2D(filterTexture, texCoord);\n" 
     //+ " gl_FragColor = t_overlayer;\n" + "}"; 
     + " gl_FragColor = t_camera;\n" + "}"; 

我的目標是混合t_camera和t_overlayer。當我單獨顯示t_camera或t_overlayer時,它可以工作(顯示相機預覽或紋理)。但是當我取消t_overlayer的註釋時,那麼t_camera變成了黑色(不知何故採樣很嚴重)。我的覆蓋層紋理是512x512和CLAMPT_TO_EDGE。 僅在例如:Android模擬器,HTC Evo 3D上發生此問題。 但在SGS3上,HTC One X,它工作得很好。

出了什麼問題?它是Evo 3D缺少一些擴展還是什麼?

+0

你提到它不適用於Android模擬器。你試過哪個操作系統版本?你嘗試過x86嗎? –

+0

我在MacOSX 10.8.2上使用x64模擬器。 –

回答

3

我在Nexus 7上遇到了同樣的問題,它讓我瘋狂。訪問samplerExternalOES或sampler2D是完全正常的,但在同一着色器中訪問它們會產生意想不到的結果。有時輸出會是黑色的。有時,其中一個查找的輸出會產生不良的量化僞像。行爲也會根據採樣器綁定到的紋理單元而變化。我沒有檢查每個opengl錯誤和validateProgram結果。

最終,有效的方法是使用單獨的着色器來訪問攝像機輸出並將其渲染到紋理中。然後可以通過常規的sampler2D訪問生成的紋理,並且所有的工作都完全按照預期進行。我懷疑有一個與samplerExternalOES相關的bug。

+1

我已經通過不使用samplerExternalOES解決了問題:/ –

+0

如何將相機緩衝區傳遞給OpenGL?我能找到的只是通過SurfaceTexture,這迫使我使用samplerExternalOES。 – user1924406

+1

想法: 我使用onPreviewFrame捕獲攝像頭緩衝區,緩衝區採用YUV21格式。然後,我將緩衝區分隔成緩衝區 - Y,U,V - YUV21格式很簡單。然後我使用紋理將這些緩衝區上傳到GPU中 - GL_ALPHA。在片段着色器中,我有3個統一的sample2d(y,u,v)。然後在片段着色器中,我從YUV-> RGB進行如下轉換: –

3

我想你有這個問題,因爲你沒有在你的代碼上設置正確的紋理ID。這是一個邏輯上錯誤的假設,但實際上在文檔中沒有這樣定義。如果選中該擴展你看到以下(編)TEXT的文檔:對於每個紋理單元

每個TEXTURE_EXTERNAL_OES紋理對象可能需要高達3紋理 圖像單元到它結合。 設置爲TEXTURE_EXTERNAL_OES 時,此值將介於1和3之間。對於其他有效的紋理目標,此值始終爲 1.請注意,當綁定TEXTURE_EXTERNAL_OES紋理對象時,單個紋理單元所需的紋理單元數可能是 1,2或3,而對於其他紋理對象每個紋理單元需要 正好1紋理圖像單元。

這意味着,如果您使用id 0,那麼在leas下一個額外的工作。你的情況:

GLES20.glUniform1i(sTextureHandle, 1); 
GLES20.glActiveTexture(GLES20.GL_TEXTURE1); 
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 
     sTextureId); 

爲了您的2D紋理:

GLES20.glUniform1i(filterTextureHandle, 0); 
GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, filterTextureID); 

我敢肯定,你這樣會鍛鍊。

+0

好吧,我得到完全相同的問題,GL_TEXTURE_EXTERNAL_OES和紋理ID排序的東西根本不起作用。我想和其他人一樣,這是一個與硬件相關的問題,不同的手機支持這個問題。 – flankechen

+0

目前還不清楚'你使用id 0'的'id'是什麼意思。我在制服中看到0,這不是一個身份證,而是一個單位。紋理ID在sTextureId和filterTextureId,我們不能任意設置。 –

+0

嗨,萊昂,我的意思是: sTextureId = GL_TEXTURE1,它依次需要glUniform1i(sTextureHandle,1);爲着色器。相同的0.不知道你的意思是「我們不能任意設置它」。我只是通過使用0和1來告訴着色器GL_TEXTURE0和GL_TEXTURE1。對我有用。 – Marco

3

這不是一個答案,而是一個問題的闡述 - 也許這將有助於OpenGl ES專家瞭解這個問題。


我有3個紋理用於​​覆蓋,和一個外部紋理,用於捕獲媒體播放器的輸出。如果我僅使用外部紋理,則輸出如預期的那樣,來自MPlayer的幀。在Nexus4,Samsung Galaxy S3,S4等設備上完全相同的代碼工作正常(所有設備都使用adreno gpus或Arm's Mali400)。硬件的區別在於Nexus 7使用Nvidia Tegra 3主板。


編輯(是如何解決在我身邊)

的Nvidia Tegra 3的要求,外部紋理採樣器被稱爲與採樣中最低的字母順序的名稱,同時爲Adreno 220似乎需要相反。另外,T3要求最後採樣外部紋理。對於使用Android 4.3及更新版本的設備,這些錯誤可能會得到解決。在Nvidia方面,這是一個bug,很久以前就解決了,但Nexus驅動程序只是在稍後才更新。所以我不得不檢查一下哪個GPU存在,並相應地調整代碼。

+0

我認爲4.3沒有解決它。太瘋狂了。這是Nvidia Tegra 3 vs - 任何其他 - ? –

3

以上方法節省了我很多時間。謝謝大師:

GLES20.glUniform1i(sTextureHandle, 1); 
GLES20.glActiveTexture(GLES20.GL_TEXTURE1); 
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 
    sTextureId); 

爲了您的2D紋理:

GLES20.glUniform1i(filterTextureHandle, 0); 
GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, filterTextureID); 

改變紋理指數是解決這個的好辦法。

+0

這是關於使用最高級別的OES紋理? 「從上面」是什麼意思?哦,對不起,這些帽子。閱讀「從上面」時會自動激活。 :) –

3

它似乎是OpenGl實現中的一個錯誤。相同的代碼在Samsung Note上運行良好,而不是在nexus 4上運行。似乎getUniformLocation在某些設備上中斷了位於samplerExternalOES之後的所有變量。

它也似乎是編譯器按字母順序排列統一變量,所以使它在兩個設備上都能正常工作的解決方案是將samplerExternalEoz重命名爲zzzTexture或其他東西。

+0

解決的辦法是在某些設備上設置它爲aaaTexture(例如:Motorola Razr),在其他設備上設置爲zzzTexture(例如:Xperia) –

1

我可能也有同樣的問題。經過幾天的嘗試,我在這裏提出我的解決方案。希望這可以幫助其他人。

首先,問題陳述。就像LukášJezný一樣,我有一個預覽紋理和一個覆蓋紋理。它適用於nexus 4/5和大多數其他類型,但在OPPO上找不到5,Lenovo A820,Lenovo A720。

溶液:

(1)一樣的LukasJezný,使用YUV數據,並在着色它們轉換爲RGB。 (2)multipass drawing,預覽紋理一次畫到framebuffer,然後讀取,然後再畫到屏幕上。

(3)您使用自己的程序之前使用其它程序,

GLES20.glUseProgram(another one); 
    GLES20.glUseProgram(your "real" program); 

,它只是適用於OPPO找到5,聯想A820,聯想A720等。沒有人知道爲什麼......

1

參考user1924406的文章(https://stackoverflow.com/a/14050597/3250829)關於拆分訪問sampler2D紋理和samplerExternalOES紋理,這是我不得不這樣做,因爲我正在開發的應用程序正在閱讀文件或從服務器流式傳輸,而不是使用設備上的相機。在同一着色器中使用兩種紋理都會導致非常奇怪的着色僞像(Galaxy S3上的情況)或飽和度和對比度問題(Nexus 4上的情況)。

因此,解決samplerExternalOES紋理錯誤(從我目前看到的)的唯一方法就是執行兩個着色器程序:一個將samplerExternalOES紋理中包含的內容寫入FBO,其他從FBO獲取內容並將其直接寫入表面。

你需要檢查的一件事是,有時當你寫一個FBO時,紋理會協調翻轉。在我的情況下,V(或T或Y)座標被翻轉,導致水平軸上出現鏡像。在第二階段編寫片段着色器時,我必須考慮到這一點。

這是一個我想分享的戰爭故事,以防有些人可能需要從服務器讀取文件或數據流,而不是直接從相機中讀取數據。

+0

在大約一百萬年的時間裏搜索瞭如何實現這一點,請允許我放下這個鏈接。 https://github.com/harism/android_instacam/blob/master/src/fi/harism/instacam/InstaCamRenderer.java –

+1

@LéonPelletier - 你可以剛給我留言,並問我代碼:)順便說一句,謝謝爲那個環節。很高興在那裏看到它。 – rayryeng

+0

我會在家嘗試。我只是想知道如果將它應用於視頻流,它將如何用FPS來表示。我計劃讓Android MediaPlayer和iOS AVFoundation將YUV幀發送到常見的OpenTK便攜式應用程序,並使用上面提到的流程(fbo貼圖)應用着色器。這將使跨平臺視頻效果變得非常簡單。 –