2015-02-12 2 views
1

Я парень с фиксированной функцией, привыкший к новомодному шейдерному материалу.OpenGL ES 2.0 на Android: не удается загрузить текстуры

Я пытаюсь расширить пример Android OpenGL ES на текстуру квадратной формы. Если последняя строка моего шейдера равна gl_Fragcolor = vColor;, я получаю белый квадрат. Если это gl_FragColor = vColor * texture2D(u_Texture, v_TexCoordinate);, я получаю только черный цвет.

Здесь, где он становится более странным: когда я начал проверять ошибки GL, я обнаружил, что строка GLES20.glUseProgram(mProgram); в начале моей функции draw() дает мне ошибку GL 1280, GL_INVALID_ENUM. Для меня это не имеет смысла - нет перечислений, переданных этой функции.

Мысли?

DemoRenderer.java:

package com.wtracy.executivedemo; 

import javax.microedition.khronos.egl.EGLConfig; 
import javax.microedition.khronos.opengles.GL10; 

import android.app.Activity; 
import android.opengl.GLES20; 
import android.opengl.GLSurfaceView.Renderer; 
import android.opengl.Matrix; 
import android.util.Log; 

public class DemoRenderer implements Renderer { 
    float ratio; 
    // mMVPMatrix is an abbreviation for "Model View Projection Matrix" 
    private final float[] mMVPMatrix = new float[16]; 
    private final float[] mProjectionMatrix = new float[16]; 
    private final float[] mViewMatrix = new float[16]; 
    private SplashScreen splash; 
    Activity parent; 

    public DemoRenderer(Activity parent) { 
     this.parent = parent; 
    } 

    public void onDrawFrame(GL10 arg0) { 
     // Draw background color 
     GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 

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

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

     // Draw square 
     splash.draw(mMVPMatrix); 
    } 

    public void onSurfaceChanged(GL10 arg0, int width, int height) { 
     // Adjust the viewport based on geometry changes, 
     // such as screen rotation 
     GLES20.glViewport(0, 0, width, height); 

     ratio = (float) width/height; 

     float newWidth; 
     float newHeight; 

     if (ratio >= 1f) { 
      newWidth = ratio; 
      newHeight = 1f; 
     } else { 
      newWidth = 1f; 
      newHeight = 1f/ratio; 
     } 
     // this projection matrix is applied to object coordinates 
     // in the onDrawFrame() method 
     Matrix.frustumM(mProjectionMatrix, 0, -newWidth, newWidth, -newHeight, newHeight, 3, 7); 
    } 

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

     splash = new SplashScreen(parent.getResources()); 
    } 

    public static int loadShader(int type, String shaderCode){ 
     // create a vertex shader type (GLES20.GL_VERTEX_SHADER) 
     // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER) 
     int shader = GLES20.glCreateShader(type); 
     checkGlError("glCreateShader"); 

     // add the source code to the shader and compile it 
     GLES20.glShaderSource(shader, shaderCode); 
     checkGlError("glShaderSource"); 
     GLES20.glCompileShader(shader); 
     checkGlError("glCompileShader"); 

     return shader; 
    } 

    public static void checkGlError(String glOperation) { 
     int error; 
     while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 
      Log.e("com.wtracy.executivedemo", glOperation + ": glError " + error); 
      throw new RuntimeException(glOperation + ": glError " + error); 
     } 
    } 
} 

SplashScreen.java:

package com.wtracy.executivedemo; 

import java.nio.ByteBuffer; 
import java.nio.ByteOrder; 
import java.nio.FloatBuffer; 
import java.nio.ShortBuffer; 

import com.wtracy.executivedemo.R; 

import android.content.res.Resources; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.opengl.GLES20; 
import android.opengl.GLUtils; 

/** 
* A two-dimensional square for use as a drawn object in OpenGL ES 2.0. 
*/ 
public class SplashScreen { 

