2012-10-09 28 views
20

He estado luchando para dibujar una imagen 2D desde archivos jpg/png usando OpenGL ES 2.0 para Android. Donde quiera que mire, los tutoriales son para texturizar imágenes en 3D por lo que ha sido difícil averiguar cómo dibujar un Sprite 2D regular. Tengo un cuadrado para dibujar y rotar, pero una vez que se trata de texturizar debo haber cometido un error porque sigo recibiendo un error al decir que DrawElements no está vinculado a ningún dato, pero si hago un comentario sobre cualquier código relacionado con la texturación, funciona bien.Dibuje una imagen 2D usando OpenGL ES 2.0

Cualquier ayuda sería muy apreciada.

Aquí está mi código para mi clase Sprite y clase de procesador:

public class Sprite 
{ 
//Reference to Activity Context 
private final Context mActivityContext; 

//Added for Textures 
private final FloatBuffer mCubeTextureCoordinates; 
private int mTextureUniformHandle; 
private int mTextureCoordinateHandle; 
private final int mTextureCoordinateDataSize = 2; 
private int mTextureDataHandle; 

private final String vertexShaderCode = 
//Test 
"attribute vec2 a_TexCoordinate;" + 
"varying vec2 v_TexCoordinate;" + 
//End Test 
"uniform mat4 uMVPMatrix;" + 
"attribute vec4 vPosition;" + 
"void main() {" + 
" gl_Position = vPosition * uMVPMatrix;" + 
    //Test 
    "v_TexCoordinate = a_TexCoordinate" + 
    //End Test 
"}"; 

private final String fragmentShaderCode = 
"precision mediump float;" + 
"uniform vec4 vColor;" + 
//Test 
"uniform sampler2D u_Texture;" + 
"varying vec2 v_TexCoordinate;" + 
//End Test 
"void main() {" + 
//"gl_FragColor = vColor;" + 
"gl_FragColor = (v_Color * texture2D(u_Texture, v_TexCoordinate));" + 
"}"; 

private final int shaderProgram;  
private final FloatBuffer vertexBuffer; 
private final ShortBuffer drawListBuffer; 
private int mPositionHandle; 
private int mColorHandle; 
private int mMVPMatrixHandle; 

// number of coordinates per vertex in this array 
static final int COORDS_PER_VERTEX = 2; 
static float spriteCoords[] = { -0.5f, 0.5f, // top left 
           -0.5f, -0.5f, // bottom left 
           0.5f, -0.5f, // bottom right 
           0.5f, 0.5f }; //top right 

private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; //Order to draw vertices 
private final int vertexStride = COORDS_PER_VERTEX * 4; //Bytes per vertex 

// Set color with red, green, blue and alpha (opacity) values 
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f }; 

