2015-08-12 4 views
1

Я пытаюсь сделать несколько «простых» тестов. Я столкнулся со многими трудностями, но я не нашел решения для одного из них.Android OpenGL ES 2.0 Вращающийся PNG перекошен

Мой тест:

  1. Рисунок вращающийся квадрат (сделанный с 2 ​​треугольников)
  2. Рисунок вращающуюся текстуру (PNG загруженного файла)

Проблема заключается в том, что обращается PNG является перекошенными во время вращения, а не квадратом.

0 degree

90 degrees

Как вы можете видеть, Squre сохраняет те же размеры, через вращение в то время как масштаб «изменен», как если бы я хотел, чтобы она всегда помещается на экране.

Ниже вы можете найти некоторые из моего кода:

Проекция матрица, которую я использовал

public void onSurfaceChanged(GL10 unused, int width, int height) { 
    GLES20.glViewport(0, 0, width, height); 
    this.screenWidth = width; 
    this.screenHeight = height; 
    float ratio = (float) width/height; 

    // this projection matrix is applied to object coordinates 
    // in the onDrawFrame() method 
    Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7); 
} 

матрицу вида и матрицу вращения

public void onDrawFrame(GL10 unused) { 

     // Rotation matrix 
     float[] scratch = new float[16]; 
     // Same rotation matrix except the angle is the opposite 
     // Because of the way the PNG is loaded ? 
     float[] scratch_ = new float[16]; 

     // Redraw background color 
     GLES20.glClear(GLES20.GL_COLOR_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); 

     // Create a rotation transformation for the triangle 
     float angle = 90; 
     Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, 1.0f); 
     Matrix.setRotateM(mRotationMatrix_, 0, -angle, 0, 0, 1.0f); 

     // Combine the rotation matrix with the projection and camera view 
     // Note that the mMVPMatrix factor *must be first* in order 
     // for the matrix multiplication product to be correct. 
     Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0); 
     Matrix.multiplyMM(scratch_, 0, mMVPMatrix, 0, mRotationMatrix_, 0); 

     //draw square and scale 
     draw(scratch, scratch_) 
    } 

Координаты моих элементов

float squareCoords[] = { 
      -0.5f, 0.5f, 0.0f, // top left 
      -0.5f, -0.5f, 0.0f, // bottom left 
      0.5f, -0.5f, 0.0f, // bottom right 
      0.5f, 0.5f, 0.0f }; // top right 

    float scaleCoords[] = { 
      -0.2f, 1.5f, // top left 
      -0.2f, -0.5f, // bottom left 
      0.2f, -0.5f, // bottom right 
      0.2f, 1.5f}; // top right 

Наконец, вы можете найти ниже моего класса «Изображение», который я использую, чтобы сделать PNG

public class Image { 
    //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 = 
      "attribute vec2 a_TexCoordinate;" + 
        "varying vec2 v_TexCoordinate;" + 
        "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 sampler2D u_Texture;" + 
        "varying vec2 v_TexCoordinate;" + 
        "void main() {" + 
        "gl_FragColor = texture2D(u_Texture, v_TexCoordinate);" + 
        "}"; 

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

    // number of coordinates per vertex in this array 
    static final int COORDS_PER_VERTEX = 2; 

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

    public Image(final Context activityContext, float[] coords) 
    { 
     mActivityContext = activityContext; 

     //Initialize Vertex Byte Buffer for Shape Coordinates/# of coordinate values * 4 bytes per float 
     ByteBuffer bb = ByteBuffer.allocateDirect(coords.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(coords); 
     //Set the Buffer to Read the first coordinate 
     vertexBuffer.position(0); 

     // U, V coordinates 
     final float[] cubeTextureCoordinateData = 
       { 
         0.0f, 0.0f, 
         0.0f, 1.0f, 
         1.0f, 1.0f, 
         1.0f, 0.0f 
       }; 

     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(coords.length * 2); 
     dlb.order(ByteOrder.nativeOrder()); 
     drawListBuffer = dlb.asShortBuffer(); 
     drawListBuffer.put(drawOrder); 
     drawListBuffer.position(0); 

     int vertexShader = PfdRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); 
     int fragmentShader = PfdRenderer.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 
     // Retrieve our image from resources. 
     int id = mActivityContext.getResources().getIdentifier("drawable/coeur_hsi", "drawable", 
       mActivityContext.getPackageName()); 
     Log.d("Id of coeur_hsi is: ", Integer.toString(id)); 
     mTextureDataHandle = loadTexture(mActivityContext, id); 
    } 

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

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

Мое предположение, что ошибка происходит из матрицы проекции, но я не могу понять, что проблема именно. Не могли бы вы рассказать мне, почему изображение моего PNG искажено?

ответ

3

Выглядит так, как будто вы просчитали свой gl_Position.

"gl_Position = vPosition * uMVPMatrix;"

Когда вы смотрите на матричном умножении, ты должен знать, что при умножении двух матриц (а Vertex также 1x4 Matrix) умножить каждую строку первой матрицы, с каждым столбцов второй матрицы. Это работает только в том случае, если матрицы «совместимы». Это означает, что первая матрица должна иметь одинаковое количество столбцов, так как вторая матрица имеет строки. Например. вы можете умножить матрицу 3x2 с матрицей 2x3, но вы не сможете умножить матрицу 2x3 с матрицей 3x2.

Поэтому заказ очень важен!

Try вычисления как

gl_Position = uMVPMatrix * vPosition; 

Wiki имеет хорошую страницу на матричном умножении. https://en.wikipedia.org/wiki/Matrix_multiplication

+0

Большое спасибо за ваш короткий, но очень четкий ответ. Вы решили свои проблемы! – RomainZ

+0

Вы очень желанны, я собираюсь отредактировать свой пост более подробно для тех, у кого есть подобные проблемы. –

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