如何在Android中加载3d对象?

Abh*_*hah 5 android opengl-es

我有.obj文件和.mtl文件,但不知道如何导入它.我试过这些教程,但它们都没有用.

Hen*_*rik 8

从.obj文件加载Object的一种方法是首先从文件中获取输入流,然后遍历每一行,因为一行包含一个顶点.然后,您可以使用.obj文件中的数据来实际绘制它的部分,您可以轻松地在线找到一堆教程,例如:http://www.droidnova.com/android-3d-game- tutorial-part-i,312.html.如果你想深入了解Opengl并且实际上学到很多东西,你可以使用Nehe全能的在线教程,该教程非常涵盖OpenGL编程:http://nehe.gamedev.net/.

无论如何,.obj文件加载可以通过以下方式开始:

        while ((line = reader.readLine()) != null)
    {
        if (line.startsWith("f"))
        {
            faces++;
            processFLine(line);
        } else if (line.startsWith("vn"))
        {
            normals++;
            processVNLine(line);
        } else if (line.startsWith("vt"))
        {
            UVCoords++;
            processVTLine(line);
        } else if (line.startsWith("v"))
        {
            vertices++;
            processVLine(line);
        }
    }
Run Code Online (Sandbox Code Playgroud)

对于除了以'f'开头的行之外的所有内容,它都非常简单,你只需将两个或三个值存储在某个东西中,我更喜欢Vector:

    private void processVNLine(String line)
{
    String[] tokens = line.split("[ ]+");
    int c = tokens.length;
    for (int i = 1; i < c; i++)
    { // add the normals to the normal vector
        _vn.add(Float.valueOf(tokens[i]));
    }
}
Run Code Online (Sandbox Code Playgroud)

对于faces部分(以'f'开头的行,您最好先检查每个顶点包含的'/'数:

    private void processFLine(String line)
{
    String[] tokens = line.split("[ ]+");
    int c = tokens.length;

    if (tokens[1].matches("[0-9]+"))
    {
        caseFEqOne(tokens, c);
    }
    if (tokens[1].matches("[0-9]+/[0-9]+"))
    {
        caseFEqTwo(tokens, c);
    }
    if (tokens[1].matches("[0-9]+//[0-9]+"))
    {
        caseFEqOneAndThree(tokens, c);
    }
    if (tokens[1].matches("[0-9]+/[0-9]+/[0-9]+"))
    {
        caseFEqThree(tokens, c);
    }
}  
Run Code Online (Sandbox Code Playgroud)

每个面由三个顶点构成,每个顶点索引为v/vt/vn.

如果你有v/vt,就会发生这种情况.它将索引存储在单独的向量中.

    private void caseFEqTwo(String[] tokens, int c)
{
    for (int i = 1; i < c; i++)
    {
        Short s = Short.valueOf(tokens[i].split("/")[0]);
        s--;
        _vPointer.add(s);

        s = Short.valueOf(tokens[i].split("/")[1]);
        s--;
        _vtPointer.add(s);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您已通过将索引添加到sperarate Vectors或数组中来处理此问题.

现在你应该有包含坐标和向量的向量,这些向量由每种类型(v,vt或vn)的索引组成.你应该有面数.通过知道面数,您现在可以开始一个从0到面数的循环.

如果现在创建包含最终结果的新向量,则可以在此循环中将索引处的坐标从循环索引移动到结果向量中的循环索引.

这可能需要一些explenation也许所以这是一个简单的例子:

private void reArrange()
{
    Iterator<Short> i;
    short s;

    i = _vPointer.iterator();
    while (i.hasNext())
    {
        s = (short) (i.next() * 3);
        for (int k = 0; k < 3; k++)
        {
            _vResult.add(_v.get(s + k));
        }
    }

    i = _vnPointer.iterator();
    while (i.hasNext())
    {
        s = (short) (i.next() * 3);
        for (int k = 0; k < 3; k++)
        {
            _vnResult.add(_vn.get(s + k));
        }
    }

    i = _vtPointer.iterator();
    while (i.hasNext())
    {
        s = (short) (i.next() * 2);
        for (int k = 0; k < 2; k++)
        {
            _vtResult.add(1f - _vt.get(s + k));
        }
    }

    _indices = new short[faces * 3];
    for (short k = 0; k < faces * 3; k++)
    {
        _indices[k] = k;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你的主动完成并从.obj文件中获取所需的信息.因此,通过将thoose向量转换为FloatBuffers并创建一个简单的0,3,2,3,4,5等ShortBuffer,您可以使用OpenGL-ES来绘制您的对象.

(这不是由我完整写​​的,我使用了一个基本的概念,我在网上找到了,现在找不到,然后让它很好地适应我想要的东西并调整它以便更容易理解)

这不包括你加载.mtl文件的部分,你通常也会从程序中导出一个Object.如果你想实现它,你可以看看这个:http://people.sc.fsu.edu/~jburkardt/data/mtl/mtl.html

如果你在一个程序中构建一个Object并想要一个更精确的副本,这将是一个很好的事情,这将为你提供如何处理材料的光值.

如果您有任何疑问,请随时向他们询问.

(我知道这可能不是加载.obj文件的最佳方式,因为我们使用多达9个不同的向量,但如果你使用序列化,这可能会非常快.)


dat*_*olf 3

OpenGL 不是场景图形库。它为您提供了一套复杂的绘图工具,但仅此而已。加载3D模型、场景管理等都留给你自己实现,或者使用库来完成。

  • @Abishek:在你处理加载模型之前,我建议你先了解一下基本的 OpenGL 知识。一旦你掌握了这一点,其余的就更有意义了。否则你会在顶点、索引数组和 OpenGL 状态之间迷失方向。 (2认同)