Android OpenGL es 2.0无法在对象上重新加载纹理。

时间:2015-06-09 23:41:22

标签: android textures opengl-es-2.0 reload

我已经设法加载纹理并自由旋转球体,这要归功于这里提到的几个教程,问题和答案,但我偶然发现在运行时需要纹理重新加载(获取位图图像,处理它然后将其应用为对象的新纹理)。我没有为我的具体问题找到任何可行的解决方案(我已经阅读了所有相关的问题和答案)。 我是OpenGL的新手。这是我的第二个项目,我的第一个3D项目和我在这里提出的第一个问题。所以这就是:

基本上,纹理加载在以下函数中完成:

    public void loadGLTexture(final Context context, final int texture) {
    GLES20.glGenTextures(1, mTextures, 0);
    if (mTextures[0] != 0)
    {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inScaled = false;
        final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), texture, options);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[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, bitmap, 0);
        bitmap.recycle();
    }

    if (mTextures[0] == 0)
    {
        throw new RuntimeException("Texture load fail");
    }
}

在此功能中完成抽奖:

     public void draw(float[] mvpMatrix) {
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.mTextures[0]);
    GLES20.glFrontFace(GLES20.GL_CW);


    for (int i = 0; i < this.mTotalNumStrips; i++) {
        //vertex
        this.mVertexBuffer.get(i).position(0);
        GLES20.glVertexAttribPointer(mPositionHandle, NUM_FLOATS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                vertexStride, this.mVertexBuffer.get(i));
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        //texture
        this.mTextureBuffer.get(i).position(0);
        GLES20.glVertexAttribPointer(mTextureCoordinateHandle, NUM_FLOATS_PER_TEXTURE,
                GLES20.GL_FLOAT, false,
                textureStride, this.mTextureBuffer.get(i));
        GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
        //draw strip
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, this.mVertices.get(i).length / NUM_FLOATS_PER_VERTEX);
    }

    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
    // Disable the client state before leaving.
    GLES20.glDisableVertexAttribArray(mPositionHandle);
    GLES20.glDisableVertexAttribArray(mTextureCoordinateHandle);
}

在上面的函数中,我使用Strips tehnique渲染一个球体。对于每个条带,我必须加载纹理和顶点数据并最终绘制它。

我还有一个应该删除纹理的函数:

        public void clearGLTextures(){
    GLES20.glDeleteTextures(1, mTextures, 0);
}

我想在这里实现的是纹理重新加载,所以计划是:

INITIALISE(有效):loadGLTexture(initialtexture) - &gt;循环draw()函数

RELOAD(不起作用):clearGLTextures() - &gt; loadGLTexture(newTexture) - &gt;循环draw()函数

因此,不仅我无法重新加载纹理,而且对clearGLTextures()的调用似乎也不起作用,因为初始纹理仍然存在于scren中。

欢迎任何想法, 谢谢!

2 个答案:

答案 0 :(得分:3)

这是在Android上进行OpenGL编程时常见问题的一个例子。不幸的是,症状变化很大,所以问题并不是真的重复。

使用GLSurfaceView时,它会创建一个单独的渲染线程。您的GLSurfaceView.Renderer实施中的所有方法(onSurfaceCreatedonSurfaceChangedonDrawFrame)都会在此渲染广告系列中调用。

难题的第二部分是你需要一个当前的OpenGL上下文来进行OpenGL调用。 OpenGL上下文是当前每个线程GLSurfaceView负责创建上下文,并使其在呈现线程中保持最新状态。

因此,您无法从其他线程进行任何OpenGL调用(除非您做了更多工作,并增加了复杂性)。最常见的错误是尝试从UI线程进行OpenGL调用,通常在处理触摸事件等用户输入时。这些电话无效。

如果要执行OpenGL调用以响应用户输入,有许多选项。例如,您可以在Renderer中设置描述必要状态更改的成员,并在onDraw()方法中进行检查。另一个方便的选择是在视图上使用queueEvent()方法,它允许您传入稍后将在渲染线程中执行的Runnable

答案 1 :(得分:1)

我遇到了同样的问题。

Reto Koradi解释说很棒,但我想分享我的解决方案: 我在GLSurfaceView中使用了 queueEvent Runnable

public void addTexture(final int textureResId) {
    queueEvent(new Runnable() {
        @Override
        public void run() {
            mRenderer.loadTexture(textureResId);
            // or different GL thread tasks like clearing the texture
        }
    });
}
相关问题