Opengl ES 纹理未应用于 object

Opengl ES texture is not applied to object

我是 android 上的 opengl es 新手,通过做一些例子来学习 opengl。我正在使用两个程序绘制 3 objects。以下代码加载纹理并绘制一个正方形。但它显示为黑色方块,而不是将纹理应用于 body.

我的fragment-shader代码

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

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

我的vertex-shader代码

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

我的object顶点缓冲区

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 程序 object 并同时 运行 它们是否有效?

[更新]

问题出在 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);
        }

您没有为纹理坐标调用 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 调用后调用它,并传入一个字符串,该字符串可以是您想要的任何调试消息。如果出现任何问题,那么您将得到一个异常,而不仅仅是无声的失败,这会让您挠头试图找出问题所在。请务必将其从您的最终版本中删除以避免强制关闭。