public Sprite(final Context activityContext) 
{ 
    mActivityContext = activityContext; 

    //Initialize Vertex Byte Buffer for Shape Coordinates/# of coordinate values * 4 bytes per float 
    ByteBuffer bb = ByteBuffer.allocateDirect(spriteCoords.length * 4); 
    //Use the Device's Native Byte Order 
    bb.order(ByteOrder.nativeOrder()); 
    //Create a floating point buffer from the ByteBuffer 
    vertexBuffer = bb.asFloatBuffer(); 
    //Add the coordinates to the FloatBuffer 
    vertexBuffer.put(spriteCoords); 
    //Set the Buffer to Read the first coordinate 
    vertexBuffer.position(0); 

    // S, T (or X, Y) 
    // Texture coordinate data. 
    // Because images have a Y axis pointing downward (values increase as you move down the image) while 
    // OpenGL has a Y axis pointing upward, we adjust for that here by flipping the Y axis. 
    // What's more is that the texture coordinates are the same for every face. 
    final float[] cubeTextureCoordinateData = 
    {            
      //Front face 
      /*0.0f, 0.0f,    
      0.0f, 1.0f, 
      1.0f, 0.0f, 
      0.0f, 1.0f, 
      1.0f, 1.0f, 
      1.0f, 0.0f*/ 

      -0.5f, 0.5f, 
      -0.5f, -0.5f, 
      0.5f, -0.5f, 
      0.5f, 0.5f 
    }; 

    mCubeTextureCoordinates = ByteBuffer.allocateDirect(cubeTextureCoordinateData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); 
    mCubeTextureCoordinates.put(cubeTextureCoordinateData).position(0); 

    //Initialize byte buffer for the draw list 
    ByteBuffer dlb = ByteBuffer.allocateDirect(spriteCoords.length * 2); 
    dlb.order(ByteOrder.nativeOrder()); 
    drawListBuffer = dlb.asShortBuffer(); 
    drawListBuffer.put(drawOrder); 
    drawListBuffer.position(0); 

    int vertexShader = MyGL20Renderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); 
    int fragmentShader = MyGL20Renderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); 

    shaderProgram = GLES20.glCreateProgram(); 
    GLES20.glAttachShader(shaderProgram, vertexShader); 
    GLES20.glAttachShader(shaderProgram, fragmentShader); 

    //Texture Code 
    GLES20.glBindAttribLocation(shaderProgram, 0, "a_TexCoordinate"); 

    GLES20.glLinkProgram(shaderProgram); 

    //Load the texture 
    mTextureDataHandle = loadTexture(mActivityContext, R.drawable.brick); 
} 

public void Draw(float[] mvpMatrix) 
{ 
    //Add program to OpenGL ES Environment 
    GLES20.glUseProgram(shaderProgram); 

    //Get handle to vertex shader's vPosition member 
    mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition"); 

    //Enable a handle to the triangle vertices 
    GLES20.glEnableVertexAttribArray(mPositionHandle); 

    //Prepare the triangle coordinate data 
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer); 

    //Get Handle to Fragment Shader's vColor member 
    mColorHandle = GLES20.glGetUniformLocation(shaderProgram, "vColor"); 

    //Set the Color for drawing the triangle 
    GLES20.glUniform4fv(mColorHandle, 1, color, 0); 

    //Set Texture Handles and bind Texture 
    mTextureUniformHandle = GLES20.glGetAttribLocation(shaderProgram, "u_Texture"); 
    mTextureCoordinateHandle = GLES20.glGetAttribLocation(shaderProgram, "a_TexCoordinate"); 

    //Set the active texture unit to texture unit 0. 
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 

    //Bind the texture to this unit. 
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle); 

    //Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0. 
    GLES20.glUniform1i(mTextureUniformHandle, 0); 

    //Pass in the texture coordinate information 
    mCubeTextureCoordinates.position(0); 
    GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, mCubeTextureCoordinates); 
    GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle); 

    //Get Handle to Shape's Transformation Matrix 
    mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix"); 

    //Apply the projection and view transformation 
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0); 

    //Draw the triangle 
    GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); 

    //Disable Vertex Array 
    GLES20.glDisableVertexAttribArray(mPositionHandle); 
} 

public static int loadTexture(final Context context, final int resourceId) 
{ 
    final int[] textureHandle = new int[1]; 

    GLES20.glGenTextures(1, textureHandle, 0); 

    if (textureHandle[0] != 0) 
    { 
     final BitmapFactory.Options options = new BitmapFactory.Options(); 
     options.inScaled = false; // No pre-scaling 

     // Read in the resource 
     final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options); 

     // Bind to the texture in OpenGL 
     GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]); 

     // Set filtering 
     GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 
     GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 

     // Load the bitmap into the bound texture. 
     GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 

     // Recycle the bitmap, since its data has been loaded into OpenGL. 
     bitmap.recycle(); 
    } 

    if (textureHandle[0] == 0) 
    { 
     throw new RuntimeException("Error loading texture."); 
    } 

    return textureHandle[0]; 
} 
} 

Procesador Mi Clase:

