在 OpenGL ES 2 中切换纹理
Posted
技术标签:
【中文标题】在 OpenGL ES 2 中切换纹理【英文标题】:Switching between textures in OpenGL ES 2 【发布时间】:2012-10-13 20:30:06 【问题描述】:我试图弄清楚如何将不同的纹理放入不同的纹理单元并选择要绘制的纹理。我的onDrawFrame()
方法中有以下代码
int[] texture = new int[7];
texture[0] =TextureHelper.loadTexture(mActivityContext,R.drawable.texture1);
texture[1] =TextureHelper.loadTexture(mActivityContext,R.drawable.texture2);
texture[2] =TextureHelper.loadTexture(mActivityContext,R.drawable.texture3);
texture[3] =TextureHelper.loadTexture(mActivityContext,R.drawable.texture4);
texture[4] =TextureHelper.loadTexture(mActivityContext,R.drawable.texture5);
texture[5] =TextureHelper.loadTexture(mActivityContext,R.drawable.texture6);
texture[6] =TextureHelper.loadTexture(mActivityContext,R.drawable.texture7);
for (int i = 0; i < 7; i ++)
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[i]);
GLES20.glUniform1i(mTextureUniformHandle, i);
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, -0.60f + 0.2f * i, 0.0f, 0.0f);
draw();
这应该做的是将七种不同的纹理加载到单独的纹理单元中并绘制立方体,每个立方体都有不同的纹理。然而,最终发生的事情是所有立方体最终都使用第一个纹理绘制。
如果我将GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i)
更改为GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
并将GLES20.glUniform1i(mTextureUniformHandle, i)
更改为GLES20.glUniform1i(mTextureUniformHandle, 0)
,它可以正常工作,但这只是使用单个纹理单元并每次都替换该单元中的纹理,这不是我想要的做。
我做错了什么? 提前致谢。
编辑:
顶点着色器:
"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 vec2 a_TexCoordinate;" + // Per-vertex texture
// coordinate information we
// will pass in.
"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 vec2 v_TexCoordinate;" + // This will be passed into
// 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);" +
// Pass through the color.
"v_Color = a_Color;" +
// Pass through the texture coordinate.
"v_TexCoordinate = a_TexCoordinate;" +
// 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;" + " ";
片段着色器:
"precision mediump float;" + // Set the default precision to medium. We don't need as high of a
// precision in the fragment shader.
"uniform sampler2D u_Texture;" + // The input texture.
"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 vec2 v_TexCoordinate;" + // Interpolated texture coordinate per fragment.
// The entry point for our fragment shader.
"void main()" +
"" +
// Multiply the color by the diffuse illumination level and texture value to get final output color.
"gl_FragColor = (v_Color * texture2D(u_Texture, v_TexCoordinate));" +
"";
draw() 方法:
public void draw()
// Pass in the position information
mCubePositions.position(0);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, 0, mCubePositions);
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Pass in the color information
mCubeColors.position(0);
GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false, 0, mCubeColors);
GLES20.glEnableVertexAttribArray(mColorHandle);
// Pass in the texture coordinate information
mCubeTextureCoordinates.position(0);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, mCubeTextureCoordinates);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
// This multiplies the view matrix by the model matrix, and stores the
// result in the MVP matrix
// (which currently contains model * view).
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
// Pass in the modelview matrix.
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);
// This multiplies the modelview matrix by the projection matrix, and
// stores the result in the MVP matrix
// (which now contains model * view * projection).
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
// Pass in the combined matrix.
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Draw the cube.
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
分配 mTextureUniformHandle :
mTextureUniformHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_Texture");
【问题讨论】:
该代码在我看来是正确的。你能确保你没有任何带有 glGetError 的 GL 错误吗?我唯一能想到的是 mTextureUniformHandle 没有正确链接。是否有有效的统一 ID? glGetError(),在 for 循环结束时调用,返回 0。如何检查统一 ID? 如果误差为零,我猜你的制服没问题。当我说要检查 ID 时,我的意思是 mTextureUniformHandle 的值是多少。也许发布你的着色器只是为了确定? 另外请添加绘图功能。 我已经发布了着色器、draw() 和 mTextureUniformHandle 的值。 【参考方案1】:最近我一直在片段着色器中搜索多个纹理,并遇到了这个Binding textures to samplers
从中我得到了以下工作:
在onSurfaceCreated
或onSurfaceChanged
:
normalMapLoc = GLES20.glGetUniformLocation(shaderProgram, "normalMap");
shadowMapLoc = GLES20.glGetUniformLocation(shaderProgram, "shadowMap");
GLES20.glGenTextures(2, textures, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[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();
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GL10.GL_TEXTURE_COORD_ARRAY, textures[1]);
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.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mColorBuffer);
GLES20.glUniform1i(normalMapLoc, 0); // Texture unit 0 is for normal images.
GLES20.glUniform1i(shadowMapLoc, 1); // Texture unit 1 is for shadow maps.
在onDrawFrame
:
GLES20.glClearColor(0f, 0f, 0f, 0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// pass variables to the fragment shader
...
// get handle to vertex shader's Position member, etcetera
int mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, mVertexBuffer);
GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, 4, GLES20.GL_UNSIGNED_SHORT, mIndexBuffer);
最后片段着色器看起来像这样(仅相关的代码部分):
uniform sampler2D normalMap, shadowMap;
varying vec2 pos;
void main()
vec4 color = texture2D(normalMap, pos);
vec4 shadow = texture2D(shadowMap, pos);
// do stuff with the colors
...
gl_FragColor = ...;
这样我终于可以访问两种纹理了!
希望这会有所帮助。
【讨论】:
以上是关于在 OpenGL ES 2 中切换纹理的主要内容,如果未能解决你的问题,请参考以下文章
OPENGL ES 2.0 知识串讲 (10) ——OPENGL ES 详解IV(纹理优化)
OPENGL ES 2.0 知识串讲 (10) ——OPENGL ES 详解IV(纹理优化)
OPENGL ES 2.0 知识串讲 ——OPENGL ES 详解III(纹理)