Chaosgoo | ESP32, IoT & Hardware DIY Blog

这是一个个人维护的技术博客,主要分享和记录 ESP32、嵌入式系统以及硬件 DIY 相关的原创项目与学习笔记。

lib3mf 集成系列(一):编译与示例测试

背景

学习flutter有半个月了, 看Flutter实战看得看不下去了, 打算写点东西练练手.
又不想写基础的UI界面, 所以想试试Flutter FFI, 以及和安卓原生的交互, 再牵涉到一些OpenGL的渲染.
于是就有了此文.
本文是系列文章的一部分, 主要记录如何编译lib3mf, 以及基础用法.
为保证环境一致, 编译时基于9ada20e4287fec118a29d5643f5714ea68302e21 (master分支当时的最新提交)

3mf文件介绍

3MF(3D Manufacturing Format)是一种专为3D打印设计的开放式、基于XML的文档格式,旨在解决STL等传统格式信息缺失的问题。它能在一个压缩文件中完整描述模型几何形状、颜色、材质、支撑和打印参数,2025年已成为国际标准(ISO/IEC 25422:2025)。

lib3mf介绍

lib3mf 是一个开源的 C++ 库,用于读写 3MF 文件。它提供了 3MF 文件的完整实现,包括 3MF 核心规范以及所有相关的扩展。

准备工作下载源码
1
2
git clone https://github.com/3MFConsortium/lib3mf.git
git submodule update
编译
1
2
3
4
mkdir build
cd build
cmake ..
make

成功编译后, 生成的文件位于build目录下, 包含lib3mf.2.dylib等依赖库.

编译SDK/EXample/CPP

lib3mf 的 C++ 示例程序涵盖了从基础几何体生成到高级扩展(如点阵、切片、加密)的应用场景。

直接编译会提示缺少头文件和库文件, 需要修复CMakeLists.txt文件.

修复CMakeLists.txt内路径错误

主要是路径错误, 直接编译报找不到lib3mf_implicit.hpp和lib3mf库找不到问题, 需要手动修复include_directorieslink_directories等路径.
后面我编译的是CPP目录下的Example, 所以路径修改如下:

1
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../Bindings/Cpp)

1
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../Autogenerated/Bindings/Cpp)

1
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../Bin)

1
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../build)

