【问题标题】:Opengl ES texture is not applied to objectOpengl ES纹理不适用于对象
【发布时间】:2015-01-13 13:37:41
【问题描述】:

我是 android 上的 opengl 的新手,通过做一些例子来学习 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程序对象并同时运行它们是否有效?

[更新]

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

【问题讨论】:

  • 你在调用 setEGLContextClientVersion(2);什么地方?
  • 是的,它在 MainActivity onCreate 函数中调用

标签: android opengl-es


【解决方案1】:

您没有为纹理坐标调用 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");

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

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 调用后调用它,并传入一个字符串,该字符串可以是您想要的任何调试消息。如果出现任何问题,那么您将得到一个异常,而不仅仅是无声的失败,这会让您摸不着头脑,试图找出问题所在。确保将其从最终构建中删除以避免强制关闭。

【讨论】:

  • P.S.关于你的第二个问题,显然可以同时打开两个 OpenGLES 应用程序并在它们之间切换,但是当一个失去焦点时,它的 GL 上下文不再有效,当它重新获得焦点时它必须重新创建它的纹理等。所以我不认为你可以让应用程序在后台进行渲染。但是,我对此不是 100% 确定,所以我没有将其包含在我的答案中。
  • 感谢回复,但启用属性并不能解决问题:( .
  • 我认为我的问题是模棱两可的,因为程序我的意思是 opengl es 程序对象;不是安卓活动。我认为您提到有多个 opengl es 活动。我将编辑我的问题以消除歧义。不过感谢您的回复:)。
  • 尝试添加 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);在您调用 glBindTexture() 之前添加到您的 loadTexture 函数。它可能不会有什么不同,因为这是默认设置,但还是试试吧。
  • 另外,调用 glGenerateMipmap(GLES20.GL_TEXTURE_2D);调用 texImage2D() 之后
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-28
  • 1970-01-01
相关资源
最近更新 更多