2013-08-17 123 views
2

我正试图将一个简单的2D纹理加载到一个正方形上并将其显示在我的GLSurfaceView背面。我已经复制并修复了Draw a 2D Image using OpenGL ES 2.0中的代码,但是当我安装并运行应用程序时,图像被分成4个象限,然后重新排列。Android OpenGL ES 2纹理象限旋转

这里是Sprite类,我实现:

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 = uMVPMatrix * vPosition;" + 
    //Test 
    "v_TexCoordinate = a_TexCoordinate;" + 
    //End Test 
    "}"; 

private final String fragmentShaderCode = 
    "precision mediump float;" + 
    "uniform vec4 v_Color;" + 
    //Test 
    "uniform sampler2D u_Texture;" + 
    "varying vec2 v_TexCoordinate;" + 
    //End Test 
    "void main() {" + 
    //"gl_FragColor = v_Color;" + 
    //"gl_FragColor = (v_Color * texture2D(u_Texture, v_TexCoordinate));" + 
    // Just draw the texture, don't apply a color 
    "gl_FragColor = 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 }; 

// Image to draw as a texture 
final int textureID = R.raw.quadrants; 

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*/ 
      /* 
      This was in the code in the aforementioned StackOverflow post, 
      but doesn't work either 
      -0.5f, 0.5f, 
      -0.5f, -0.5f, 
      0.5f, -0.5f, 
      0.5f, 0.5f 
      */ 
      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 = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, 
               vertexShaderCode); 
    int fragmentShader = MyGLRenderer.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, textureID); 
} 

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 v_Color member 
    mColorHandle = GLES20.glGetUniformLocation(shaderProgram, "v_Color"); 

    //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]; 
    } 
} 

举个例子,在http://changesuk.net/wp-content/uploads/2009/05/4-quadrants.jpg图像被改变,这样的数字都是正确的方向,但在模式

4 | 3 
----- 
2 | 1 

如果我改变添加正方形坐标的顺序(例如从“左下角”开始),图像的象限会移动,但也会围绕它们各自的中心旋转(在上图中,数字将全部是在他们的侧面或头上)。我浏览过每一行代码,无法理解这里发生了什么。有没有人曾经遇到过这种行为,或者有人可能会解释导致它的原因?

+0

这里有什么问题? – zyzof

+0

我已更新帖子。 –

回答

2

我一直在查看SO一段时间,但从来没有机会回答一个问题。我知道这个问题有5个月了,但我会尽力回答。

基本上,你在做什么是你没有正确对齐你的纹理的角落与你的顶点的角落。你得到

4 | 3 
----- 
2 | 1 

,因为你的纹理中心是您正方形的右下角,并且纹理被重复,因此4和2的右侧和3是在上面。

解决这个问题的办法是在你的顶点着色器

uniform vec4 pos; 

添加新vec4与X,Y,宽度和高度填充

int pos = GLES20.glGetUniformLocation(mProgram, "pos"); 
    GLES20.glUniform4f(pos, .5f, .5f, 1, 1); // x, y, width, height 

现在改变这个

v_TexCoordinate = a_TexCoordinate; 

至此

v_TexCoordinate = vec2((a_TexCoordinate.x - pos.x)/pos.z, (a_TexCoordinate.y - pos.y)/pos.w); 

这应该做的伎俩。

0

我尝试了P0rter解决方案,但它没有为我工作。

而且要清楚的是,问题并不在于象限的排列,而是开始以中心为中心。其他方面只是默认重复。 如果你打开它,当加载纹理时,它将只绘制右下象限。

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, 
     GLES20.GL_TEXTURE_WRAP_S, 
     GLES20.GL_CLAMP_TO_EDGE 
    ); 
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, 
     GLES20.GL_TEXTURE_WRAP_T, 
     GLES20.GL_CLAMP_TO_EDGE 
    ); 

我得到了另一种解决方案。我不完全知道我在做什么,所以我只是粘贴,为我工作。

public class Sprite extends GLObject { 

