转换浮点数组中的 blend 或 obj 文件以在 OpenGL 中绘图

Posted

技术标签:

【中文标题】转换浮点数组中的 blend 或 obj 文件以在 OpenGL 中绘图【英文标题】:Convert blend or obj file in float array for drawing in OpenGL 【发布时间】:2018-06-30 07:53:06 【问题描述】:

是否可以将 .blend 或 .obj 文件转换为浮点数组以供以后在 OpenGL 中进行渲染?例如, 顶点:

float[] vertices = 
    -1, -1, 0,
    // some vertices
;

纹理坐标:

float[] texCoords = 
    0, 0,
    // some texture coordinates
;

顶点索引:

float[] indices = 
    0, 1, 2,
    // some vertices indices
;

获得我们绘制的图形类型也很好:

glDrawElements(GL.GL_TRIANGLES /* type */, intbuff.capacity(), GL.GL_UNSIGNED_INT, intbuff);

有可能吗?以及如何做到这一点?

【问题讨论】:

您应该查看众多 WaveFront OBJ 导入器的源代码,这可能是一个很好的灵感来源,可以根据 JOGL 编写自己的源代码,但请记住,OBJ 文件也可以包含一些材料.你可以在这里查看我的源代码:github.com/gouessej/Ardor3D/tree/master/ardor3d-extras/src/main/… @gouessej : [...]"based on JOGL"[...] 除了可能在 obj 文件中引用的材料/纹理之外,该库很可能无关紧要。 最初,原发帖者的问题被标记为“jogl”。其次,库很重要,因为与 OpenGL 和 OpenGL-ES API 的绑定可能使用不同的语法,JOGL 有自己的 API 来操作纹理和图像,即使仍然可以使用较低级别的调用。此外,每个场景图 API 或框架都有自己的 API 来操作变换、矩阵等。有些引擎只支持可编程管道,有些只支持固定管道。最后,原海报提到了纹理坐标。 JOGL-demos 中有一个 OBJ 导入器:github.com/sgothel/jogl-demos/blob/master/src/demos/util/… JOGL-Utils 中有另一个:github.com/sgothel/jogl-utils/blob/master/src/net/java/… 两者都没有我的完整。选择最适合您需求的。 【参考方案1】:

为什么要打开 .blend 文件? 你需要动画吗?如果没有,您不必导入 .blend 文件。 对于大多数 OBJ 文件,创建自己的文件非常容易。

OBJ File Format Specifications

但这不是必须的。

这是一个完整的 OBJ :https://github.com/javagl/Obj

顺便说一句,这是我的 Mesh 类,只能加载单组 OBJ:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;

