Android 来自 png 文件的 OpenGL ES 2.0 纹理是黑色的
Android OpenGL ES 2.0 textures from png file are black
我的 OpenGL 实现遇到了一个我不明白的问题。
我正在显示一个在 FragmentShader 中组合了三个纹理的 Sprite。如果我使用来自 android 资源的位图作为纹理,一切正常,但如果我使用下载的 png 等价物并从文件系统加载它们,我的纹理只显示黑色。
纹理不是 2 的幂,也不是正方形,但正如我所说,如果我将图像复制到 android 资源,则实现有效,但在现实世界中我需要下载它们。
这是我的代码:
精灵构造函数:
final float[] spriteTextureCoordinates =
{
1f, 0f,
1f, 1f,
0f, 1f,
0f, 0f
};
mCubeTextureCoordinates = ByteBuffer.allocateDirect(spriteTextureCoordinates.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mCubeTextureCoordinates.put(spriteTextureCoordinates).position(0);
ByteBuffer dlb = ByteBuffer.allocateDirect(spriteCoords.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
shaderProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(shaderProgram, vertexShader);
GLES20.glAttachShader(shaderProgram, fragmentShader);
GLES20.glBindAttribLocation(shaderProgram, 0, "a_TexCoordinate");
GLES20.glLinkProgram(shaderProgram);
mTextureManager.loadDefaultTextures(mActivityContext, true);
开画:
GLES20.glUseProgram(shaderProgram);
mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
mTextureUniformHandle0 = GLES20.glGetUniformLocation(shaderProgram, "u_Texture0");
mTextureUniformHandle1 = GLES20.glGetUniformLocation(shaderProgram, "u_Texture1");
mTextureUniformHandle2 = GLES20.glGetUniformLocation(shaderProgram, "u_Texture2");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(shaderProgram, "a_TexCoordinate");
GLES20.glUniform1i(mTextureUniformHandle0, 0);
GLES20.glUniform1i(mTextureUniformHandle1, 2);
GLES20.glUniform1i(mTextureUniformHandle2, 4);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureManager.getMapLayerTexture());
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + 2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureManager.getRadarTexture(currentImageIndex));
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + 4);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureManager.getGeoLayerTextureForZoomLevel(zoomStep));
mCubeTextureCoordinates.position(0);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, mCubeTextureCoordinates);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix");
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
GLES20.glDisableVertexAttribArray(mPositionHandle);
着色器:
private final String vertexShaderCode =
"attribute vec2 a_TexCoordinate;" +
"varying vec2 v_TexCoordinate;" +
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"v_TexCoordinate = a_TexCoordinate;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform sampler2D u_Texture0;" +
"uniform sampler2D u_Texture1;" +
"uniform sampler2D u_Texture2;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
"vec4 texel0 = texture2D(u_Texture0, v_TexCoordinate);" +
"vec4 texel1 = texture2D(u_Texture1, v_TexCoordinate);" +
"vec4 texel2 = texture2D(u_Texture2, v_TexCoordinate);" +
"gl_FragColor = mix(mix(texel0, texel1, texel1.a),texel2,texel2.a);"+
"}";
工作纹理加载:
public int[] loadTextures(final Context context, int... resIDs)
{
final int[] textureHandle = new int[resIDs.length];
GLES20.glGenTextures(resIDs.length, textureHandle, 0);
for(int i=0; i<textureHandle.length; i++){
if (textureHandle[i] != 0)
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resIDs[i], options);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[i]);
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 (textureHandle[i] == 0)
{
throw new RuntimeException("Error loading texture.");
}
}
return textureHandle;
}
一个不工作的:
public synchronized int loadNewRadarLayerTexture(Context context, ImageData data) throws IOException {
int textureID = data.getTextureID();
if(textureID == 0) {
final int[] textureHandle = new int[1];
GLES20.glGenTextures(textureHandle.length, textureHandle, 0);
textureID = textureHandle[0];
if (textureID != 0) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
File directory = context.getDir(RRD.DIR,
Context.MODE_PRIVATE);
File image = new File(directory, data.getFile());
Bitmap bitmap = BitmapFactory.decodeFile(image.getPath(),options);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
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);
Log.d("OpenGL","Error:"+GLES20.glGetError());
bitmap.recycle();
}
if(textureID == 0){
throw new RuntimeException("Error loading texture.");
}
data.setTextureID(textureID);
}
return textureID;
}
如果我使用第一种方法生成的纹理,一切正常。如果我使用第二种方法,我的整个纹理似乎都是黑色的
阅读本主题时发现错误:Threading textures load process for android opengl game
下载完成后我正在加载纹理。我在正确的线程中,但不是在 onSurfaceChanged 或 onDrawFrame 方法期间,原因是纹理未正确上传。
第一个解决方案是在加载纹理时检查 onDrawFrame,如果没有加载则加载纹理。
我的 OpenGL 实现遇到了一个我不明白的问题。 我正在显示一个在 FragmentShader 中组合了三个纹理的 Sprite。如果我使用来自 android 资源的位图作为纹理,一切正常,但如果我使用下载的 png 等价物并从文件系统加载它们,我的纹理只显示黑色。
纹理不是 2 的幂,也不是正方形,但正如我所说,如果我将图像复制到 android 资源,则实现有效,但在现实世界中我需要下载它们。
这是我的代码: 精灵构造函数:
final float[] spriteTextureCoordinates =
{
1f, 0f,
1f, 1f,
0f, 1f,
0f, 0f
};
mCubeTextureCoordinates = ByteBuffer.allocateDirect(spriteTextureCoordinates.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mCubeTextureCoordinates.put(spriteTextureCoordinates).position(0);
ByteBuffer dlb = ByteBuffer.allocateDirect(spriteCoords.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
shaderProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(shaderProgram, vertexShader);
GLES20.glAttachShader(shaderProgram, fragmentShader);
GLES20.glBindAttribLocation(shaderProgram, 0, "a_TexCoordinate");
GLES20.glLinkProgram(shaderProgram);
mTextureManager.loadDefaultTextures(mActivityContext, true);
开画:
GLES20.glUseProgram(shaderProgram);
mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
mTextureUniformHandle0 = GLES20.glGetUniformLocation(shaderProgram, "u_Texture0");
mTextureUniformHandle1 = GLES20.glGetUniformLocation(shaderProgram, "u_Texture1");
mTextureUniformHandle2 = GLES20.glGetUniformLocation(shaderProgram, "u_Texture2");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(shaderProgram, "a_TexCoordinate");
GLES20.glUniform1i(mTextureUniformHandle0, 0);
GLES20.glUniform1i(mTextureUniformHandle1, 2);
GLES20.glUniform1i(mTextureUniformHandle2, 4);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureManager.getMapLayerTexture());
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + 2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureManager.getRadarTexture(currentImageIndex));
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + 4);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureManager.getGeoLayerTextureForZoomLevel(zoomStep));
mCubeTextureCoordinates.position(0);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, mCubeTextureCoordinates);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix");
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
GLES20.glDisableVertexAttribArray(mPositionHandle);
着色器:
private final String vertexShaderCode =
"attribute vec2 a_TexCoordinate;" +
"varying vec2 v_TexCoordinate;" +
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"v_TexCoordinate = a_TexCoordinate;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform sampler2D u_Texture0;" +
"uniform sampler2D u_Texture1;" +
"uniform sampler2D u_Texture2;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
"vec4 texel0 = texture2D(u_Texture0, v_TexCoordinate);" +
"vec4 texel1 = texture2D(u_Texture1, v_TexCoordinate);" +
"vec4 texel2 = texture2D(u_Texture2, v_TexCoordinate);" +
"gl_FragColor = mix(mix(texel0, texel1, texel1.a),texel2,texel2.a);"+
"}";
工作纹理加载:
public int[] loadTextures(final Context context, int... resIDs)
{
final int[] textureHandle = new int[resIDs.length];
GLES20.glGenTextures(resIDs.length, textureHandle, 0);
for(int i=0; i<textureHandle.length; i++){
if (textureHandle[i] != 0)
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resIDs[i], options);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[i]);
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 (textureHandle[i] == 0)
{
throw new RuntimeException("Error loading texture.");
}
}
return textureHandle;
}
一个不工作的:
public synchronized int loadNewRadarLayerTexture(Context context, ImageData data) throws IOException {
int textureID = data.getTextureID();
if(textureID == 0) {
final int[] textureHandle = new int[1];
GLES20.glGenTextures(textureHandle.length, textureHandle, 0);
textureID = textureHandle[0];
if (textureID != 0) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
File directory = context.getDir(RRD.DIR,
Context.MODE_PRIVATE);
File image = new File(directory, data.getFile());
Bitmap bitmap = BitmapFactory.decodeFile(image.getPath(),options);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
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);
Log.d("OpenGL","Error:"+GLES20.glGetError());
bitmap.recycle();
}
if(textureID == 0){
throw new RuntimeException("Error loading texture.");
}
data.setTextureID(textureID);
}
return textureID;
}
如果我使用第一种方法生成的纹理,一切正常。如果我使用第二种方法,我的整个纹理似乎都是黑色的
阅读本主题时发现错误:Threading textures load process for android opengl game 下载完成后我正在加载纹理。我在正确的线程中,但不是在 onSurfaceChanged 或 onDrawFrame 方法期间,原因是纹理未正确上传。
第一个解决方案是在加载纹理时检查 onDrawFrame,如果没有加载则加载纹理。