2013-03-05 39 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