【问题标题】:Create AIScene instance from the file's content从文件内容创建 AIScene 实例
【发布时间】:2019-03-24 14:25:14
【问题描述】:

我正在编写一个 Java Web 服务,可以在其中上传 3D 对象,对其进行操作并存储它。

我要做的是创建一个AIScene 实例,使用byte[] 作为输入参数,它是文件本身(它的内容)。

我在文档中找不到这样做的方法,所有导入方法都需要路径。

现在我正在查看 Assimp 的 lwjgl java 版本和 C++ 版本。使用哪一个来解决问题并不重要。

编辑:我正在尝试完成的代码:

@Override
public String uploadFile(MultipartFile file) {
    AIFileIO fileIo = AIFileIO.create();
    AIFileOpenProcI fileOpenProc = new AIFileOpenProc() {
        public long invoke(long pFileIO, long fileName, long openMode) {
            AIFile aiFile = AIFile.create();
            final ByteBuffer data;

            try {
                data = ByteBuffer.wrap(file.getBytes());
            } catch (IOException e) {
                throw new RuntimeException();
            }

            AIFileReadProcI fileReadProc = new AIFileReadProc() {
                public long invoke(long pFile, long pBuffer, long size, long count) {
                    long max = Math.min(data.remaining(), size * count);
                    memCopy(memAddress(data) + data.position(), pBuffer, max);
                    return max;
                }
            };
            AIFileSeekI fileSeekProc = new AIFileSeek() {
                public int invoke(long pFile, long offset, int origin) {
                    if (origin == Assimp.aiOrigin_CUR) {
                        data.position(data.position() + (int) offset);
                    } else if (origin == Assimp.aiOrigin_SET) {
                        data.position((int) offset);
                    } else if (origin == Assimp.aiOrigin_END) {
                        data.position(data.limit() + (int) offset);
                    }
                    return 0;
                }
            };
            AIFileTellProcI fileTellProc = new AIFileTellProc() {
                public long invoke(long pFile) {
                    return data.limit();
                }
            };
            aiFile.ReadProc(fileReadProc);
            aiFile.SeekProc(fileSeekProc);
            aiFile.FileSizeProc(fileTellProc);
            return aiFile.address();
        }
    };
    AIFileCloseProcI fileCloseProc = new AIFileCloseProc() {
        public void invoke(long pFileIO, long pFile) {
            /* Nothing to do */
        }
    };
    fileIo.set(fileOpenProc, fileCloseProc, NULL);
    AIScene scene = aiImportFileEx(file.getName(),
            aiProcess_JoinIdenticalVertices | aiProcess_Triangulate, fileIo); // ISSUE HERE. file.getName() is not a path, just a name. so is getOriginalName() in my case. 

    try{
        Long id = scene.mMeshes().get(0);
        AIMesh mesh = AIMesh.create(id);
        AIVector3D vertex = mesh.mVertices().get(0);

        return mesh.mName().toString() + ": " + (vertex.x() + " " + vertex.y() + " " + vertex.z());
    }catch(Exception e){
        e.printStackTrace();
    }
    return "fail";
}

在调试方法时,我在绑定到本机的方法中遇到访问冲突:

public static long naiImportFileEx(long pFile, int pFlags, long pFS)

这是消息:

#

Java 运行时环境检测到致命错误:

#

在 pc=0x000000007400125d,pid=6400,tid=0x0000000000003058 处的异常_访问_VIOLATION (0xc0000005)

#

JRE 版本:Java(TM) SE 运行时环境 (8.0_201-b09)(内部版本 1.8.0_201-b09)

Java VM:Java HotSpot(TM) 64 位服务器 VM(25.201-b09 混合模式 windows-amd64 压缩 oops)

有问题的框架:

V [jvm.dll+0x1e125d]

#

无法写入核心转储。默认情况下,在 Windows 的客户端版本上不启用小型转储

#

包含更多信息的错误报告文件保存为:

C:\Users\ragos\IdeaProjects\objectstore3d\hs_err_pid6400.log

#

如果您想提交错误报告,请访问:

http://bugreport.java.com/bugreport/crash.jsp

#

