2013-03-05 41 views
3

請參閱末尾編輯以獲取進度。僅使用最後綁定紋理的OpenGL ES 2.0 1

我在努力學習的OpenGL ES 2.0的過程中(我會在Android設備上進行開發)

我有點困惑的頂點和片段着色器。我理解他們的目的,但是如果我從一個定製的類(例如'point')構建一個形狀並設置其大小和顏色或應用紋理,並假定這兩個着色器都是在對象類的構造函數中初始聲明和定義的,這是否意味着該類的每個實例都擁有它自己的一對着色器?

這是我的第一個問題。我的第二個是,如果是這種情況(每個對象的着色器對).........這是要走的路嗎?我聽說有一個着色器對和切換它的參數不是一個好主意,因爲性能,但如果我有100個精靈,所有相同的大小和顏色(或紋理)是否有意義,他們都有一個不同的着色器對具有完全相同的參數?

我希望我問的是正確的問題,我沒有長時間研究ES 2.0,所以覺得有點混亂。我目前只對OpenGL有限的理解!

編輯

根據要求添加代碼。

public class Dot { 

    int iProgId; 
    int iPosition; 
    float size = 10; 
    FloatBuffer vertexBuf; 
    float r = 1f; 
    float g = 1f; 
    float b = 1f; 
    float a = 1f; 
    int iBaseMap; 
    int texID; 
    Bitmap imgTexture; 


    //Constructor 
    public Dot() { 

     float[] vertices = { 
         0,0,0f    
         }; 

    //Create vertex shader 
    String strVShader = 
       "attribute vec4 a_position;\n"+ 
       "void main()\n" + 
       "{\n" + 
       "gl_PointSize = " +size+ ";\n" + 
       "gl_Position = a_position;\n"+     
       "}"; 

    //Create fragment shader 
    String strFShader = 
       "precision mediump float;" + 
       "void main() " + 
       "{" + 
       "gl_FragColor = vec4(0,0,0,1);" + 
       "}"; 
       iProgId = Utils.LoadProgram(strVShader, strFShader); 
       iPosition = GLES20.glGetAttribLocation(iProgId, "a_position"); 

        vertexBuf = ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); 

        vertexBuf.put(vertices).position(0); 


     } 

我的SetTexture方法

public void setTexture(GLSurfaceView view, Bitmap imgTexture){ 
    this.imgTexture=imgTexture; 

    //Create vertex shader 
    String strVShader = 
      "attribute vec4 a_position;\n"+ 
      "void main()\n" + 
      "{\n" + 
      "gl_PointSize = " +size+ ";\n" + 
      "gl_Position = a_position;\n"+     
      "}"; 

    //Fragment shader 
    String strFShader = 
      "precision mediump float;" + 
      "uniform sampler2D u_baseMap;" + 
      "void main()" + 
      "{" + 
      "vec4 color;" + 
      "color = texture2D(u_baseMap, gl_PointCoord);" + 
      "gl_FragColor = color;" + 
      "}"; 

    iProgId = Utils.LoadProgram(strVShader, strFShader); 
    iBaseMap = GLES20.glGetUniformLocation(iProgId, "u_baseMap"); 

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 
    GLES20.glUniform1i(iBaseMap, 0); 

    texID = Utils.LoadTexture(view, imgTexture); //See code below 
} 

LoadTexture()從我Utils類方法:

public static int LoadTexture(GLSurfaceView view, Bitmap imgTex) { 
    int textures[] = new int[1]; 
    try { 
     GLES20.glGenTextures(1, textures, 0); 
     GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); 
     GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR); 
     GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_LINEAR); 
     GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, imgTex, 0); 
    } catch 
    } 
    return textures[0]; 
} 

最後,我的畫法:

public void drawDot(float x, float y){ 

     float[] vertices = { 
       x,y,0f    
       }; 

     vertexBuf = ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); 
     vertexBuf.put(vertices).position(0); 
     GLES20.glUseProgram(iProgId); 
     GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 0, vertexBuf); 
     GLES20.glEnableVertexAttribArray(iPosition); 
     GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1); 
    } 

