2011-08-17 155 views
8

我剛學習使用OpenGL ES 2.0 for Android。我一直試圖簡單地在屏幕中間顯示紋理,這很容易,但我似乎無法使PNG alpha正常工作。圖像將以黑色背景顯示,或根據我使用的設置將整個圖像稍微混合爲背景顏色。OpenGL ES 2.0 PNG alpha通道

我也跟着去了這一點實際的教程與透明度從來沒有工作過,所以我試圖在代碼中工作,我已經通過各地搜索發現,並有可能剛剛錯過了重要的一步。儘管我已經搜索了很多東西來解決這個問題,但我還沒有看到任何有我的設置沒有的東西的答案。我已經嘗試了glBlendFunc的每一個組合,而不是沒有運氣。

我想,如果我試圖在所有可能與此有關的代碼粘貼,這個問題會顯得很臃腫,所以我會很樂意張貼你們要求的任何代碼位。我非常感謝接下來我應該嘗試的任何想法。

編輯::這是我的片段着色器,這是我認爲是原因。這是我從未真正找到過使用透明度的一個體面示例的唯一部分,其他所有內容都與我在其他地方看到的相符。

 final String fragmentShader =   
     "precision mediump float;  \n" 
     + "varying vec2 v_Color;   \n"  
     + "uniform sampler2D s_baseMap; \n" 
     + "void main()     \n"  
     + "{        \n" 
     + " vec4 baseColor;    \n" 
     + " baseColor = texture2D(s_baseMap, v_Color); \n" 
     + " gl_FragColor = baseColor;  \n"  
     + "}        \n"; 

它從來不與阿爾法明確的東西,它是不使用它畢竟一個例子,但我仍然不知道很多關於片段着色器和因爲它似乎「之類的」當它將圖像混合到背景中工作時,我認爲它以某種形式處理了alpha,並且我剛剛設置了錯誤的東西。

編輯::這裏是 「loadTexture」 的方法。這與我試圖從中學習的openGL ES 2.0書中的例子大致相同,只是一些改動似乎使圖像更接近正常工作。

private int loadTexture (InputStream is) 
{ 
    int[] textureId = new int[1]; 
    Bitmap bitmap; 
    bitmap = BitmapFactory.decodeStream(is); 
    byte[] buffer = new byte[bitmap.getWidth() * bitmap.getHeight() * 4]; 

    for (int y = 0; y < bitmap.getHeight(); y++) 
     for (int x = 0; x < bitmap.getWidth(); x++) 
     { 
      int pixel = bitmap.getPixel(x, y); 
      buffer[(y * bitmap.getWidth() + x) * 4 + 0] = (byte)((pixel >> 16) & 0xFF); 
      buffer[(y * bitmap.getWidth() + x) * 4 + 1] = (byte)((pixel >> 8) & 0xFF); 
      buffer[(y * bitmap.getWidth() + x) * 4 + 2] = (byte)((pixel >> 0) & 0xFF); 
     } 

    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(bitmap.getWidth() * bitmap.getHeight() * 4); 
    byteBuffer.put(buffer).position(0); 

    GLES20.glGenTextures (1, textureId, 0); 
    GLES20.glBindTexture (GLES20.GL_TEXTURE_2D, textureId[0]); 

    GLES20.glTexImage2D (GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(), bitmap.getHeight(), 0, 
          GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, byteBuffer); 

    GLES20.glTexParameteri (GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); 
    GLES20.glTexParameteri (GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); 
    GLES20.glTexParameteri (GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); 
    GLES20.glTexParameteri (GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); 

    return textureId[0]; 
} 

我明白的代碼是幹什麼的,但不可否認它仍然混淆了我一下,讓我可能只是缺少明顯的東西,由於我缺乏知識。

我沒有看到我的代碼的任何其他部分看起來像他們可能會導致我遇到的問題,但編程總是充滿了意想不到的(特別是在OpenGL的世界看起來),所以如果你認爲別的原因我一定會爲你發佈。對不起,所有的煩惱!