public class MyGL20Renderer implements GLSurfaceView.Renderer 
{ 
private final Context mActivityContext; 

//Matrix Initializations 
private final float[] mMVPMatrix = new float[16]; 
private final float[] mProjMatrix = new float[16]; 
private final float[] mVMatrix = new float[16]; 
private float[] mRotationMatrix = new float[16]; 

//Declare as volatile because we are updating it from another thread 
public volatile float mAngle; 

//private Triangle triangle; 
private Sprite sprite; 

public MyGL20Renderer(final Context activityContext) 
{ 
    mActivityContext = activityContext; 
} 

public void onSurfaceCreated(GL10 unused, EGLConfig config) 
{ 
    //Set the background frame color 
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 

    //Initialize Shapes 
    //triangle = new Triangle(); 
    sprite = new Sprite(mActivityContext); 
} 

public void onDrawFrame(GL10 unused) 
{ 
    //Redraw background color 
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 

    //Set the camera position (View Matrix) 
    Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); 

    //Calculate the projection and view transformation 
    Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0); 

    //Create a rotation transformation for the triangle 
    Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f); 

    //Combine the rotation matrix with the projection and camera view 
    Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0); 

    //Draw Shape 
    //triangle.Draw(mMVPMatrix); 
    sprite.Draw(mMVPMatrix); 
} 

public void onSurfaceChanged(GL10 unused, int width, int height) 
{ 
    GLES20.glViewport(0, 0, width, height); 

    float ratio = (float) width/height; 

    //This Projection Matrix is applied to object coordinates in the onDrawFrame() method 
    Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7); 
} 

public static int loadShader(int type, String shaderCode) 
{ 
    //Create a Vertex Shader Type Or a Fragment Shader Type (GLES20.GL_VERTEX_SHADER OR GLES20.GL_FRAGMENT_SHADER) 
    int shader = GLES20.glCreateShader(type); 

    //Add The Source Code and Compile it 
    GLES20.glShaderSource(shader, shaderCode); 
    GLES20.glCompileShader(shader); 

    return shader; 
} 
} 
+0

[link] (http://developer.android.com/training/graphics/opengl/index.html) repase esto, es un buen tutorial. – sarabhai05

+0

He pasado por ese tutorial pero no incluye nada sobre texturizar – Strifex

+0

Estoy tratando de usar tu clase de sprite después de la modificación en esta publicación. Pero cuando trato de traducir el sprite me da un comportamiento alámbrico. Me pregunto si tuviste el mismo problema con traducirlo. – user1673892

Respuesta

20

"v_TexCoordinate = a_TexCoordinate" +

debería haber sido

"v_TexCoordinate = a_TexCoordinate;" +

Aparentemente olvidé un punto y coma, ahora me doy cuenta de lo mucho que confío en mi IDE para decirme cuando estropeo cosas estúpidas jaja.

0

La solución podría ser tan simple como permitir mTextureCoord ... antes de asignar el VertexAttribPointer ;

+0

Lo probé, no resolvió mi problema. – Strifex

+0

¡Se arregló !, resulta que mi problema era que me faltaba un punto y coma en mi sombreador de vértices. – Strifex

1

Pruebe con las siguientes coordenadas de textura:

flotador final de [] cubeTextureCoordinateData = {
0,5, -0,5, 0.5,0.5, -0.5,0.5, -0,5, -0,5 };

Su funcionamiento. Muchas gracias.

9

Hay un error con la denominación vColor variable (o el uso) en fragmentShaderCode. Aquí la variable tiene el nombre vColor:

uniform vec4 vColor; 

y en esta línea que tiene el nombre v_Color

gl_FragColor = (v_Color * texture2D(u_Texture, v_TexCoordinate)); 
1

También me gustaría cambiar esto en el shader

gl_Position = vPosition * uMVPMatrix; 

a este

gl_Position = uMVPMatrix * vPosition; 

hará un dif ferencia al tratar de traducir la posición de la imagen.