    final static float COORDS_SQUARE[] = { 
     -0.5f, 0.5f, 0.0f, 
     -0.5f, -0.5f, 0.0f, 
     0.5f, -0.5f, 0.0f, 
     0.5f, 0.5f, 0.0f 
    }; 


    /** 
    * Number of coordinates per point in this array. 
    */ 
    protected static final int COORDINATES_PER_VERTEX = 3; 

    final static float TEXTURE_COORDS[] = { 
     0.0f, 1.0f, 
     0.0f, 0.0f, 
     1.0f, 0.0f, 
     1.0f, 1.0f 
    }; 

    /** 
    * Number of coordinates per point in this array. 
    */ 
    protected static final int COORDINATES_PER_TEXTURE_VERTEX = 2; 

    /** 
    * Order to draw COORDINATES_VERTICES 
    */ 
    protected static final short DRAW_ORDER[] = { 
     0, 1, 2, 0, 3, 2 
    }; 

    private static final String VERTEX_SHADER_CODE = 
     "attribute vec2 aTexCoordinate;" + 
      "varying vec2 vTexCoordinate;" + 
      "uniform mat4 uMVPMatrix;" + 
      "attribute vec4 vPosition;" + 
      "void main() {" + 
      " gl_Position = uMVPMatrix * vPosition;" + 
      " vTexCoordinate = aTexCoordinate;" + 
      "}"; 

    private static final String FRAGMENT_SHADER_CODE = 
     "precision mediump float;" + 
      "uniform sampler2D uTexture;" + 
      "varying vec2 vTexCoordinate;" + 
      "void main() {" + 
      " gl_FragColor = texture2D(uTexture, vTexCoordinate);" + 
      "}"; 

    private final int mProgram; 

    private final FloatBuffer vertexBuffer; 
    private final ShortBuffer drawListBuffer; 
    private final FloatBuffer mTextureCoordinates; 
    private int mTextureDataHandle; 

    public Sprite(final Context context, @DrawableRes int resID) { 

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

     ByteBuffer tcb = ByteBuffer.allocateDirect(TEXTURE_COORDS.length * 4); 
     tcb.order(ByteOrder.nativeOrder()); 
     mTextureCoordinates = tcb.asFloatBuffer(); 
     mTextureCoordinates.put(TEXTURE_COORDS); 
     mTextureCoordinates.position(0); 

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

     int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER_CODE); 
     int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_CODE); 

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

     //Texture Code 
     GLES20.glBindAttribLocation(mProgram, 0, "aTexCoordinate"); 

     GLES20.glLinkProgram(mProgram); 

     //Load the texture 
     mTextureDataHandle = loadTexture(context, resID); 
    } 

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

     //Get handle to vertex shader's vPosition member 
     int positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); 
     int textureUniformHandle = GLES20.glGetAttribLocation(mProgram, "uTexture"); 
     int textureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "aTexCoordinate"); 
     int MVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); 

     //Enable a handle to the triangle COORDINATES_VERTICES 
     GLES20.glEnableVertexAttribArray(positionHandle); 

     //Prepare the triangle coordinate data 
     vertexBuffer.position(0); 
     GLES20.glVertexAttribPointer(
      positionHandle, COORDINATES_PER_VERTEX, 
      GLES20.GL_FLOAT, false, 
      0, vertexBuffer 
     ); 

     //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(textureUniformHandle, 0); 

     //Pass in the texture coordinate information 
     mTextureCoordinates.position(0); 
     GLES20.glVertexAttribPointer(
      textureCoordinateHandle, COORDINATES_PER_TEXTURE_VERTEX, 
      GLES20.GL_FLOAT, false, 
      0, mTextureCoordinates 
     ); 
     GLES20.glEnableVertexAttribArray(textureCoordinateHandle); 

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

     //Draw the triangle 
     drawListBuffer.position(0); 
     GLES20.glDrawElements(GLES20.GL_TRIANGLES, DRAW_ORDER.length, GLES20.GL_UNSIGNED_SHORT, 
      drawListBuffer); 

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

在我GLObject类是用于装载质地等,没有什么重要的一些共享的方法。