告诉OpenGL三角形的正确纹理坐标

时间:2014-12-30 18:50:36

标签: android opengl-es

在我的第一个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吗?

2 个答案:

答案 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)

您可能希望加载:

  1. 创建一个包含每个v;
  2. 的数组
  3. 创建一个包含每个vt;
  4. 的数组
  5. 创建从(v, vt)到索引;
  6. 的哈希映射
  7. 对于f引用的每个顶点,请参考哈希映射索引:
    • 如果存在,请将该索引添加到您的订单缓冲区;
    • 以其他方式查找vvt的相应值,并将它们附加到vertexBuffertextureBuffer数组,存储您刚写入的位置的索引使用键(v, vt)和您的订单缓冲区的哈希映射。
  8. 鉴于你正在绘制一个立方体,你可能最终得到24个顶点 - 你的vertexBuffer数组将是24 * 3标量长而你的{{1数组将是24 * 2标量长。您的瞬态哈希映射最终将包含24个项目,映射到0到23之间的整数。

答案 1 :(得分:0)

我从obj文件加载对象的代码。最后,我将verticestexturesdrawings 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);
}