    private final String vertexShaderCode = 
      // This matrix member variable provides a hook to manipulate 
      // the coordinates of the objects that use this vertex shader 
      "uniform mat4 uMVPMatrix;" + 
      "attribute vec4 vPosition;" + 
      "attribute vec2 a_TexCoordinate; " +// Per-vertex texture coordinate information we will pass in. 
      "varying vec2 v_TexCoordinate;" + 
      "void main() {" + 
      // The matrix must be included as a modifier of gl_Position. 
      // Note that the uMVPMatrix factor *must be first* in order 
      // for the matrix multiplication product to be correct. 
      " gl_Position = uMVPMatrix * vPosition;" + 
      " v_TexCoordinate = a_TexCoordinate;" + 
      "}"; 

    private final String fragmentShaderCode = 
      "precision mediump float; " + 
      "uniform vec4 vColor; " + 
      "uniform sampler2D u_Texture; " + 
      "varying vec2 v_TexCoordinate; " + 
      "void main() {" + 
      /*" float diffuse;" + 
      " diffuse = diffuse * (1.0/(1.0 + (0.10 * distance)));" + 
      " diffuse = diffuse + 0.3;" +*/ 
      " gl_FragColor = vColor * texture2D(u_Texture, v_TexCoordinate);" + 
      //" gl_FragColor = vColor;" + 
      "}"; 

    private final FloatBuffer vertexBuffer; 
    private final ShortBuffer drawListBuffer; 
    private final int mProgram; 
    private int mPositionHandle; 
    private int mColorHandle; 
    private int mMVPMatrixHandle; 
    /** Store our model data in a float buffer. */ 
    private final FloatBuffer mCubeTextureCoordinates; 
    /** This will be used to pass in the texture. */ 
    private int mTextureUniformHandle; 
    /** This will be used to pass in model texture coordinate information. */ 
    private int mTextureCoordinateHandle; 
    /** Size of the texture coordinate data in elements. */ 
    private final int mTextureCoordinateDataSize = 2; 
    /** This is a handle to our texture data. */ 
    private int mTextureDataHandle; 

    // number of coordinates per vertex in this array 
    static final int COORDS_PER_VERTEX = 3; 
    static float squareCoords[] = { 
      -1.f, 1.f, 0.0f, // top left 
      -1.f, -1.f, 0.0f, // bottom left 
      1.f, -1.f, 0.0f, // bottom right 
      1.f, 1.f, 0.0f }; // top right 

    private final short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices 

    private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex 

    final float color[] = { 1f, 1f, 1f, 1.0f }; 
    final int[] textureHandle = new int[1]; 

