OpenGL ES 2.0 - 纹理总是黑色
Posted
技术标签:
【中文标题】OpenGL ES 2.0 - 纹理总是黑色【英文标题】:OpenGL ES 2.0 - Textures always black 【发布时间】:2014-04-10 15:07:52 【问题描述】:我今天阅读了很多关于 Open GL ES 2.0 中纹理的内容。我的问题是,它们都是黑色的。
我的代码:
从位图生成纹理:
private void generateTexture(Bitmap bmp)
final int[] textureHandle = new int[1];
Log.d(TAG, "Generating texture handle");
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0)
Log.d(TAG, "binding texture to " + textureHandle[0]);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
Log.d(TAG, "GLError@bindTex=" + GLES20.glGetError());
// 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);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
Log.d(TAG, "Loading bitmap into texture");
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
Log.d(TAG, "GLError@texImg2D=" + GLES20.glGetError());
Log.d(TAG, "Recycle bitmap");
// Recycle the bitmap, since its data has been loaded into OpenGL.
bmp.recycle();
我的 logcat 中没有错误,一切似乎都像它应该的那样。
我如何使用纹理:
if (mShader instanceof Texture2DShader && mTextureBuffer != null)
// activate texture
Log.d(TAG, "Passing texture stuff");
mTextureBuffer.position(0);
Log.d(TAG, "Activate Texture");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
Log.d(TAG, "Binding texture -> " + mTexture.getHandle());
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture.getHandle());
if (mShader.getGLLocation(BaseShader.U_TEXTURE) != -1)
Log.d(TAG, "Passing u_Texture");
GLES20.glUniform1i(mShader.getGLLocation(BaseShader.U_TEXTURE), 0);
if (mShader.getGLLocation(BaseShader.A_TEXCOORDINATE) != -1)
Log.d(TAG, "Passing a_TexCoordinate");
GLES20.glVertexAttribPointer(mShader.getGLLocation(BaseShader.A_TEXCOORDINATE), 2, GLES20.GL_FLOAT, false, 0, mTextureBuffer);
GLES20.glEnableVertexAttribArray(mShader.getGLLocation(BaseShader.A_TEXCOORDINATE));
Log.d(TAG, "Texture stuff passed.");
Log.d(TAG, "Error = " + GLES20.glGetError());
Logcat 是这样说的:
D/TextureCube﹕ Activate Texture
D/TextureCube﹕ Binding texture -> 3
D/TextureCube﹕ Passing u_Texture
D/TextureCube﹕ Passing a_TexCoordinate
D/TextureCube﹕ Texture stuff passed.
D/TextureCube﹕ Error = 0
所以没有错误,似乎工作正常?
我的着色器:
片段着色器:
precision mediump float; // Set the default precision to medium. We don't need as high of a
// precision in the fragment shader.
uniform vec3 u_LightPos; // The position of the light in eye space.
uniform vec4 u_Light;
uniform vec4 u_Ambient;
uniform vec3 u_LightDirection;
uniform vec3 u_CameraPos;
uniform sampler2D u_Texture;
//varying vec4 v_Ambient; // Ambient light factor!
varying vec2 v_TexCoordinate;
varying vec3 v_Position; // Interpolated position for this fragment.
varying vec4 v_Color; // This is the color from the vertex shader interpolated across the triangle per fragment.
varying vec3 v_Normal; // Interpolated normal for this fragment.
//varying vec3 v_CameraPosition;
// The entry point for our fragment shader.
void main()
// Will be used for attenuation.
float distance = length(u_LightPos - v_Position);
// Get a lighting direction vector from the light to the vertex.
vec3 lightVector = normalize(u_LightPos - v_Position);
// Calculate the dot product of the light vector and vertex normal. If the normal and light vector are
// pointing in the same direction then it will get max illumination.
float diffuse = max(dot(v_Normal, lightVector), 0.1);
// Add attenuation. (used to be 0.25)
diffuse = diffuse * (1.0 / (1.0 + (0.25 * distance * distance)));
// calculate specular light!
//vec3 lightDirection = -u_LightDirection;
//vec3 vertexToEye = normalize(u_CameraPos - v_CameraPos);
//vec3 lightReflect = normalize(reflect(u_LightDirection, v_Normal));
//float specularFactor = dot(vertexToEye, lightReflect);
// Multiply the color by the diffuse illumination level to get final output color.
//
gl_FragColor = v_Color * (u_Ambient + (diffuse * u_Light) * texture2D(u_Texture, v_TexCoordinate));
顶点着色器:
uniform mat4 u_MVPMatrix; // A constant representing the combined model/view/projection matrix.
uniform mat4 u_MVMatrix; // A constant representing the combined model/view matrix.
attribute vec4 a_Position; // Per-vertex position information we will pass in.
attribute vec4 a_Color; // Per-vertex color information we will pass in.
attribute vec3 a_Normal; // Per-vertex normal information we will pass in.
attribute vec2 a_TexCoordinate;
varying vec2 v_TexCoordinate;
varying vec3 v_Position; // This will be passed into the fragment shader.
varying vec4 v_Color; // This will be passed into the fragment shader.
varying vec3 v_Normal; // This will be passed into the fragment shader.
//varying vec3 v_CameraPosition;
//varying vec4 v_Ambient; // Pass the ambient color to the fragment shader.
// The entry point for our vertex shader.
void main()
// Transform the vertex into eye space.
v_Position = vec3(u_MVMatrix * a_Position);
v_TexCoordinate = a_TexCoordinate;
// Pass through the color.
v_Color = a_Color;
// Transform the normal's orientation into eye space.
v_Normal = vec3(u_MVMatrix * vec4(a_Normal, 0.0));
//v_CameraPos = vec3(u_MVMatrix * vec4(u_CameraPos, 0.0));
// v_CameraPosition = u_CameraPos;
// gl_Position is a special variable used to store the final position.
// Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
gl_Position = u_MVPMatrix * a_Position;
似乎texture2D 在片段着色器中返回一个零向量,因为如果我简单地写gl_FragColor = vec4(0.5,0.5,0.5,1.0) + texture2D(..)
,它就会被绘制出来。
我已经在 SO 以及其他网站上查看了无数问题,我知道这个确切的问题已被问过几次,但无论我尝试了什么 - 它都没有帮助。
我已经将纹理缩小到 512x512,然后是 256x256,甚至更低到 64x64,但没有任何变化。我已经打印了我的纹理处理程序,检查了 GL 错误等,但什么也没有。
编辑:
起初我一直在尝试从 R.raw 加载纹理,然后将其移至 R.drawable,但没有任何变化。
编辑 2:立方体顶点/法线/纹理/颜色声明:
private final float[] mCubePosition =
// Front face
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
// Right face
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
// Back face
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
// Left face
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
// Top face
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
// Bottom face
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
;
// R, G, B, A
private final float[] mCubeColors =
// Front face (red)
1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
// Right face (green)
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
// Back face (blue)
0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
// Left face (yellow)
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
// Top face (cyan)
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
// Bottom face (magenta)
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f
;
private final float[] mCubeNormals =
// Front face
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
// Right face
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
// Back face
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
// Left face
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
// Top face
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
// Bottom face
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f
;
private final float[] mCubeTexture =
// Front face
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
// Right face
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
// Back face
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
// Left face
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
// Top face
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
// Bottom face
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f
;
编辑 3:将纹理坐标作为颜色来查看它们是否正在传输:
片段着色器中的gl_FragColor = vec4(v_TexCoordinate.x, v_TexCoordinate.y, 0, 1);
导致:
【问题讨论】:
这里有很多东西可能会出错。我看到你已经检查了一些,但你仍然应该尝试找出问题所在。尝试绘制一个简单的带纹理的矩形,占据屏幕的一部分。如果绘制,请检查颜色。检查纹理坐标是否正确(在片段着色器中使用 X,Y 表示红色和绿色,您应该会看到一个漂亮的幽灵)。如果这一切都成功,那么您的问题一定是在加载、传递纹理或纹理参数中。 您好,感谢您的回复。我已经看到正在绘制我正在绘制的立方体,因为它后面还有其他非纹理元素,表示黑色立方体。我将检查片段着色器中的纹理坐标,但打印我传递的缓冲区会产生正确的缓冲区,我会将浮点数组编辑到问题中。 所以看起来你在着色器中收到的纹理数据确实是黑色或空的。从位图加载后,您能否检查纹理参数。如果可能,检查宽度、高度和内部格式。甚至一些像素数据也可能很好。如果这些检查出来,则只能将纹理连接到着色器。还有mTexture和textureHandle之间的关系是什么。生成纹理的代码似乎与设置纹理 ID 的任何对象无关,您也没有从应用程序的该部分发布任何日志输出。 我想我找到了问题所在。与往常一样,我的线程混淆了 OpenGL。所以我正在做的是:在线程中加载位图,然后在surfaceView上发布一个应该生成和绑定OpenGL纹理的runnable。但显然这不起作用,因为如果我在“TextureCube”示例类中使用相同的代码创建纹理,它就会起作用。有什么方法可以在 OpenGL 线程上执行方法吗? 由于您已经在单独的线程上完成了所有纹理加载,您需要做的就是在该线程上设置一个新的上下文,但它需要与您的主上下文共享。因此,在创建主上下文之前尝试生成一个共享组并将共享组设置为一些静态参数。然后在生成所有上下文时使用该共享组,每个线程应该有自己的上下文。也可以尝试只加载一个后台线程(如果还没有的话),否则您可能会遇到一些清理问题。 【参考方案1】:这是一个非常常见的问题,那么您不能使用 2 个纹理的幂(像素级)。
为了不再重复已经提供的相同解决方案,请查看我之前对此事的回复。
android OpenGL2.0 showing black textures
希望这能解决您的问题。
干杯 毛里齐奥
【讨论】:
我现在所说的正是你的意思,因为我之前已经阅读过你对这个问题的回答——但它并没有改变我的情况。另外,我已经提到我已经将纹理重新缩放为 2 大小。所以不幸的是,这不是我的问题的解决方案。【参考方案2】:好的,我找到了解决方案。我再次对 OpenGL 线程的工作方式感到困惑。我在线程中加载位图,然后使用glView.post();
将 Runnable 发布回(我认为的)OpenGL 线程,纹理应该在该线程中生成并绑定到位图。
这不起作用。我应该做的是:
GLSurfaceView glView = ...;
glView.queueEvent(new Runnable()
@Override
public void run()
generateTexture(bitmap);
);
在 generateTexture 中,我执行所有 GLES20.generateTexture
等内容,因为有了 queueEvent,它又在真正的 OpenGL 线程上,而不是在 UI 线程上。
显然,我使用纹理的代码是正确的。感谢您的帮助。
【讨论】:
以上是关于OpenGL ES 2.0 - 纹理总是黑色的主要内容,如果未能解决你的问题,请参考以下文章
OPENGL ES 2.0 知识串讲 (10) ——OPENGL ES 详解IV(纹理优化)
OPENGL ES 2.0 知识串讲 (10) ——OPENGL ES 详解IV(纹理优化)
OPENGL ES 2.0 知识串讲 ——OPENGL ES 详解III(纹理)