Opengl ES纹理不适用于对象

时间:2015-01-10 19:24:01

标签: android opengl-es

我是初学者,通过做一些例子来学习机器人和学习opengl。我正在使用两个程序来绘制3个对象。以下代码加载纹理并绘制正方形。但它看起来像是一个黑色方块而不是将纹理应用到身体上。

我的片段着色器代码

precision mediump float;
uniform sampler2D u_Texture;
varying vec2 v_TexCoordinate;

void main() {
    gl_FragColor = texture2D(u_Texture, v_TexCoordinate);
}

我的顶点着色器代码

attribute vec2 a_TexCoordinate;

varying vec2 v_TexCoordinate;

attribute vec4 a_Position;

uniform mat4 u_Matrix;

void main() {
    gl_Position = u_Matrix * a_Position;
    v_TexCoordinate = a_TexCoordinate;
}

我的对象顶点缓冲区

float [] vBufferFloat = new float[] {
            -0.2f, -0.2f, 1f,
            0.2f, -0.2f, 1f,
            0.2f, 0.2f, 1f,
            -0.2f, 0.2f, 1f,
            -0.2f, -0.2f, 1f,
        };

我的纹理缓冲区

float [] texCoordinate = new float[] {
            -0.2f, -0.2f, 
            0.2f, -0.2f, 
            0.2f, 0.2f, 
            -0.2f, 0.2f,
            -0.2f, -0.2f,
        };

我的onSurfaceCreated&& onDrawFrame代码

public void onSurfaceCreated() {
        cloudRendereProgram = ShaderHelper.createProgram(mContext, R.raw.sky_texture_vertex_shader, R.raw.sky_texture_fragment_shader);
        cloudTextureId = Utils.loadTexture(mContext, com.elpis.gamecontroller.R.drawable.cloud);
        aTextureLocation = GLES20.glGetAttribLocation(cloudRendereProgram, "a_TexCoordinate");
        uMatrixLocation = GLES20.glGetUniformLocation(cloudRendereProgram, "u_Matrix");
        aPositionLocation = GLES20.glGetAttribLocation(cloudRendereProgram, "a_Position");
        uTextureLocation = GLES20.glGetUniformLocation(cloudRendereProgram, "u_Texture");
    }

public void onDrawFrame() {
        float [] mVMatrix = new float[16];
        GLES20.glUseProgram(cloudRendereProgram);
        GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false, 0, vBuff.buffer);
        GLES20.glEnableVertexAttribArray(aPositionLocation);
        Matrix.multiplyMM(mVMatrix, 0, modelMatrix, 0, projectionMatrix, 0);
        GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, mVMatrix, 0);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.cloudTextureId);
        GLES20.glUniform1i(uTextureLocation, 0);
        GLES20.glVertexAttribPointer(aTextureLocation, 2, GLES20.GL_FLOAT, false, 0, texBuff.buffer);
        GLES20.glEnableVertexAttribArray(aTextureLocation);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 5);
    }

和我的纹理加载器帮助程序代码

public static int loadTexture(Context ctx, int resId) {
        final int [] textureHandle = new int[1];
        GLES20.glGenTextures(1, textureHandle, 0);
        if (textureHandle[0] == 0)
            return 0;
        final BitmapFactory.Options options = new Options();
        options.inScaled = false;
        final Bitmap imgTexture = BitmapFactory.decodeResource(ctx.getResources(), resId);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
        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);

        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, imgTexture, 0);
        imgTexture.recycle();

        return textureHandle[0];
    }

当我运行Android应用程序时,我看到的是一个黑色方块,而不是看到云的纹理。所以,如果有人指出我正确的方向,我将不胜感激。

两个简单的问题;使用不同的着色器创建多个opengl程序对象并同时运行它们是否有效?

[UPDATE]

问题出在onDrawFrame()上。我必须使用vBuff.buffer.position(0)和texBuff.buffer.position(0)才能正确绘制纹理。

public void onDrawFrame() {
            float [] mVMatrix = new float[16];
            GLES20.glUseProgram(cloudRendereProgram);
            // FIX 
            vBuff.buffer.position(0);
            texBuff.buffer.position(0);
            // END FIX
            GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false, 0, vBuff.buffer);
            GLES20.glEnableVertexAttribArray(aPositionLocation);
            Matrix.multiplyMM(mVMatrix, 0, modelMatrix, 0, projectionMatrix, 0);
            GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, mVMatrix, 0);

            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.cloudTextureId);
            GLES20.glUniform1i(uTextureLocation, 0);
            GLES20.glVertexAttribPointer(aTextureLocation, 2, GLES20.GL_FLOAT, false, 0, texBuff.buffer);
            GLES20.glEnableVertexAttribArray(aTextureLocation);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 5);
        }

1 个答案:

答案 0 :(得分:0)

你没有为纹理坐标调用glEnableVertexAttribArray。将此行添加到onDrawFrame():

GLES20.glEnableVertexAttribArray(aTextureLocation);

在loadTexture()函数中上传纹理texImage2D()后调用glGenerateMipmap,以确保所有mip-map级别都有效:

glGenerateMipmap(GLES20.GL_TEXTURE_2D);

另外,将这些调用从surfaceCreated()函数移到drawFrame()的开头:

aTextureLocation = GLES20.glGetAttribLocation(cloudRendereProgram, "a_TexCoordinate");
uMatrixLocation = GLES20.glGetUniformLocation(cloudRendereProgram, "u_Matrix");
aPositionLocation = GLES20.glGetAttribLocation(cloudRendereProgram, "a_Position");
uTextureLocation = GLES20.glGetUniformLocation(cloudRendereProgram, "u_Texture");

(可能是这些变量未正确绑定或者GL上下文尚未在surfaceCreated()中正确设置)

OpenGLES的调试技巧。将此函数添加到您的代码中(它来自Android OpenGLES示例):

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

你可以在每次OpenGLES调用之后调用它,并传入一个String,它可以是你想要的任何调试消息。如果出现任何问题,那么你会得到一个例外,而不仅仅是无声的失败,这会让你摸不着头脑,试图弄清楚出了什么问题。确保将其从最终构建中移除以避免强制关闭。