Невозможно отобразить 2D-изображение в Android с открытым GLES 2.0

Я попытался отобразить какой-то 2D-объект, и я могу это сделать, но теперь я попытался отобразить некоторые изображения в opengl, но он ничего не показывает. Вот мой код рендеринга изображения.

package com.example.androidinternalmaps;

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

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;

public class ImageObject 
{
    private final Context mActivityContext;

    private final FloatBuffer mCubeTextureCoordinates;
    private int mTextureUniformHandle;
    private int mTextureCoordinateHandle;
    private final int mTextureCoordinateDataSize = 2;
    private int mTextureDataHandle;

    private final String VerShader = 
    "uniform mat4 u_Matrix;"+
    "attribute vec4 a_Position;"+  
    "attribute vec2 a_TextureCoordinates;"+
    "varying vec2 v_TextureCoordinates;"+
    "void main()"+                    
    "{"+                            
        "v_TextureCoordinates = a_TextureCoordinates;"+       
        "gl_Position = u_Matrix * a_Position;"+    
    "}";

    private final String FragShader = 
            "precision mediump float;"+ 
            "uniform sampler2D u_TextureUnit;"+                                         
            "varying vec2 v_TextureCoordinates;"+                                       
            "void main()"+                          
            "{"+                                
                "gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);"+                                   
            "}";

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

    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

    float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };

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

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

        final float[] cubeTextureCoordinateData =
        {                                               
            -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, VerShader);
        int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, FragShader);

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

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

Он ничего не показывает. Просто пустой экран. Я не знаю, что я делаю неправильно. Нужна помощь. Спасибо .

Мой класс рендерера

package com.example.androidinternalmaps;


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

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;

public class MyGLRenderer implements GLSurfaceView.Renderer {

    private FloorPolygon floorPolygon;
    private ImageObject imageObject;
    private final float[] mMVPMatrix = new float[16];
    private final float[] mProjectionMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];
    private final float[] mRotationMatrix = new float[16];

    private float originX = 0.0f, originY = 0.0f;
    private float translationDx=0.0f,translationDy=0.0f;
    private float originScaleX = 2.5f, originScaleY = 2.5f;
    private float scaleDx = 1.0f, scaleDy = 1.0f; 
    private float surfaceViewWidth, surfaceViewHeight;
    private Context mContext;

    public MyGLRenderer(Context context)
    {
        mContext = context;
    }
    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    floorPolygon = new FloorPolygon();
    imageObject = new ImageObject(mContext);
    }

    public void onDrawFrame(GL10 unused) 
    {
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
    Matrix.translateM(mMVPMatrix, 0, originX+translationDx, originY+translationDy, 0.0f);
    Matrix.scaleM(mMVPMatrix, 0, scaleDx*originScaleX, scaleDy*originScaleY, 0.0f);

    imageObject.Draw(mMVPMatrix);
    }

    public void onSurfaceChanged(GL10 unused, int width, int height) 
    {
        surfaceViewHeight = height;
        surfaceViewWidth = width;

    GLES20.glViewport(0, 0, width, height);
    GLES20.glViewport(0, 0, width, height);
    float ratio = (float) width / height;
    Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
    }

    public static int loadShader(int type, String shaderCode)
    {
    int shader = GLES20.glCreateShader(type);
    GLES20.glShaderSource(shader, shaderCode);
    GLES20.glCompileShader(shader);

    return shader;
    }

    public void setTranslationPoints(float translationDx, float translationDy)
    {
        this.translationDx = ((translationDx/surfaceViewWidth)*2);
        this.translationDy = -((translationDy/surfaceViewHeight)*2);
    }

    public void setScalePoints(float scaleDx, float scaleDy)
    {
        this.scaleDx = scaleDx;
        this.scaleDy = scaleDy;
    }
}

person nilkash    schedule 09.01.2014    source источник
comment
Являются ли размеры ваших текстур степенью двойки? Попробуйте вызвать GLES20.glClearColor, чтобы задать цвет фона, отличный от черного. Если вы видите, что ваш объект полностью окрашен в черный цвет, это проблема с текстурой. Где вы устанавливаете проекцию и матрицу просмотра? Вы уверены, что смотрите на объект?   -  person NigelK    schedule 09.01.2014
comment
ОК, позвольте мне поставить весь код. И размеры моей текстуры равны степени двойки.   -  person nilkash    schedule 09.01.2014
comment
Я меняю цвет фона на белый. И нет рендеринга черной текстуры :(. Какие-то проблемы в моем коде?   -  person nilkash    schedule 09.01.2014


Ответы (1)


Одна проблема, я думаю, заключается в следующем:

Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

Ваш вектор взгляда равен (0,0,0), который не описывает направление. Положение вашего глаза равно (0,0,5), что указывает на положение по направлению к вам по оси Z от начала координат. Таким образом, ваш вектор взгляда должен быть направлен от вас к исходной точке. Поэтому попробуйте изменить вектор взгляда на (0,0,-1):

Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5, 0f, 0f, -1f, 0f, 1.0f, 0.0f);

РЕДАКТИРОВАТЬ:

Для начала переместите это в onSurfaceChanged, так как вам не нужно вызывать его в каждом кадре, только когда создается поверхность:

Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5, 0f, 0f, -1f, 0f, 1.0f, 0.0f);

Теперь о классе ImageObject. В вершинном шейдере измените «a_TextureCoordinates» на «a_TexCoordinate», чтобы имя соответствовало тому, что вы используете в коде конструктора.

В конструкторе внесите это изменение:

//GLES20.glBindAttribLocation(shaderProgram, 0, "a_TexCoordinate");
GLES20.glBindAttribLocation(shaderProgram, 0, "a_Position");
GLES20.glBindAttribLocation(shaderProgram, 1, "a_TexCoordinate");

Раньше вы привязывали «a_TexCoordinate» к позиции 0, но она должна быть позицией 1, поскольку это второй атрибут в шейдере. Первый атрибут в вашем шейдере — «a_Position», поэтому он должен быть привязан к позиции 0.

В Draw внесите следующие изменения:

//mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "a_Position");

//mTextureUniformHandle = GLES20.glGetAttribLocation(shaderProgram, "u_Texture");
mTextureUniformHandle = GLES20.glGetUniformLocation(shaderProgram, "u_TextureUnit");

//mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix");
mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "u_Matrix");

Это потому, что имена не совпадают с именами в шейдерах. Для обработчика текстуры это униформа, а не атрибут, поэтому вам нужно использовать glGetUniformLocation.

Так и должно быть, я думаю. Я запустил ваш код и получил текстуру, нарисованную на экране.

person NigelK    schedule 09.01.2014
comment
Спасибо за повтор. Я попробовал ваше решение, но оно не работает. Есть ли хороший учебник по рендерингу изображений в Android Open Gles 2.0? Спасибо за помощь. - person nilkash; 09.01.2014
comment
Извините за задержку, я был занят изучением вашего кода - это было приятное и полезное упражнение для меня (не делал этого в течение нескольких месяцев). - person NigelK; 09.01.2014
comment
Спасибо за большую помощь :) - person nilkash; 10.01.2014