OpenGL ES 2.0纹理映射问题

时间:2015-04-12 23:12:10

标签: java textures opengl-es-2.0

我正在使用OpenGL ES 2.0并试图获得一个基本的纹理多维数据集.obj作为Blender模型导入测试的一部分进行渲染。

这是.obj:

# Blender v2.63 (sub 0) OBJ File: 'testCube.blend'
# www.blender.org
mtllib testCube.mtl
o Cube
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 1.000000 1.000000 1.000000
vt 0.250043 0.500000
vt 0.500000 0.500000
vt 0.499999 0.749957
vt 0.250043 0.749956
vt 0.000087 0.000087
vt 0.250043 0.000087
vt 0.250043 0.250043
vt 0.000087 0.250043
vt 0.500000 0.000087
vt 0.500000 0.250043
vt 0.749956 0.250043
vt 0.749956 0.000087
vt 0.499999 0.999913
vt 0.250042 0.999913
vn -1.000000 -0.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 1.000000 -0.000000 0.000000
vn 0.000000 0.000000 1.000000
vn -0.000000 -1.000000 0.000000
vn -0.000000 1.000000 0.000000
usemtl Material
s off
f 2/1/1 1/2/1 5/3/1
f 2/1/1 5/3/1 6/4/1
f 6/5/2 7/6/2 3/7/2
f 6/5/2 3/7/2 2/8/2
f 7/6/3 8/9/3 4/10/3
f 7/6/3 4/10/3 3/7/3
f 1/11/4 4/10/4 8/9/4
f 1/11/4 8/9/4 5/12/4
f 1/2/5 2/1/5 3/7/5
f 1/2/5 3/7/5 4/10/5
f 8/13/6 7/14/6 6/4/6
f 8/13/6 6/4/6 5/3/6

这是纹理: http://i1273.photobucket.com/albums/y409/Gamer_217/testcube_zpsf2hhxszq.png

这是渲染结果: http://i1273.photobucket.com/albums/y409/Gamer_217/TextureBug_zpsjpkb6egv.png

以下是来自同一java类的代码片段:

全局变量:

private int[] mTextureHandle;
private int mTextureUniformHandle;
private int mTextureCoordinateHandle;
private final int mTextureCoordinateDataSize = 2;
private float uv[];

从OBJ中读取UV贴图:

else if(type.compareTo("vt") == 0)
{
    uv[u]=Float.valueOf(line[1]);
    u++;
    uv[u]=1.0f-Float.valueOf(line[2]);
    u++;
}

纹理坐标缓冲区并加载BMP:

ByteBuffer tb = ByteBuffer.allocateDirect(uv.length*4);
tb.order(ByteOrder.nativeOrder());
texBuffer = tb.asFloatBuffer();
texBuffer.put(uv);
texBuffer.position(0);

mTextureHandle = new int[1];
GLES20.glGenTextures(1, mTextureHandle, 0);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
InputStream in = mgr.open("testcube.bmp");
Bitmap bitmap = BitmapFactory.decodeStream(in);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureHandle[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);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();

绘制功能:

GLES20.glEnable( GLES20.GL_DEPTH_TEST );
GLES20.glDepthFunc( GLES20.GL_LEQUAL );
GLES20.glDepthMask( true );
GLES20.glUseProgram(mProgram);
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);

mTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "uTexture");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "vTexCoordinate");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glUniform1i(mTextureUniformHandle, 0);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, texBuffer);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);

mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, face_v.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
GLES20.glDisableVertexAttribArray(mPositionHandle);

最后是着色器代码:

private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec2 vTexCoordinate;" +
"varying vec2 oTexCoordinate;" +
"void main() {" +
    "oTexCoordinate = vTexCoordinate;" +
    " gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"uniform sampler2D uTexture;" +
"varying vec2 oTexCoordinate;" +
"void main() {" +
    "  gl_FragColor = texture2D(uTexture, oTexCoordinate);" +
"}";

感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

.obj格式分别存储顶点数据,纹理坐标数据和法线,并为每个使用单独的索引。这意味着给定的顶点位置,纹理坐标或法线仅被写出一次,并且网格中的不同面可以共享顶点索引,即使它们具有不同的纹理坐标。

但是,OpenGLES在渲染网格时只使用单个索引缓冲区,因此您需要在顶点和纹理坐标中使用单独的条目,并为顶点位置,纹理坐标和组合的每个组合设置正常数组。正常。

现在看起来你正在将纹理坐标读入数组,然后将该数组作为浮点缓冲区原样传递给OpenGLES。问题是OpenGLES在任何时候都不知道纹理数组中与.obj文件中每个三角形相关联的索引。相反,OpenGLES将在查找纹理坐标时使用顶点索引。

因此,您的.obj文件中的面部数据如下所示:

f 2/1/1 1/2/1 5/3/1
f 2/1/1 5/3/1 6/4/1
f 6/5/2 7/6/2 3/7/2

将有效地呈现,好像它是这样的:

f 2/2/2 1/1/1 5/5/5
f 2/2/2 5/5/5 6/6/6
f 6/6/6 7/7/7 3/3/3

(忽略你还没有真正渲染法线的事实)

您需要一个额外的预处理步骤,在此步骤中识别目标文件中顶点/纹理坐标/法线的每个组合。然后为顶点,纹理坐标数据和法线生成单独的数组,每个组合有一个条目(这意味着一些顶点位置将重复多次,如果它们具有不同的纹理坐标关联)。对于给定的v / t / n组合,3个数组的索引应该匹配。然后根据这些新索引为三角形创建索引缓冲区。

另一种选择是根本不使用索引缓冲区。加载文件时,请将顶点数据等读入数组。然后根据三角形的数量分配一个更大的数组,并处理来自obj文件的索引,根据各种索引将相应的顶点/ tex coord / normal复制到数组中。然后,您将使用glDrawArrays代替glDrawElements

进行绘制