在我的第一个Android OpenGL应用程序中,我想渲染一个带有纹理的简单立方体到屏幕上。我从一个obj文件中加载我的对象,如果我用一种颜色渲染它,它的效果很好但是有一个纹理我有一些问题。我已经对我的代码进行了调查并查看了所有数组,并发现所有数据都可以从文件中读取。这是我的obj文件:
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 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt -1.918677 2.918677
vt -1.918677 -1.918677
vt 2.918677 -1.918677
vt 2.918677 2.918677
f 2/1 3/2 4/3
f 8/1 7/2 6/3
f 1/4 5/1 6/2
f 2/4 6/1 7/2
f 7/1 8/2 4/3
f 1/1 4/2 8/3
f 1/4 2/1 4/3
f 5/4 8/1 6/3
f 2/3 1/4 6/2
f 3/3 2/4 7/2
f 3/4 7/1 4/3
f 5/4 1/1 8/3
要在屏幕上绘制对象,我有这些数组(后来称为Buffer)和这些OpenGL方法:
float vertices[] = {1f, -1f, -1f, 1f, ... , -1f, 1f, -1f };
short order[] = { 1, 2, 3, 7, ... , 4, 0, 7 }; // f o/t | o - 1
float textures[] = { -1.918677, 2.918677, ... , 2.918677 2.918677 };
Matrix.multiplyMM(mvpMatrix, 0, vpMatrix, 0, modelMatrix, 0);
GLES20.glUniformMatrix4fv(shaderMatrix, 1, false, mvpMatrix, 0);
GLES20.glEnableVertexAttribArray(shaderPosition);
GLES20.glVertexAttribPointer(shaderPosition, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
GLES20.glEnableVertexAttribArray(shaderTexCoordinate);
GLES20.glVertexAttribPointer(shaderTexCoordinate, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, orderBuffer.capacity(), GLES20.GL_UNSIGNED_SHORT, orderBuffer);
GLES20.glDisableVertexAttribArray(shaderPosition);
但这不起作用 - 纹理显示不正确。我有一个假设,即OpenGL不知道它必须用巫婆纹理坐标绘制哪个三角形。那我怎么能告诉这个OpenGL呢?我是否必须为具有相同顶点大小的纹理坐标创建一个数组/缓冲区,以便OpenGL使用第一个顶点来渲染三角形,并使用前三个纹理来表示此三角形?或者我该怎么做?
总之:我可以设置类似于drawOrder funktion但是对于textureCoordinates吗?
答案 0 :(得分:1)
OpenGL将单个顶点视为描述该顶点的每个属性的组合。因此,在您的情况下,由位置和纹理坐标组成的单个单元是顶点。他们是第五维。
像:
这样的一行f 2/1 3/2 4/3
描述具有三个顶点的三角形。顶点有坐标:
(1.000000 -1.000000 1.000000, -1.918677 2.918677)
(-1.000000 -1.000000 1.000000, -1.918677 -1.918677)
(-1.000000 -1.000000 -1.000000, 2.918677 -1.918677)
您可能希望加载:
v
; vt
; (v, vt)
到索引; f
引用的每个顶点,请参考哈希映射索引:
v
和vt
的相应值,并将它们附加到vertexBuffer
和textureBuffer
数组,存储您刚写入的位置的索引使用键(v, vt)
和您的订单缓冲区的哈希映射。鉴于你正在绘制一个立方体,你可能最终得到24个顶点 - 你的vertexBuffer
数组将是24 * 3标量长而你的{{1数组将是24 * 2标量长。您的瞬态哈希映射最终将包含24个项目,映射到0到23之间的整数。
答案 1 :(得分:0)
我从obj文件加载对象的代码。最后,我将vertices
,textures
和drawings
ArrayLists转换为数组,然后转换为Buffer。
编辑:对于所有人来说,如何寻找一个obj Loader。这段代码效果很好。请务必启用depth buffer
。那是我的问题。否则,三角形在另一个之前绘制,它看起来不像立方体。感谢大家对这段代码的帮助。
while((line = bufferedReader.readLine()) != null)
{
lineCounter += 1; line.trim();
if(line.length() <= 1) continue;
StringTokenizer tok = new StringTokenizer(line, " ");
String cmp = tok.nextToken();
if(cmp.equals("v"))
{ // Read out the vertices
all_vertices.add( Float.valueOf(tok.nextToken()) );
all_vertices.add( Float.valueOf(tok.nextToken()) );
all_vertices.add( Float.valueOf(tok.nextToken()) );
}
else if(cmp.equals("vt"))
{ // Read out the texture
all_textures.add( Float.valueOf(tok.nextToken()) );
all_textures.add( Float.valueOf(tok.nextToken()) );
}
else if(cmp.equals("f") || cmp.equals("fo"))
{
while(tok.hasMoreTokens())
{
String indices = tok.nextToken().trim();
String[] variables = indices.split("/");
if(map.containsKey(indices)) drawings.add(map.get(indices));
else
{
short vertexIndex = (short) (vertices.size() / 3);
map.put(indices, vertexIndex); drawings.add(vertexIndex);
Log.d("ME", indices + "|" + vertexIndex);
int verNumber = Integer.valueOf(variables[0]) - 1;
vertices.add(all_vertices.get(3 * verNumber + 0));
vertices.add(all_vertices.get(3 * verNumber + 1));
vertices.add(all_vertices.get(3 * verNumber + 2));
int texNumber = Integer.valueOf(variables[1]) - 1;
textures.add(all_textures.get(2 * texNumber + 0));
textures.add(all_textures.get(2 * texNumber + 1));
}
}
}
}
在这里,您还有一小段代码可以将ArrayLists
转换为数组,然后将这些数组放入特定的Buffer中。它非常高效,并且处于复杂性n
中。玩得开心:
float vertices[] = new float[vert.size()];
short drawings[] = new short[draw.size()];
float textures[] = new float[texs.size()];
int maxVD = Math.max(vert.size(), draw.size());
int maxVNT = Math.max(maxVD, texs.size());
Log.d("ME", "" + maxVNT);
for(int i=0; i < maxVNT; i++)
{
int vi = Math.min(i, vertices.length - 1);
vertices[vi] = vert.get(vi);
int di = Math.min(i, drawings.length - 1);
drawings[di] = draw.get(di);
int ti = Math.min(i, textures.length - 1);
textures[ti] = texs.get(ti);
}