Android OpenGL | ES 2.0纹理

时间:2013-04-01 19:43:46

标签: android textures opengl-es-2.0

我正在使用OpenGL | ES 2.0来创建一个简单的2D方块。我正在努力让纹理工作。请帮助我这方面。我附上了以下代码:

GFXUtils:

public class GFXUtils {
    public static final String TAG = "GFXUtils";    
    public static final int COORDS_PER_VERTEX = 3;
    public static final int COORDS_PER_TEXTURE = 2;
    public static int vertexStride = COORDS_PER_VERTEX * 4; // bytes per vertex
    public static int textureStride = COORDS_PER_TEXTURE * 4; // bytes per vertex

    public static Context Context = null;
    public static SparseIntArray textures = new SparseIntArray();

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

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

        return shader;
    }

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

    public static void loadTexture(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);

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

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

        textures.append(resourceId, textureHandle[0]);      
    }
}

顶点:

public class Vertex
{
    public FloatBuffer floatBuffer; // buffer holding the vertices
    public ShortBuffer indexBuffer;
    public int numVertices;
    public int numIndeces;

    //public float vertex[];

    public Vertex (float[] vertex, int coordsPerVertex)
    {
        //this.vertex = vertex;
        this.setVertices(vertex, coordsPerVertex);
    }

    public Vertex (float[] vertex, short[] indices, int coordsPerVertex)
    {
        //this.vertex = vertex;
        this.setVertices(vertex, coordsPerVertex);
        this.setIndices(indices);
    }

    private void setVertices(float vertex[], int coordsPerVertex)
    {
        // a float has 4 bytes so we allocate for each coordinate 4 bytes
        ByteBuffer factory = ByteBuffer.allocateDirect (vertex.length * 4);
        factory.order (ByteOrder.nativeOrder ());
        // allocates the memory from the byte buffer
        floatBuffer = factory.asFloatBuffer ();
        // fill the vertexBuffer with the vertices
        floatBuffer.put (vertex);
        // set the cursor position to the beginning of the buffer
        floatBuffer.position (0);
        numVertices = vertex.length / coordsPerVertex;
    }

    protected void setIndices(short[] indices) {
        ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
        ibb.order(ByteOrder.nativeOrder());
        indexBuffer = ibb.asShortBuffer();
        indexBuffer.put(indices);
        indexBuffer.position(0);
        numIndeces = indices.length;
    }
}

更新方:

public class Square{

    private static final String TAG = "Square";

    public float[] rotation = {0.0f,0.0f,45.0f};
    public float[] scale = {100.0f,100f,100f};
    public float[] position = {0.0f,0.0f,100f};
    public float[] color = { 0.0f, 0.0f, 1.0f, 1.0f };

    private int textureRef = -1;

    private int mMVPMatrixHandle;

    protected int DRAW_MODE = GLES20.GL_TRIANGLES;
    protected int mProgram; 
    protected int mPositionHandle;
    protected Vertex vertices;
    protected Vertex texture;

    private int mColorHandle;

    private int vsTextureCoord;
    private int fsTexture;  

    protected float[] result_matrix = new float[16];    

    private final String vertexShaderCode =
            "uniform mat4 uMVPMatrix;" +
                    "attribute vec4 vPosition;" +
                    "attribute vec2 TexCoordIn;" +
                    "varying vec2 TexCoordOut;" +
                    "void main() {" +
                    //the matrix must be included as a modifier of gl_Position
                    "  gl_Position = uMVPMatrix * vPosition;" +
                    "  TexCoordOut = TexCoordIn;" +
                    "}";

    private final String fragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "uniform sampler2D Texture;" +
                    "varying lowp vec2 TexCoordOut;" +                             
                    "void main() {" +                   
                    "  gl_FragColor = vColor;" +
                    "}";    
    //I am fully aware that I am not using the texture by assigning the colour, but until I can actually SEND the texture through, there would be no point.
    static 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


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

    public Square(int textureResourceId) {

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

        mProgram = GLES20.glCreateProgram();             // create empty OpenGL ES Program
        GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
        GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
        GLES20.glLinkProgram(mProgram);                  // creates OpenGL ES program executables
        textureRef = GFXUtils.textures.get(textureResourceId);

        // initialize vertex byte buffer for shape coordinates
        vertices = new Vertex(squareCoords, drawOrder, GFXUtils.COORDS_PER_VERTEX);

        texture = new Vertex (new float[]
                {               
                    1.0f, 0.0f,
                    0.0f, 0.0f,
                    1.0f, 1.0f,
                    0.0f, 1.0f,
                }, GFXUtils.COORDS_PER_TEXTURE);   

        DRAW_MODE = GLES20.GL_TRIANGLE_FAN;
    }