public class Mesh 
    public float[] vertices;
    public float[] texcoords;
    public float[] normals;
    public int[] indices;

    public Mesh(float[] vertices, float[] texcoords, float[] normals, int[] indices) 
        this.vertices = vertices;
        this.texcoords = texcoords;
        this.normals = normals;
        this.indices = indices;
    

    public Mesh(String filename) throws FileNotFoundException, IOException 
        File f=new File(filename);
        FileInputStream fis=new FileInputStream(f);
        int c=fis.read();
        String s="";
        while (c != -1) 
            s+=(char)c;
            c=fis.read();
        
        String[] lines=s.split("\n");
        ArrayList<Float> vertices2=new ArrayList<Float>();
        ArrayList<Float> normals2=new ArrayList<Float>();
        ArrayList<Float> texcoords2=new ArrayList<Float>();
        ArrayList<Integer> normalindices=new ArrayList<Integer>();
        ArrayList<Integer> uvindices=new ArrayList<Integer>();
        ArrayList<Integer> indices2=new ArrayList<Integer>();
        for (String line:lines) 
            String[] parts=line.split(" ");
            if (parts[0].equals("v")) 
                vertices2.add(Float.parseFloat(parts[1]));
                vertices2.add(Float.parseFloat(parts[2]));
                vertices2.add(Float.parseFloat(parts[3]));
            
            else if (parts[0].equals("vt")) 
                texcoords2.add(Float.parseFloat(parts[1]));
                texcoords2.add(Float.parseFloat(parts[2]));
            
            else if (parts[0].equals("vn")) 
                normals2.add(Float.parseFloat(parts[1]));
                normals2.add(Float.parseFloat(parts[2]));
                normals2.add(Float.parseFloat(parts[3]));
            
            else if (parts[0].equals("f")) 
                for (int i=1; i < parts.length; i++) 
                    String part=parts[i];
                    String[] byslash=part.split("/");
                    int indi=Integer.parseInt(byslash[0]);
                    indices2.add(indi-1);
                    if (byslash.length > 1) 
                    indi=Integer.parseInt(byslash[1]);
                    uvindices.add(indi-1);
                    indi=Integer.parseInt(byslash[2]);
                    normalindices.add(indi-1);
                    
                    else 
                        uvindices.add(indi-1);
                        normalindices.add(indi-1);
                    
                                
            
        
        indices=new int[indices2.size()];
        vertices=new float[indices2.size()*3];
        texcoords=new float[indices2.size()*2];
        normals=new float[indices2.size()*3];
        for (int i=0; i < indices.length; i++) 
            indices[i]=i;
            int vuvi=indices2.get(i)*3;
            int fuvi=uvindices.get(i)*2;
            int nuvi=normalindices.get(i)*3;
            vertices[i*3]=vertices2.get(vuvi);
            vertices[i*3+1]=vertices2.get(vuvi+1);
            vertices[i*3+2]=vertices2.get(vuvi+2);
            texcoords[i*2]=texcoords2.get(fuvi);
            texcoords[i*2+1]=texcoords2.get(fuvi+1);
            normals[i*3]=normals2.get(nuvi);
            normals[i*3+1]=normals2.get(nuvi+1);
            normals[i*3+2]=normals2.get(nuvi+2);
        
    

它不支持材质,这使得它独立于库(JOGL/LWJGL)。 希望对你有帮助。

【讨论】:

问题被标记为“jogl”,原始发帖人在他的源代码中提到了纹理坐标,这似乎表明他需要纹理支持。如果不能绘制纹理,为什么还要读取纹理坐标?网上有大量更完整、更经过测试的 OBJ 导入器。没有必要在更糟的情况下重新发明***。 Github 上的lect86 在 jassimp 上工作,在 JMonkeyEngine、LibGDX、Unlicense 中有这种格式的导入器……在 jReality 和 JogAmp 的 Ardor3D Continuation 中都有一个导入器和一个导出器。 @gouessej 给你解释一下:一些 OBJ文件有usemtl。这定义了所需纹理的来源。但最有可能的是,您将使用应用程序中的任何纹理对其进行纹理处理。而且纹理加载与 OBJ 加载有很大不同 在材质模板库文件中指定纹理贴图是一种明确的方式来指示要使用的纹理,即使您可以通过在软件中使用其他纹理来覆盖此指示。抱歉,当我查看免费软件的源代码时,我不想猜测哪些图像文件用作纹理。当您想在同一个 OBJ 文件的网格中使用一组完全不同的纹理时,您仍然可以编写多个 MTL 文件并加载它们或以编程方式创建多个材质库。 是的,有些 OBJ 文件有 usemtl,有些则没有。在没有材质的情况下使用带有纹理坐标的 OBJ 文件或在不加载材质的情况下使用纹理坐标加载 OBJ 文件是一种可能的解决方案,但对我来说是一个糟糕的解决方案。这就是我对上面的源代码不满意的主要原因,我谈到了更糟糕的重新发明***,因为我看到很多进口商没有处理行继续标记,也没有明确指出哪些关键字没有被处理。 @gouessej 是的,这就是我发布更好链接的原因。我只是想展示一些我的来源,因为这可能有助于他理解它。

以上是关于转换浮点数组中的 blend 或 obj 文件以在 OpenGL 中绘图的主要内容,如果未能解决你的问题,请参考以下文章

在 Blend 2015 中使用 3D OBJ 文件

将浮点值存储在数组中,并分析最后 20 个值以在 C++ 中检查

将 CString 转换为浮点数组

csv转换obj

将浮点数组转换为 Wav 文件 Swift [关闭]

C语言字符串类型转换为整型或浮点怎么做