Android OpenGL es 2.0 无法重新加载对象上的纹理。
Android OpenGL es 2.0 Can not reload textures on object.
我已经成功地加载纹理并自由旋转球体,这要归功于这里提出的几个教程、问题和答案,但我偶然发现需要在运行时重新加载纹理(获取位图图像,处理它然后应用它作为对象的新纹理)。我没有为我的特定问题找到任何有效的解决方案(我已经阅读了所有相关的问题和答案)。
我对 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 技术来渲染一个球体。对于每个条带,我必须加载纹理和顶点数据并最终绘制它。
我还有一个应该删除纹理的函数,除了:
public void clearGLTextures(){
GLES20.glDeleteTextures(1, mTextures, 0);
}
我想在这里实现的是重新加载纹理,所以计划是:
INITIALISE(有效):loadGLTexture(initialtexture)-> 循环 draw() 函数
重新加载(不起作用):clearGLTextures() -> loadGLTexture(newTexture) -> 循环 draw() 函数
因此,不仅我无法重新加载纹理,而且对 clearGLTextures() 的调用似乎也不起作用,因为初始纹理仍保留在屏幕上。
欢迎任何想法,
谢谢!
这是在 Android 上进行 OpenGL 编程时常见问题的一个示例。不幸的是,症状变化很大,所以问题并不是真的重复。
当您使用 GLSurfaceView
时,它会创建一个单独的渲染线程。 GLSurfaceView.Renderer
实现(onSurfaceCreated
、onSurfaceChanged
、onDrawFrame
)中的所有方法都在此渲染线程中调用。
难题的第二部分是您需要当前的 OpenGL 上下文才能进行 OpenGL 调用。并且 OpenGL 上下文是当前的 每个线程 。 GLSurfaceView
负责创建上下文,并使其在渲染线程中处于当前状态。
因此,您无法从其他线程进行任何 OpenGL 调用(除非您做更多工作并增加复杂性)。最常见的错误是尝试从 UI 线程进行 OpenGL 调用,通常是在处理触摸事件等用户输入时。这些电话将不起作用。
如果您想执行 OpenGL 调用以响应用户输入,有许多选项。例如,您可以在 Renderer
中设置描述必要状态更改的成员,并在 onDraw()
方法中进行检查。另一个方便的选择是在视图上使用 queueEvent()
方法,它允许您传入 Runnable
稍后将在渲染线程中执行。
我刚 运行 遇到了同样的问题。
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
}
});
}
我已经成功地加载纹理并自由旋转球体,这要归功于这里提出的几个教程、问题和答案,但我偶然发现需要在运行时重新加载纹理(获取位图图像,处理它然后应用它作为对象的新纹理)。我没有为我的特定问题找到任何有效的解决方案(我已经阅读了所有相关的问题和答案)。 我对 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 技术来渲染一个球体。对于每个条带,我必须加载纹理和顶点数据并最终绘制它。
我还有一个应该删除纹理的函数,除了:
public void clearGLTextures(){
GLES20.glDeleteTextures(1, mTextures, 0);
}
我想在这里实现的是重新加载纹理,所以计划是:
INITIALISE(有效):loadGLTexture(initialtexture)-> 循环 draw() 函数
重新加载(不起作用):clearGLTextures() -> loadGLTexture(newTexture) -> 循环 draw() 函数
因此,不仅我无法重新加载纹理,而且对 clearGLTextures() 的调用似乎也不起作用,因为初始纹理仍保留在屏幕上。
欢迎任何想法, 谢谢!
这是在 Android 上进行 OpenGL 编程时常见问题的一个示例。不幸的是,症状变化很大,所以问题并不是真的重复。
当您使用 GLSurfaceView
时,它会创建一个单独的渲染线程。 GLSurfaceView.Renderer
实现(onSurfaceCreated
、onSurfaceChanged
、onDrawFrame
)中的所有方法都在此渲染线程中调用。
难题的第二部分是您需要当前的 OpenGL 上下文才能进行 OpenGL 调用。并且 OpenGL 上下文是当前的 每个线程 。 GLSurfaceView
负责创建上下文,并使其在渲染线程中处于当前状态。
因此,您无法从其他线程进行任何 OpenGL 调用(除非您做更多工作并增加复杂性)。最常见的错误是尝试从 UI 线程进行 OpenGL 调用,通常是在处理触摸事件等用户输入时。这些电话将不起作用。
如果您想执行 OpenGL 调用以响应用户输入,有许多选项。例如,您可以在 Renderer
中设置描述必要状态更改的成员,并在 onDraw()
方法中进行检查。另一个方便的选择是在视图上使用 queueEvent()
方法,它允许您传入 Runnable
稍后将在渲染线程中执行。
我刚 运行 遇到了同样的问题。
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
}
});
}