    private void getHandles()
    {

        //get handle to vertex shader's vPosition member
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        if (mPositionHandle == -1) Log.e(TAG, "vPosition not found");
        //get handle to fragment shader's vColor member
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        if (mColorHandle == -1) Log.e(TAG, "vColor not found");

        //get handle to shape's transformation matrix
        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        if (mMVPMatrixHandle == -1) Log.e(TAG, "uMVPMatrix not found");

        //get handle to texture coordinate variable
        vsTextureCoord = GLES20.glGetAttribLocation(mProgram, "TexCoordIn");
        if (vsTextureCoord == -1) Log.e(TAG, "TexCoordIn not found");

        //get handle to shape's texture reference
        fsTexture = GLES20.glGetUniformLocation(mProgram, "Texture");
        if (fsTexture == -1) Log.e(TAG, "Texture not found");

    }

    private void translateRotateScale(float[] matrix, float[] perspectiveMatrix)
    {       
        for (int i= 0; i < perspectiveMatrix.length;i++)
            matrix[i] = perspectiveMatrix[i];

        Matrix.translateM(matrix, 0, position[0], position[1], position[2]);
        Matrix.rotateM(matrix, 0, rotation[0], 1.0f, 0.0f, 0.0f);
        Matrix.rotateM(matrix, 0, rotation[1], 0.0f, 1.0f, 0.0f);
        Matrix.rotateM(matrix, 0, rotation[2], 0.0f, 0.0f, 1.0f);
        Matrix.scaleM(matrix, 0, scale[0], scale[1], scale[2]);            
    }

    public void draw(float[] mvpMatrix) {
        rotation[2]+=0.5;
        // Add program to OpenGL ES environment
        GLES20.glUseProgram(mProgram);
        GFXUtils.checkGlError("using program");

        //Housekeeping
        getHandles();
        translateRotateScale(result_matrix, mvpMatrix);
        //end housekeeping

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

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

        // Prepare the shape coordinate data
        GLES20.glVertexAttribPointer(mPositionHandle, GFXUtils.COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                GFXUtils.vertexStride, vertices.floatBuffer);
        GFXUtils.checkGlError("load vertex buffer");

        GLES20.glVertexAttribPointer(vsTextureCoord, GFXUtils.COORDS_PER_TEXTURE,
                GLES20.GL_FLOAT, false, 
                GFXUtils.textureStride, texture.floatBuffer);
        GFXUtils.checkGlError("load texture buffer - " + vsTextureCoord);

        // Enable a handle to the shape vertices
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        GFXUtils.checkGlError("enable position handle");
        GLES20.glEnableVertexAttribArray(vsTextureCoord);
        GFXUtils.checkGlError("enable texture handle");

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GFXUtils.checkGlError("activtexture");
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureRef);
        GFXUtils.checkGlError("bindtexture");
        GLES20.glUniform1i(fsTexture, 0);
        GFXUtils.checkGlError("uniformi");
        //Draw the shape
        GLES20.glDrawElements(DRAW_MODE, vertices.numIndeces, GLES20.GL_UNSIGNED_SHORT, vertices.indexBuffer);
        GFXUtils.checkGlError("glDrawArrays with " + vertices.numVertices + " vertices");

        //Disable vertex array
        GLES20.glDisableVertexAttribArray(vsTextureCoord);
        GLES20.glDisableVertexAttribArray(mPositionHandle);
        GFXUtils.checkGlError("glDisableVertexAttribArray for position");

    }
}

UPDATE 但它现在找不到fsTexture的'Texture'sampler2D参数。图像在这里:

enter image description here

我看过以下内容:

Android: OpenGL ES 2.0 - Texture always black
Draw multiple objects with textures
Android OpenGLES 2.0 Texture Mapping Does Not Work
Textures in OpenGL ES 2.0 for Android
http://www.learnopengles.com/android-lesson-six-an-introduction-to-texture-filtering/
http://www.learnopengles.com/android-lesson-four-introducing-basic-texturing/
http://blog.shayanjaved.com/2011/05/13/android-opengl-es-2-0-render-to-texture/
http://www.raywenderlich.com/4404/opengl-es-2-0-for-iphone-tutorial-part-2-textures
http://androgeek.info/?p=167

2 个答案:

答案 0 :(得分:2)

好的,这就是我对解决方案的猜测:

  • glVertexAttribPointer()调用似乎没问题

  • 我的猜测

    vsTextureCoord == -1

    glGetAttribLocation()不会生成错误 如果找不到该属性。你必须检查结果是否 不是-1,以确保一切顺利。

    问题的根源可能是你的属性TexCoordIn 着色器是一个vec4!

答案 1 :(得分:1)

floatBuffer应该包含该数组中第一个元素的地址。你在glVertexAttribPointer之后有错误,因为最后一个参数没有指向顶点数据。直接解决方案是使floatbuffer =&amp; vertexdata

我的建议是使用glGenBuffer,glBindBuffer,glBufferData将顶点数据放到gl_array_buffer中。之后,只需使用0作为最后一个参数,在glVertexAttribPointer之前绑定缓冲区。这比使用顶点的地址

更快