我已经设法加载纹理并自由旋转球体,这要归功于这里提到的几个教程,问题和答案,但我偶然发现在运行时需要纹理重新加载(获取位图图像,处理它然后将其应用为对象的新纹理)。我没有为我的具体问题找到任何可行的解决方案(我已经阅读了所有相关的问题和答案)。 我是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中。
欢迎任何想法, 谢谢!
答案 0 :(得分:3)
这是在Android上进行OpenGL编程时常见问题的一个例子。不幸的是,症状变化很大,所以问题并不是真的重复。
使用GLSurfaceView
时,它会创建一个单独的渲染线程。您的GLSurfaceView.Renderer
实施中的所有方法(onSurfaceCreated
,onSurfaceChanged
,onDrawFrame
)都会在此渲染广告系列中调用。
难题的第二部分是你需要一个当前的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
}
});
}