+0

確保在將圖像加載到紋理中(而不是加載RGB圖像或創建RGB紋理)時保留來自PNG的Alpha通道。當然,確保你調用'glEnable(GL_BLEND)'(除了設置正確的'glBlendFunc')。但有些代碼肯定會幫助你多一點。也許只是圖像加載和紋理創建代碼以及您設置混合狀態的代碼。當然,因爲你是新來者,不要忘記告訴你自己有關接受和投票功能。 –

+0

片段着色器看起來是有效的,因爲它正確地將紋理的alpha代理給了片段顏色。所以你不會發布一些你的加載和紋理創建代碼。 –

+0

您可以嘗試禁用混合的'gl_FragColor = vec4(baseColor.aaa,1.0)'。這應該會給你一個alpha通道的灰度圖像。 – trenki

回答

3

您很可能希望使用glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)作爲混合函數,並且您還必須確保也將紋理的Alpha值寫入gl_FragColor片段着色器輸出變量。

對於這一切工作您上傳的紋理數據必須包含一個alpha值,你必須使用支持alpha通道的紋理格式(RGBA,RGBA8等)。

您可以通過簡單地將alpha值路由到RGB顏色組件並檢查獲取的圖像來驗證此情況。

編輯:

在你的圖像加載代碼,你忘了alpha通道複製!試試davebytes給出的建議。

+0

如果我在glBlendFunc上使用該設置,圖像根本不會顯示。看起來,glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA)對我來說最適合,或者至少最接近正常工作。 我還應該提到,當圖像混合到背景中時,它似乎也刪除了圖像的透明部分。 我相信我的問題在於片段着色器,因爲我還不太瞭解它,它主要是來自沒有使用透明度的示例的代碼副本。我會在主帖中發佈。 – DaeKo

1

您的初始着色器沒問題。 alpha是顏色操作中固有的,它可能不適用於混合/模式/等。

假設你的紋理是黑色的,如果你這樣做fragcolor = base.aaa,這意味着你的紋理數據是'壞'。

看着你的紋理負載,是的,這是錯誤的。你永遠不會複製alpha,只是rgb。假設java將字節數組清除爲0,所有alpha將爲零,這將使您得到您的黑盒子,這將導致圖像在啓用alpha混合時「消失」。

爲了簡化你的生活,而不是所有的手和複製的東西,你可以簡單地正常加載位圖,並使用GLUtils助手上傳的,而不是直接使用glTexImage2d:

bitmap = BitmapFactory.decodeStream(is); 
    GLES20.glGenTextures (1, textureId, 0); 
    GLES20.glBindTexture (GLES20.GL_TEXTURE_2D, textureId[0]); 
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 

類似的東西。然後啓用混合,如果不是預乘,使用src + invsrc混合模式,並渲染,您應該得到所需的結果。

9

變化

for (int y = 0; y < bitmap.getHeight(); y++) 
    for (int x = 0; x < bitmap.getWidth(); x++) 
    { 
     int pixel = bitmap.getPixel(x, y); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 0] = (byte)((pixel >> 16) & 0xFF); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 1] = (byte)((pixel >> 8) & 0xFF); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 2] = (byte)((pixel >> 0) & 0xFF); 
    } 

for (int y = 0; y < bitmap.getHeight(); y++) 
    for (int x = 0; x < bitmap.getWidth(); x++) 
    { 
     int pixel = bitmap.getPixel(x, y); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 0] = (byte)((pixel >> 16) & 0xFF); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 1] = (byte)((pixel >> 8) & 0xFF); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 2] = (byte)((pixel >> 0) & 0xFF); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 3] = (byte)((pixel >> 24) & 0xFF); 
    } 

包括阿爾法信息,則只需添加

GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); 
GLES20.glEnable(GLES20.GL_BLEND); 

繪製紋理權之前。請記住在完成後禁用GL_BLEND。