    /** 
    * Sets up the drawing object data for use in an OpenGL ES context. 
    */ 
    public SplashScreen(Resources resources) { 
     // initialize vertex byte buffer for shape coordinates 
     ByteBuffer bb = ByteBuffer.allocateDirect(
     // (# of coordinate values * 4 bytes per float) 
       squareCoords.length * 4); 
     bb.order(ByteOrder.nativeOrder()); 
     vertexBuffer = bb.asFloatBuffer(); 
     vertexBuffer.put(squareCoords); 
     vertexBuffer.position(0); 

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

     // initialize byte buffer for the draw list 
     ByteBuffer dlb = ByteBuffer.allocateDirect(
       // (# of coordinate values * 2 bytes per short) 
       drawOrder.length * 2); 
     dlb.order(ByteOrder.nativeOrder()); 
     drawListBuffer = dlb.asShortBuffer(); 
     drawListBuffer.put(drawOrder); 
     drawListBuffer.position(0); 

     // prepare shaders and OpenGL program 
     int vertexShader = DemoRenderer.loadShader(
       GLES20.GL_VERTEX_SHADER, 
       vertexShaderCode); 
     int fragmentShader = DemoRenderer.loadShader(
       GLES20.GL_FRAGMENT_SHADER, 
       fragmentShaderCode); 

     mProgram = GLES20.glCreateProgram();    // create empty OpenGL Program 
     DemoRenderer.checkGlError("glCreateProgramr"); 
     GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program 
     DemoRenderer.checkGlError("glAttachShader"); 
     GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program 
     DemoRenderer.checkGlError("glAttachShader"); 
     GLES20.glLinkProgram(mProgram);     // create OpenGL program executables 
     DemoRenderer.checkGlError("glLinkProgram"); 

     GLES20.glGenTextures(1, textureHandle, 0); 
     DemoRenderer.checkGlError("glGenTextures"); 

     Bitmap bitmap; 
     BitmapFactory.Options bo = new BitmapFactory.Options(); 
     bo.inScaled = false; 
     bitmap = BitmapFactory.decodeResource(
       resources, 
       R.drawable.myfirstdemo, 
       bo); 
     // Bind to the texture in OpenGL 
     GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]); 
     DemoRenderer.checkGlError("glBindTexture"); 

     // 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); 
     DemoRenderer.checkGlError("glTexParameter"); 

     // 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."); 
     } 
    } 

    /** 
    * Encapsulates the OpenGL ES instructions for drawing this shape. 
    * 
    * @param mvpMatrix - The Model View Project matrix in which to draw 
    * this shape. 
    */ 
    public void draw(float[] mvpMatrix) { 
     // Add program to OpenGL environment 
     GLES20.glUseProgram(mProgram); 
     DemoRenderer.checkGlError("glUseProgram"); 

     // get handle to fragment shader's vColor member 
     mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor"); 
     DemoRenderer.checkGlError("glGetUniformLocation"); 
     // get handle to vertex shader's vPosition member 
     mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); 
     DemoRenderer.checkGlError("glGetAttribLocation"); 
     mTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture"); 
     DemoRenderer.checkGlError("glGetUniformLocation"); 
     mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate"); 
     DemoRenderer.checkGlError("glGetAttribLocation"); 

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

     GLES20.glActiveTexture(textureHandle[0]); 
     //DemoRenderer.checkGlError("glActiveTexture"); 
     // Bind the texture to this unit. 
     GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle); 
     //DemoRenderer.checkGlError("glBindTexture"); 
     // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0. 
     GLES20.glUniform1i(mTextureUniformHandle, 0); 
     //DemoRenderer.checkGlError("glUniform1i"); 

     // get handle to shape's transformation matrix 
     mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); 
     //DemoRenderer.checkGlError("glGetUniformLocation"); 

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

     // 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); 

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

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

     // Disable vertex array 
     GLES20.glDisableVertexAttribArray(mPositionHandle); 
     GLES20.glDisableVertexAttribArray(mTextureCoordinateHandle); 
    } 

} 
+0

Я забыл упомянуть: Я использую 512x512 .png файл для моего источника текстуры. – wtracy

+0

Это первый пример загрузки текстуры в opengl es 2.x. Я видел, весь код, который я нашел через google, равен 1.x. Невероятно, что на сайте разработчика Android ничего нет. Я все еще получаю сообщение «java.lang.Class для этого при попытке выполнить ошибку конструктора нулевого аргумента, хотя я уверен, что это исправление. – Androidcoder

ответ

1

Ваша ошибка GL_INVALID_ENUM почти наверняка из другого вызова. Имейте в виду, что значение ошибки сохраняется до тех пор, пока вы не проверите его. Таким образом, это может быть от любого вызова с момента последнего звонка glGetError().

С быстро сканирования кода, я вижу два вызова, которые получают неверный аргумент здесь:

GLES20.glActiveTexture(textureHandle[0]); 
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle); 
  • glActiveTexture() принимает перечисление, который определяет блок текстуры вы хотите связать с, в то время как вы проходите имя текстуры.
  • glBindTexture(), с другой стороны, требуется имя текстуры в качестве второго аргумента, в то время как вы передаете переменную, которой не присвоено значение нигде в размещенном коде.

Эти вызовы должны быть:

GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]); 
+0

Так оно и есть - я не могу поверить, что пропустил это. Спасибо! – wtracy

Смежные вопросы