0

底线在前面

在立方体的每一侧使用我的 3D 对象(例如立方体)1 三角形正在正确渲染,而另一侧则没有。

概述

我正在尝试将在 Blender 中创建的 3D 对象导入我的 Android OpenGL 世界。

我编写了自己的自定义解析器来读取顶点、索引以及现在的纹理坐标。我可以很好地读取所有数据,并且没有纹理,形状很完美。问题是当我尝试读取纹理坐标时,在每个面上,一个三角形都非常糟糕,而其中一个三角形被正确渲染。

我相信这与在搅拌机中如何生成纹理坐标有关。我注意到在f 1/1 2/2 3/3 4/4列出“纹理索引”的文件部分中,它们没有按照纹理列出的顺序排列。这可能是问题吗?如果我按照列出纹理索引的顺序构建纹理缓冲区会有帮助吗?

我的 .obj 文件

# Blender v2.63 (sub 0) OBJ File: ''
# www.blender.org
mtllib untitled.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 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.000000 0.334353
vt 0.332314 0.333333
vt 0.333333 0.665647
vt 0.001020 0.666667
vt 1.000000 0.001019
vt 0.998981 0.333333
vt 0.666667 0.332314
vt 0.667686 0.000000
vt 1.000000 0.665647
vt 0.667686 0.666667
vt 0.666667 0.334353
vt 0.334353 0.666667
vt 0.333333 0.334353
vt 0.665647 0.333333
vt 0.666667 0.665647
vt 0.333333 0.332314
vt 0.001020 0.333333
vt 0.000000 0.001020
vt 0.332314 0.000000
vt 0.333333 0.001019
vt 0.665647 0.000000
vt 0.334353 0.333333
usemtl Material_golden_fur_by_Dwaoviel.jpg
s off
f 1/1 2/2 3/3 4/4
f 5/5 8/6 7/7 6/8
f 1/6 5/9 6/10 2/11
f 2/12 6/13 7/14 3/15
f 3/16 7/17 8/18 4/19
f 5/20 1/21 4/7 8/22

我的解析器方法

public static Mesh createMesh(int resourceID)
{
    Mesh m = new Mesh();
    Scanner s;
    BufferedReader inputStream = null;
    
    ArrayList<Float> floats = new ArrayList<Float>();
    ArrayList<Short> indicies = new ArrayList<Short>();
    ArrayList<Float> textures = new ArrayList<Float>();
    ArrayList<Short> texturesindex = new ArrayList<Short>();
    try
    {
        inputStream = new BufferedReader(new InputStreamReader(context.getResources().openRawResource(resourceID)));
        s = new Scanner(inputStream);
        String line = inputStream.readLine();
        line = inputStream.readLine();
        line = inputStream.readLine();
        line = inputStream.readLine();
        line = inputStream.readLine();
        while(line.charAt(0) == 'v'&&line.charAt(1)!='t')
        {
            s = new Scanner(line);
            s.next();
            floats.add(s.nextFloat());
            floats.add(s.nextFloat());
            floats.add(s.nextFloat());
            line = inputStream.readLine();
        }
        while(line.charAt(0)=='v' && line.charAt(1)=='t')
        {
            s = new Scanner(line);
            s.next(); //read in "vt"
            textures.add(s.nextFloat());
            textures.add(s.nextFloat());
            line = inputStream.readLine();
        }
        line = inputStream.readLine();
        line = inputStream.readLine();
        while(line != null && line.charAt(0) == 'f')
        {
            s = new Scanner(line);
            s.useDelimiter("[ /\n]");
            String xx = s.next();
            int a,b,c,d;
            int e,f,g,h;
            
            a = s.nextShort();
        
            e = s.nextShort();
            
            b = s.nextShort();
            
            f = s.nextShort();
            
            c = s.nextShort();
            
            g = s.nextShort();
            
            d = s.nextShort();
            
            h = s.nextShort();
            
            indicies.add((short)a);
            indicies.add((short)b);
            indicies.add((short)c);
            indicies.add((short)a);
            indicies.add((short)c);
            indicies.add((short)d);
            line = inputStream.readLine();
        }       
        float[] vertex = new float[floats.size()];
        for(int i=0;i<vertex.length;i++)
        {
            vertex[i] = floats.get(i).floatValue();
        }
        short[] ind = new short[indicies.size()];
        for(int i=0;i<ind.length;i++)
        {
            ind[i] = (short) (indicies.get(i).shortValue()-1); //minus one because its 1 based in that program
        }
        float[] texture = new float[floats.size()];
        for(int i=0;i<texture.length;i++)
        {
            texture[i] = textures.get(i).floatValue();
        }
        m.constructVertexBuffer(vertex);
        m.constructIndexBuffer(ind);
        m.constructTextureBuffer(texture);
        
    } 
    catch (FileNotFoundException e)
    {
        e.printStackTrace();
    } 
    catch (IOException e)
    {
        e.printStackTrace();
    }

    return m;
}

请注意,此方法基本上将尽可能多的纹理 uv 坐标读入数组列表,然后填充浮点数组,然后调用构造纹理缓冲区方法,该方法执行 OpenGL 所需的所有 ByteBuffer/FloatBuffer 内容。

我的构造方法

public void constructTextureBuffer(float[] texture)
{
    ByteBuffer vbb = ByteBuffer.allocateDirect(texture.length*4);
    vbb.order(ByteOrder.nativeOrder());
    textureBuffer = vbb.asFloatBuffer();
    textureBuffer.put(texture);
    textureBuffer.position(0);
}

有人对我可以尝试解决的问题有任何想法吗?

4

2 回答 2

1

我不确定我是否正确阅读了您的代码,但我认为问题在于解析面部命令('f'字符)。如果您查看OBJ 规范或wiki上关于 obj 格式的文章,则 face 命令是格式(在您的情况下)f v1/vt1 v2/vt2 v3/vt3 ...,这意味着首先是顶点坐标索引(进入您先前加载的顶点坐标列表),'/'然后是纹理坐标索引(到您之前加载的纹理坐标列表中)。'f'命令创建一个面(三角形、四边形等) 后,一行上的所有这些顶点。

纹理数组(列表)的索引是否与之前声明的顺序相同也没关系,它只是索引(0 <= 索引 < 列表大小)。

于 2012-12-14T15:08:59.080 回答
0

有一些很好的适用于 Android 的 FOSS OpenGL 引擎。虽然我不能给你一个你的代码没有运行的确切原因,但我知道 Rajawali 的 OBJ 解析器做得很好,尤其是从 Blender 导出的模型。也许你可以在他们的代码中找到一些线索:

https://github.com/MasDennis/Rajawali/blob/master/src/rajawali/parser/ObjParser.java

编辑:我还应该补充一点,即使在拉贾瓦里,我通常也必须从我的 OBJ 中删除两行,如下所示: usemtl Material_golden_fur_by_Dwaoviel.jpgs off

也许您的解析器也不能很好地处理这些?

于 2013-01-29T19:49:13.793 回答