1
add_custom_command(TARGET ${MyTarget} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../../Bin/lib3mf.${LSUFFIX}" $<TARGET_FILE_DIR:${MyTarget}>/lib3mf${LSUFFIXOUT})

1
add_custom_command(TARGET ${MyTarget} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../../../build/lib3mf.${LSUFFIX}" $<TARGET_FILE_DIR:${MyTarget}>/lib3mf${LSUFFIXOUT})

再次编译

再次make得到可执行文件

1
2
3
4
5
6
❯ ls                 
CMakeCache.txt Example_Components Example_SecureCube GenerateVS2017.bat lib3mf.2.dylib
CMakeFiles Example_Converter Example_Slice GenerateVS2019.bat
CMakeLists.txt Example_Cube Example_TextureCube Makefile
Example_BeamLattice Example_ExtractInfo GenerateMake.sh Source
Example_ColorCube Example_FillMeshWithGyroid GenerateVS2015.bat cmake_install.cmake

运行Example_ColorCube得到了一个colorcube.3mf, 原来这是生成3mf文件的例子
使用Bambu Studio打开后预览模型
Color Cube Preview
发现不是立方体, 但是不知道为啥例子叫做Cube, 而且没有颜色.
为了验证颜色, 使用MeshLab打开正确识别到了颜色
Color Cube Preview

lib3mf 示例程序 (CPP) 运行报告

前面步骤编译出了所有的Example可执行文件, 索性在这里记录下所有的Example的功能, 以及在不同查看器中的表现.

1. 基础模型与转换
示例名称 功能描述 兼容性与备注 预览图
Cube 普通长方体模型 最基础的几何体生成示例。
ColorCube 彩色长方体 演示如何为模型添加颜色属性。
Components 对象复用特性 生成多个不同位置的长方体,支持导出 STL/3MF。
Converter 格式转换 实现 3MF ↔ STL 的双向转换。 -
ExtractInfo 信息提取 从 3MF 文件中读取并打印模型元数据。 -

2. 复杂结构与兼容性分析

针对 3MF 高级扩展(Lattice)的专项测试:

示例名称 核心原理 查看器表现 (Bambu Studio/ MeshLab / 3mfViewer) 预览图
BeamLattice 基于“梁”单元(Beam Lattice)的框架。 Bambu Studio打不开;MeshLab仅显轮廓;3mfViewer支持良好。
FillMeshGyroid 数学公式生成的 Gyroid 陀螺面点阵。 Bambu Studio/3mfViewer均无法打开。 -

3MF 并非单一标准,它由 Core Spec 和多个 Extensions 组成, 不同切片软件可能会按需实现Extensions。


3. 功能扩展示例
  • Slice (内置切片)
    • 功能: 生成包含内置切片信息的 3MF 文件。
    • 表现: Bambu Studio 忽略了此信息;但在 3mf Viewer 中,右侧会出现专用的 Slice 滑动条供逐层观察。
  • SecureCube (安全扩展)
    • 功能: 演示 3MF 的安全内容扩展(如加密、数字签名)。
    • 状态: 暂未深入研究。
为 Flutter FFI 做准备

在进入下一篇之前,我们需要确认编译出的动态库是否符合 FFI 调用要求。

检查导出符号

使用 nm -gU lib3mf.2.dylib 检查。lib3mf 提供了专门的 C-Wrapper,这对于 Flutter(仅能直接调用 C 风格接口)至关重要。

1
2
3
4
5
6
7
8
❯ nm -gU lib3mf.2.dylib 
00000000001abe30 T _lib3mf_accessright_getconsumer
00000000001ac8ec T _lib3mf_accessright_getdigestmethod
00000000001ac54c T _lib3mf_accessright_getmgfalgorithm
00000000001ac1b4 T _lib3mf_accessright_getwrappingalgorithm
00000000001e09fc T _lib3mf_acquire
000000000016c3fc T _lib3mf_attachment_getpath
...

Handle 机制

lib3mf 使用句柄(Handle)管理对象,这意味着在 Flutter 侧我们需要维护一套指针映射,防止内存泄漏。

总结

本文完成了 lib3mf 的环境搭建与功能验证。虽然部分高级扩展在商用切片软件中兼容性不佳,但 lib3mf 强大的 C-API 为我们在 Flutter 中操作 3D 模型提供了坚实基础。

Flutter 嵌入安卓原生 View,以及与原生交互

在跨端开发里,有些场景是 Flutter 处理起来比较麻烦或者利用原生组件实现更高效。

这时候就得祭出 PlatformViewMethodChannel。不仅把一个 Android 原生 TextView 塞进了 Flutter 布局,还能实现Flutter和原生Android View的双向交互。

为了直观,我打算基于Flutter默认的计数器模板演示, 界面布局和悬浮按钮还是 Flutter 的,但中间显示的那个数字,换成安卓原生的TextView

阅读更多
球面几何计算:基于经纬度的距离(Great-Circle)推导

球面几何计算:基于经纬度的距离(Great-Circle)推导

背景

最近在做一个基于当前 GPS 坐标,通过输入目标经纬度来计算相对位置与距离的硬件装置。

在查阅相关算法时,我发现网上的推导过程大多较为碎片化或直接给出结论。为了彻底理解其底层的数学逻辑,我决定从零开始重新推导一遍,并将其系统地记录下来。

本文将完整呈现这一推导过程:从建立三维空间直角坐标系开始,利用向量点积导出球面余弦定律(Law of Cosines)。此外,我们还会深入探讨该公式在短距离场景下产生“精度丢失”的物理本质,以及如何利用半角恒等式引入 Haversine 公式 来修正误差。最后,我将分享如何通过数学化简,精简公式降低运算量,从而实现更高的运算效能。

阅读更多

网站性能优化实战:PageSpeed Insights 从 47 分到 97 分的优化历程

This article is also available in the following language: English.
前言

最近为了优化站点体验, 我决定借助PageSpeed Insights的分析,专项优化站点性能表现.
本文起初基于Cactus主题进行优化, 从47分提高到了94分, 在撰写期间, 又将主题切换到了Icarus, 结果之前的部分优化失效.
不得不重新优化, 但是按照同样思路, 甚至把PageSpeed Insights的分数刷新到了97分.

阅读更多

在 M5Stack Cardputer 上实现远程桌面串流(基于 H.264)

This article is also available in the following language: English.
背景

几年前,我曾试过在 ESP32 上实现串流操作
当时硬件搭建在面包板上,一快 1.14 寸的屏幕分辨率为 240x135,主控是初代 ESP32。
文章较为详细地描述了实现细节。

时隔五年,我决定重新制作一次,将硬件环境迁移到 M5Stack 家的 Cardputer。

M5Stack Cardputer H264 Streaming

阅读更多
Android 进阶:如何在安卓中实现像 LVGL 一样的"实体"Border?

Android 进阶:如何在安卓中实现像 LVGL 一样的"实体"Border?

做嵌入式的时候用过 LVGL,它的样式系统给我留下了深刻印象。LVGL 的 Border 是”实体”的——会占据布局空间,把内容往里挤。

安卓这边就没这么痛快了。ShapeDrawableMaterialCardView 的边框更像是”装饰品”,想让边框、圆角、内边距各自独立可控?原生组件做起来挺别扭。

所以我干脆手搓了一个 BorderFrameLayout,把 LVGL 那套逻辑搬过来。
BorderFrameLayout层级示意图
图中不同的颜色代表真实占用的空间。
绿色代表Border, 红色代表内部Padding, 蓝色代表Child可使用空间.

阅读更多