【问题讨论】:

  • 您可以通过aiImportFileEx函数自定义加载过程。您可以为该函数提供一个包含回调函数的结构,以加载/读取资源(无论这些资源是什么)。请参阅 LWJGL/lwjgl3-demos 存储库中的此示例:github.com/LWJGL/lwjgl3-demos/blob/master/src/org/lwjgl/demo/… 它从类路径中作为 InputStreams/ByteBuffers 加载模型和材料。
  • 感谢您的评论,但这里github.com/assimp/assimp/blob/… 它表明底层实现无论如何都使用文件的路径。定义的缓冲区是一个自定义的 IO 系统。因此,它会在我的代码中导致读取访问冲突,因为我没有来自 Spring 的MultipartFile 的有效文件路径。我错过了什么?我正在将我的代码添加到问题中。与您链接的内容基本相同,但获取数据除外。
  • 文件名只是你和 Assimp 之间接口的一部分,让你知道/识别应该加载什么。字符串实际上可以是任何东西。只是为了让您知道要加载/做什么。
  • 而文件名用于加载链接资源,例如 Wavefront .obj 文件中按名称引用的 .mtl 文件。
  • 那真的应该不是问题。你能帮我看看我在哪里搞砸了吗?我从第 8-10 行开始更改了代码,因为 MultipartFile 只是传递了对象,而我已经将它的内容作为 byte[]

标签: spring lwjgl assimp


【解决方案1】:

如果我们使用aiImportFileFromMemory 方法是可能的。

我想遵循的方法是从 github 演示中复制的,实际上是在不必要地复制缓冲区。

访问冲突的原因是使用了间接缓冲区(有关为什么这是一个问题的更多信息,请查看this out)。

解决方案并不像我最初粘贴的代码那么复杂:

@Override
    public String uploadFile(MultipartFile file) throws IOException {
        ByteBuffer buffer = BufferUtils.createByteBuffer((int) file.getSize());
        buffer.put(file.getBytes());
        buffer.flip();
        AIScene scene = Assimp.aiImportFileFromMemory(buffer,aiProcess_Triangulate, (ByteBuffer) null);
        Long id = scene.mMeshes().get(0);
        AIMesh mesh = AIMesh.create(id);
        AIVector3D vertex = mesh.mVertices().get(0);
        return mesh.mName().dataString() + ": " + (vertex.x() + " " + vertex.y() + " " + vertex.z());
    }

在这里,我创建了一个具有适当大小的 direct 缓冲区,加载数据和 flip it(这部分是必须的。)然后让 Assimp 发挥它的魔力所以你得到指向结构的指针。使用return 语句,我只是检查我是否获得了有效数据。

编辑

正如在 cmets 中指出的那样,此实现仅限于单个文件上传,并假设它从 MultipartFile 获取所需的一切,它不适用于引用的格式。有关更多详细信息,请参阅docs

在问题中用作基础的问题 cmets 中链接的演示与我原来的用例不同。

【讨论】:

  • "...实际上不必要地复制缓冲区。"对于演示(必须从 InputStream 中读取数据作为类路径资源),我什至认为没问题。见:github.com/LWJGL/lwjgl3/issues/451#issuecomment-476382224
  • 所以我会改写“我想遵循的方法是从 github 演示中复制的,实际上是不必要地复制缓冲区。”到“我想遵循的方法是从 github 演示中复制的,不适用于我的用例,因为我不使用 InputStream 来支持数据,而是使用数组。最重要的是,在我的用例中Assimp 不会像在演示中那样加载引用的文件,它加载 Wavefront .obj 文件并引用 .mtl 文件。"
  • 另外请注意,aiImportFileFromMemory 显然无法处理将其内容分散到多个文件(例如 .obj 或 .md3)的文件格式。请参阅 Assimp 函数文档中的“注意”部分:assimp.sourceforge.net/lib_html/…
  • 感谢您的意见。该服务假设上传单个文件,在我的情况下它与一个 obj 一起工作(因为我只有一个文件,没有.mtl 等等)。我会在答案中记下,以防有人偶然发现。
  • 但是在这种情况下,我也会考虑解决引用问题。这毕竟是一个实践项目。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多