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

时间:2011-05-22 14:27:51

标签: android opengl-es

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

3 个答案:

答案 0 :(得分:8)

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

除了行以“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]));
    }
}

对于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);
    }
}  

每个面由三个顶点构成,每个顶点索引为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);
    }
}

现在你已经通过将索引添加到sperarate Vectors或数组中来处理这个问题。

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

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

这可能需要一些表达式,所以这里有一个简单的例子:

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;
    }
}

现在你的实际操作完成了,并从.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个不同的向量,但如果你也使用序列化,那么这可能会非常快。)

答案 1 :(得分:3)

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

答案 2 :(得分:1)

现在已经很晚了......但仍然是有用的解决方案: min3D引擎有助于在android中加载3d模型

以下是syeps:

1)下载Rajawali lib

2)创建一个RenderActivity

private Object3dContainer faceObject3D;         private Object3dContainer objModel;

    @Override 
    public void initScene() {
        scene.lights().add(new Light());
        scene.lights().add(new Light());

        Light myLight = new Light();
        myLight.position.setZ(150);
        scene.lights().add(myLight);

        IParser parser = Parser.createParser(Parser.Type.OBJ,
                getResources(), "com.azoi.opengltutor:raw/monster_high", true);
        parser.parse();

        objModel = parser.getParsedObject();
        objModel.scale().x = objModel.scale().y = objModel.scale().z = .7f;
        scene.addChild(objModel);
    }

在res / raw目录中添加你的3d模型obj文件......这里是monster_high

就是这样......在Manifest中注册活动并运行:)。

如果要移动3d模型覆盖updateScene(..):

public void updateScene() {
    super.updateScene();

    objModel.rotation().x++;
    objModel.rotation().y--;
    objModel.rotation().z++;
}

此处更多http://code.google.com/p/min3d/wiki/HowToLoadObjFile享受:)