所以我可以創建東西l ike so:

Dot dot1 = new Dot(); 
dot1.setSize(40); 
setTexture(myBitmap); //(created earlier with BitmapFactory) 
drawDot(0,0); 

謝謝!

編輯1:感謝迄今爲止的答案。在進一步的研究中,似乎還有一些人有這個完全相同的問題。這個問題似乎是因爲我沒有在渲染例程中調用glBindTexture,因此OpenGL只是使用它加載的最後一個紋理,我認爲這很有意義。

如果我把下列我的渲染程序:

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 1); 

它將應用第一的位圖,並顯示它

如果我把:

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 2); 

它將應用第二位圖並顯示它

所以,找個地方!但我現在的問題是,如何讓我的渲染方法根據哪個對象調用它(渲染例程)自動知道要使用哪個位圖?

再次感謝

回答

2

我會回答自己,因爲我發現問題是什麼。

將此添加到我的drawDot方法:

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texID); 

texID是對應於調用drawDot()方法的對象紋理ID。

完美的作品

希望這有助於人誰可以在未來類似的問題。

3

它是如何工作(簡述)

着色器只是在顯卡上運行的程序。你編譯並鏈接它們,然後你可以傳遞一些變量來修改頂點和片段的屬性。 這意味着,當您調用某些繪圖函數(如glDrawElements或glDrawArrays)時,頂點數據(這意味着位置,紋理座標,法線,顏色等取決於您要發送的內容)將被髮送到管線。 這意味着當前加載的頂點着色器將逐個獲取頂點並運行其代碼以應用所需的任何變換。之後,OpenGL將應用光柵化爲當前幀生成片段。然後片段着色器將採取每個片段並相應地修改它。

您可以隨時卸載着色器並加載另一個着色器。如果不同對象需要不同的着色器,則可以根據着色器對對象進行分組,並在爲每個組重新加載相應着色器時獨立渲染它們。

但是,有時候更容易將某些參數傳遞給着色器併爲每個對象更改它們。例如,如果要渲染3D模型,則可以將其拆分爲子網格,每個子網格具有不同的紋理。然後,當您傳遞網格的頂點數據時,將加載紋理並將其傳遞給着色器。對於下一個網格,您將傳遞另一個紋理,依此類推。

在現實世界中,一切都比較複雜,但我希望它對您瞭解它的工作原理非常有用。

你的榜樣

您正在加載在構造一對着色器(無紋理),然後創建每次設置紋理時間新的着色器。我不確定這是更好的方法。

不知道Utils.LoadShader做了什麼很難知道,但每次調用它時都可以記錄結果。也許你第二次連接着色器不起作用。

如果我是你,我會在你的點對象外面使用一對着色器。您可以將參數傳遞給着色器(使用glUniform ...),指示點的大小,紋理等。 setTexture函數只會在不加載着色器的情況下綁定新紋理。然後在開始編譯(在設置GL上下文之後等)。

當這項工作時,你可能會考慮每次改變你的着色器,只要它真的有必要。

+0

感謝@Esparver的答案。所以在我的實現中,對象的每個實例是否都有自己的對或着色器?或者他們會分享一對嗎?我無法弄清楚它是如何工作的!我創建了一個對象的2個實例併爲每個對象應用了一個紋理,但是當我渲染它們時,它們都顯示相同的紋理,因此我試圖瞭解它發生了什麼 - 再次感謝您的時間和幫助。 – Zippy 2013-03-05 16:47:40

+1

你能用一些相關的代碼編輯你的問題嗎?看看你的着色器和你如何發送數據(glDrawElements調用或其他) – Esparver 2013-03-05 16:52:12

+0

這聽起來像你沒有創建一個新的紋理對象,並在你使用第二個紋理之前進行綁定。 – jonbonazza 2013-03-05 16:53:12