从零构建Open3D C++ GUI应用:环境配置、CMake与3D可视化实战
2026/7/30 10:49:55 网站建设 项目流程

1. 项目概述:从零构建Open3D C++ GUI应用

如果你已经用Python玩过Open3D,体验过它简洁的API和快速的3D可视化,那么当你转向C++时,可能会感到一丝“落差”。Python里几行代码就能弹出的窗口,在C++里需要你亲手搭建一个完整的应用程序骨架。这恰恰是C++的魅力所在,也是其高性能的基石——你对程序拥有完全的控制权。今天,我们就来亲手搭建这个基石:创建一个基于Open3D C++库的、带有图形用户界面的窗口程序。这不仅仅是弹出一个窗口那么简单,它是你后续所有3D点云处理、网格编辑、实时渲染等高级功能得以运行的舞台。

很多人学Open3D C++卡在第一步,环境配置复杂,CMakeLists.txt不知从何写起,好不容易编译通过了,却只是一个黑漆漆的控制台。本教程的目标,就是带你跨过这道门槛,让你看到一个实实在在的、可以交互的GUI窗口。我们将从最基础的CMake工程配置开始,一步步解释每个依赖项的作用,编写清晰的主程序,并最终实现一个能够响应鼠标和键盘事件的3D视图窗口。无论你是想开发专业的点云处理工具,还是为机器人视觉系统构建实时监控界面,这个“第一个窗口”都是你必须迈出的、坚实的第一步。

2. 环境准备与工程配置详解

在开始写代码之前,一个稳定、正确的开发环境是成功的先决条件。与Python的pip install一键搞定不同,C++项目更强调环境的可复现性和依赖性管理。我们将使用CMake作为构建系统,这是现代C++项目,特别是像Open3D这样跨平台库的标准选择。

2.1 系统与工具链选择

首先,明确你的操作系统。本教程以Ubuntu 20.04 LTS为例进行说明,因为这是机器人、计算机视觉领域非常流行且稳定的开发平台。对于Windows用户,核心逻辑完全一致,只是部分库的安装命令和路径设置有所不同。

你需要准备以下工具:

  1. 编译器:GCC/G++ 9 或更高版本,或者 Clang。Ubuntu 20.04 默认的G++ 9.3即可。
  2. 构建工具:CMake (版本 3.18+)。Open3D的某些新特性需要较新版本的CMake支持。
  3. 图形后端:Open3D的GUI依赖于系统级的窗口和渲染API。在Linux上,它通常使用GLFW库来创建和管理窗口,并通过OpenGL进行渲染。幸运的是,Open3D的编译脚本会自动处理这些依赖。

安装基础命令如下:

sudo apt update sudo apt install build-essential cmake libgl1-mesa-dev libglu1-mesa-dev

libgl1-mesa-devlibglu1-mesa-dev提供了OpenGL开发所需的头文件和链接库。

2.2 Open3D C++库的获取与编译

这是最关键,也最容易出错的一步。虽然理论上可以寻找预编译包,但为了最佳的兼容性和灵活性,我强烈推荐从源码编译Open3D。

第一步:获取源码建议从Open3D的GitHub仓库克隆最新稳定版本。打开终端,执行:

git clone --recursive https://github.com/isl-org/Open3D.git cd Open3D

--recursive参数至关重要,它会同时拉取Open3D依赖的子模块(如Eigen、GLFW等),避免后续编译失败。

第二步:配置与编译在Open3D根目录下,创建一个构建目录并进入,然后运行CMake进行配置。

mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON ..

这里有两个关键参数:

  • -DCMAKE_BUILD_TYPE=Release:生成优化后的发布版本,运行速度更快。调试时你可以改用Debug,但编译出的库文件会很大。
  • -DBUILD_SHARED_LIBS=ON:编译生成动态链接库(.so文件)。这通常更省空间,也便于多个程序共享。如果你希望静态链接,可以设为OFF

配置成功后,使用make进行编译。这个过程耗时较长(可能30分钟到1小时以上,取决于你的CPU核心数),你可以用-j参数指定并行编译的线程数以加快速度,例如make -j8

第三步:安装(可选但推荐)编译完成后,将库和头文件安装到系统目录(如/usr/local),这样你所有的项目都可以方便地找到它。

sudo make install

执行此命令后,Open3D的库文件(如libOpen3D.so)会被复制到/usr/local/lib,头文件被复制到/usr/local/include/open3d。你需要运行sudo ldconfig更新一下系统的动态链接库缓存。

注意:从源码编译是理解依赖关系的最佳方式。如果编译过程中报错,最常见的原因是网络问题导致子模块下载不完整,或是系统缺少某个底层依赖(如libx11-dev)。请仔细阅读CMake输出的错误信息,它通常会明确告诉你缺少哪个包。

2.3 创建你的项目工程结构

现在,为你自己的教程项目创建一个独立的工作空间。一个清晰的项目结构能让你后续管理代码和依赖更加轻松。

MyOpen3DProject/ ├── CMakeLists.txt # 项目的总构建脚本 ├── src/ # 源代码目录 │ └── main.cpp # 我们的主程序文件 └── build/ # 编译输出目录(建议空目录,用于存放编译产物)

我们将在项目根目录的CMakeLists.txt中,告诉CMake如何找到我们刚刚安装的Open3D库,并将src/main.cpp编译成可执行文件。

3. 编写CMakeLists.txt:构建系统的核心

CMakeLists.txt是你的项目蓝图。对于刚接触CMake的开发者来说,它可能像天书一样。别担心,我们逐行拆解一个为Open3D GUI项目量身定制的最小化配置。

# 1. 定义CMake的最低版本要求和项目信息 cmake_minimum_required(VERSION 3.18) project(Open3D_GUI_Tutorial VERSION 0.1.0 LANGUAGES CXX) # 2. 设置C++标准。Open3D需要C++14或更高,我们直接使用C++17以获得现代特性支持。 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 3. 寻找Open3D包。这是最关键的一步。 # 如果之前执行了`sudo make install`,CMake会自动在系统路径中查找。 find_package(Open3D REQUIRED) # 4. 打印找到的Open3D信息,用于确认配置成功。 if(Open3D_FOUND) message(STATUS "Found Open3D: ${Open3D_INCLUDE_DIRS}") message(STATUS "Open3D Libraries: ${Open3D_LIBRARIES}") endif() # 5. 添加可执行目标,并将源代码文件关联给它。 add_executable(${PROJECT_NAME} src/main.cpp) # 6. 为你的可执行目标链接Open3D库。 # Open3D::Open3D是一个CMake导入的目标(target),它自动包含了所有必要的头文件路径、链接库和编译选项。 target_link_libraries(${PROJECT_NAME} Open3D::Open3D) # 7. (可选,但推荐) 设置可执行文件的输出目录,保持build目录整洁。 set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)

关键点解析

  • find_package(Open3D REQUIRED):这行命令指挥CMake去寻找Open3D的配置。REQUIRED表示如果找不到,就报错停止。成功找到后,会定义诸如Open3D_FOUNDOpen3D_INCLUDE_DIRSOpen3D_LIBRARIES等变量,以及最重要的Open3D::Open3D目标。
  • target_link_libraries(... Open3D::Open3D):这是现代CMake的最佳实践。你不需要手动指定-I(包含路径)和-l(链接库)。通过链接这个“目标”,所有依赖项(如OpenGL、GLFW、Eigen等)都会被自动、正确地传递给你的项目。这避免了手动管理依赖链的繁琐和错误。

实操心得:如果你没有进行系统范围的make install,而是想直接链接编译Open3D生成的build/lib目录下的库,可以使用find_package(Open3D PATHS "/path/to/your/Open3D/build" REQUIRED)来指定搜索路径。这种方式在快速迭代和调试Open3D自身时非常有用。

4. 第一个GUI窗口的代码实现

环境就绪,蓝图绘好,现在让我们来编写真正的C++代码。打开src/main.cpp文件。

4.1 基础程序骨架与头文件

// 引入Open3D的核心GUI和可视化头文件 #include <open3d/Open3D.h> int main(int argc, char* argv[]) { // 初始化Open3D的应用环境。这对于GUI和可视化模块是必须的。 // 它会处理底层窗口系统(如GLFW)的初始化。 open3d::utility::SetVerbosityLevel(open3d::utility::VerbosityLevel::Debug); open3d::visualization::gui::Application::GetInstance().Initialize(); // 你的GUI代码将写在这里... // 进入应用主事件循环。这行代码会让窗口保持显示并响应用户输入,直到程序被终止。 open3d::visualization::gui::Application::GetInstance().Run(); return 0; }
  • #include <open3d/Open3D.h>:这是包含所有Open3D功能的“总头文件”,方便入门。在大型项目中,为了编译速度,建议只包含你需要的具体头文件,如#include <open3d/visualization/gui/Application.h>
  • SetVerbosityLevel:设置日志输出级别为Debug,这样在控制台能看到更多初始化信息,便于排查问题。发布时可以设为ErrorWarning
  • Application::Initialize()必须首先调用。它创建了GUI应用的单例(Singleton)并执行底层初始化。
  • Application::Run()这是一个阻塞调用。程序执行流会停在这里,不断地处理窗口事件(鼠标点击、键盘按键、重绘请求等)。当所有窗口关闭或收到退出指令时,Run()函数才会返回,程序继续向下执行并结束。

4.2 创建并配置主窗口

仅仅初始化应用还不够,我们需要创建一个具体的窗口。我们在初始化之后、运行之前添加窗口创建逻辑。

int main(int argc, char* argv[]) { open3d::utility::SetVerbosityLevel(open3d::utility::VerbosityLevel::Debug); auto& app = open3d::visualization::gui::Application::GetInstance(); app.Initialize(); // -------------------------------------------- // 1. 创建主窗口 // -------------------------------------------- // 参数:窗口标题,初始宽度,初始高度 auto window = std::make_shared<open3d::visualization::gui::Window>("My First Open3D GUI", 1024, 768); // -------------------------------------------- // 2. 设置窗口的关闭回调 // -------------------------------------------- // 当用户点击窗口关闭按钮时,这个函数会被调用。 // 这里我们简单地告诉应用要退出了。 window->SetOnClose([&app]() { app.Quit(); // 触发应用退出,使 Application::Run() 返回 return true; // 返回true表示允许关闭 }); // -------------------------------------------- // 3. 将窗口添加到应用中 // -------------------------------------------- app.AddWindow(window); // -------------------------------------------- // 4. 进入主事件循环 // -------------------------------------------- app.Run(); return 0; }

现在,编译并运行这个程序(在项目build目录下执行cmake .. && make,然后运行生成的可执行文件),你应该能看到一个标题为“My First Open3D GUI”、大小为1024x768的空白窗口了!你可以拖动、缩放、最小化、关闭它。一个真正的原生GUI窗口诞生了。

4.3 在窗口中添加3D可视化场景

一个空窗口意义不大。Open3D GUI的核心价值在于其强大的3D可视化能力。让我们在窗口中嵌入一个Scene(场景)控件,它是所有3D几何体(点云、网格、线集)的渲染容器。

int main(int argc, char* argv[]) { // ... 初始化代码同上 ... auto window = std::make_shared<open3d::visualization::gui::Window>("Open3D GUI with 3D View", 1024, 768); // -------------------------------------------- // 创建3D场景控件 // -------------------------------------------- // SceneWidget 是一个可以嵌入到窗口中的、用于3D渲染的组件。 auto scene_widget = std::make_shared<open3d::visualization::gui::SceneWidget>(); // -------------------------------------------- // 创建一个简单的几何体并添加到场景 // -------------------------------------------- // 创建一个红色的坐标系(X轴红,Y轴绿,Z轴蓝),尺寸为1.0 auto coord_frame = open3d::geometry::TriangleMesh::CreateCoordinateFrame(1.0); // 将坐标系几何体添加到场景控件的场景中 scene_widget->GetScene()->AddGeometry("Coordinate Frame", coord_frame); // -------------------------------------------- // 设置场景的初始视角 // -------------------------------------------- // 让相机看向整个场景,确保坐标系在视图中 scene_widget->SetupCamera(60.0f, // 垂直视场角(度) scene_widget->GetScene()->GetBoundingBox(), // 场景的包围盒 {0.0, 0.0, 0.0} // 相机初始看向的中心点(原点) ); // -------------------------------------------- // 将场景控件设置为窗口的中心内容 // -------------------------------------------- // 这意味着场景控件会占据窗口的整个客户区。 window->AddChild(scene_widget); window->SetOnClose([&app]() { app.Quit(); return true; }); app.AddWindow(window); app.Run(); return 0; }

代码解析

  1. SceneWidget:这是连接GUI和3D渲染的核心桥梁。它本身是一个GUI控件,同时管理着一个内部的Open3DScene对象。
  2. GetScene()->AddGeometry(...):这是向3D场景中添加物体的标准方式。你需要为每个几何体指定一个唯一的名称(如”Coordinate Frame”),方便后续查找、更新或删除。
  3. SetupCamera:这个函数非常实用。它根据你提供的场景包围盒和视野角度,自动计算一个合适的相机位置和朝向,让所有物体都能完整地显示在视图内。避免了手动调整相机参数的麻烦。

编译运行,你将看到一个带有红绿蓝三维坐标系的窗口。你可以用鼠标进行交互:

  • 左键拖拽:旋转视图。
  • 右键拖拽:平移视图。
  • 滚轮:缩放视图。

至此,你已经成功创建了一个具备基本3D交互功能的GUI应用。

5. 添加基础交互与界面元素

一个完整的GUI应用除了显示,还需要有交互逻辑。让我们为窗口添加一个按钮,并学习如何处理GUI事件。

5.1 使用布局管理器与添加按钮

直接AddChild会让控件充满整个窗口。如果我们想同时放置多个控件(如一个3D视图加一个按钮面板),就需要使用布局管理器。Open3D GUI提供了Vert(垂直布局)和Horiz(水平布局)等便捷方式。

int main(int argc, char* argv[]) { // ... 初始化代码同上 ... auto window = std::make_shared<open3d::visualization::gui::Window>("Interactive Open3D GUI", 1024, 768); // 创建一个垂直布局作为窗口的根布局 auto layout = std::make_shared<open3d::visualization::gui::Vert>(); // 1. 创建场景控件(同上) auto scene_widget = std::make_shared<open3d::visualization::gui::SceneWidget>(); auto coord_frame = open3d::geometry::TriangleMesh::CreateCoordinateFrame(1.0); scene_widget->GetScene()->AddGeometry("Coordinate Frame", coord_frame); scene_widget->SetupCamera(60.0f, scene_widget->GetScene()->GetBoundingBox(), {0.0, 0.0, 0.0}); // 2. 创建一个水平布局的按钮面板 auto button_layout = std::make_shared<open3d::visualization::gui::Horiz>(); button_layout->AddStretch(); // 添加一个弹性空间,将按钮推到一侧 // 3. 创建“添加立方体”按钮 auto add_cube_btn = std::make_shared<open3d::visualization::gui::Button>("Add a Cube"); // 为按钮设置回调函数:当按钮被点击时,执行指定的操作 add_cube_btn->SetOnClicked([scene_widget]() { // 创建一个单位立方体网格 auto cube = open3d::geometry::TriangleMesh::CreateBox(1.0, 1.0, 1.0); // 将立方体涂成蓝色 cube->PaintUniformColor({0.0, 0.0, 1.0}); // 添加到场景中,使用一个动态生成的名称以避免重复 static int cube_count = 0; std::string name = "Cube_" + std::to_string(cube_count++); scene_widget->GetScene()->AddGeometry(name, cube); // 添加后,重置相机视角以看到新物体 scene_widget->SetupCamera(60.0f, scene_widget->GetScene()->GetBoundingBox(), {0.0, 0.0, 0.0}); open3d::utility::LogInfo("Added: {}", name); }); // 4. 创建“清空场景”按钮 auto clear_btn = std::make_shared<open3d::visualization::gui::Button>("Clear All"); clear_btn->SetOnClicked([scene_widget]() { // 获取场景中所有几何体的名称 auto geometries = scene_widget->GetScene()->GetGeometries(); for (const auto& name : geometries) { scene_widget->GetScene()->RemoveGeometry(name); } open3d::utility::LogInfo("All geometries cleared."); }); // 5. 将按钮添加到按钮布局中 button_layout->AddChild(add_cube_btn); button_layout->AddChild(clear_btn); // 6. 将场景控件和按钮布局依次添加到主垂直布局中 // SceneWidget需要尽可能多的空间,所以设置其伸缩因子为1 layout->AddChild(scene_widget, 1); layout->AddChild(button_layout); // 7. 将布局设置为窗口的内容 window->AddChild(layout); window->SetOnClose([&app]() { app.Quit(); return true; }); app.AddWindow(window); app.Run(); return 0; }

关键机制解析

  • 布局系统VertHorizLayout的子类,用于自动排列子控件。AddChild时可以指定一个“伸缩因子”(如layout->AddChild(scene_widget, 1)),因子越大,该控件在布局中占据的剩余空间比例就越大。AddStretch()会添加一个可伸缩的空格,常用于对齐控件。
  • 事件回调SetOnClicked是典型的GUI事件处理方式。这里我们传递了一个Lambda表达式[scene_widget]() { ... }。方括号[]是捕获列表,[scene_widget]表示Lambda函数体内部可以访问(捕获)外部变量scene_widget的副本。这是C++11之后处理回调的现代且安全的方式。
  • 场景管理GetScene()->GetGeometries()返回已添加几何体名称的列表,RemoveGeometry(name)则根据名称移除。这是动态管理3D场景的基础。

现在运行程序,你会看到窗口底部有两个按钮。点击“Add a Cube”,一个蓝色的立方体会出现在坐标系旁边,并且视图会自动调整以容纳新物体。多次点击会添加多个立方体。点击“Clear All”则会清空所有添加的几何体,只留下最初的坐标系。

5.2 处理键盘与鼠标3D拾取事件

除了按钮点击,我们经常需要响应更直接的3D交互,比如用鼠标点击选中一个物体。

// 在创建scene_widget之后,添加以下代码 scene_widget->SetOnMouseButton([scene_widget](const open3d::visualization::gui::MouseButtonEvent& e) { // 检查是否是左键按下事件 if (e.type == open3d::visualization::gui::MouseButtonEvent::Type::BUTTON_DOWN && e.button.button == open3d::visualization::gui::MouseButton::LEFT) { // 进行3D场景拾取,获取鼠标点击位置对应的几何体信息 auto pick_result = scene_widget->GetScene()->PickPoint(e.x, e.y); if (pick_result.HasHit()) { // 如果拾取到了几何体 const auto& geometry_name = pick_result.GetGeometryName(); open3d::utility::LogInfo("You clicked on geometry: {}", geometry_name); // 例如,可以高亮被选中的物体(这里简单打印日志) } } return false; // 返回false表示事件未被完全处理,可以继续传递给其他处理器 }); // 同样,可以添加键盘事件回调 window->SetOnKeyEvent([scene_widget](const open3d::visualization::gui::KeyEvent& e) { if (e.type == open3d::visualization::gui::KeyEvent::Type::DOWN) { if (e.key == open3d::visualization::gui::KeyName::R) { // 按下R键,重置视图 scene_widget->SetupCamera(60.0f, scene_widget->GetScene()->GetBoundingBox(), {0.0, 0.0, 0.0}); open3d::utility::LogInfo("View reset by key R."); return true; // 返回true表示事件已处理,不再传递 } } return false; });

这段代码为SceneWidget添加了鼠标点击拾取和窗口级键盘事件监听。按下R键可以快速将视图重置到初始状态,这是一个非常实用的功能。

6. 项目构建、运行与调试实战

理论说再多,不如动手跑一遍。让我们完成从编译到运行的完整流程。

6.1 完整的构建与运行步骤

在你的项目根目录MyOpen3DProject下:

# 1. 进入并清空build目录(如果是第一次,需要创建) cd build # 如果build目录非空,可以 rm -rf * 清理,但请确认无误 # 2. 运行CMake生成构建系统(Makefile) cmake .. -DCMAKE_BUILD_TYPE=Release # 3. 编译项目 make -j4 # 根据你的CPU核心数调整j后面的数字 # 4. 运行生成的可执行文件 ./bin/Open3D_GUI_Tutorial

如果一切顺利,你的交互式3D GUI窗口就应该弹出来了。

6.2 常见编译与运行问题排查

即使按照步骤操作,你也可能会遇到一些问题。这里记录几个我踩过的坑和解决方案。

问题1:CMake找不到Open3D包

CMake Error at CMakeLists.txt:10 (find_package): By not providing "FindOpen3D.cmake" in CMAKE_MODULE_PATH this project has asked CMake to find a package configuration file provided by "Open3D", but CMake did not find one.

解决方案

  • 确认你已成功编译并安装了Open3D(执行了sudo make install)。
  • 如果安装了但CMake仍找不到,可以尝试在CMake命令中显式指定Open3D的安装路径:
    cmake .. -DOpen3D_DIR=/usr/local/lib/cmake/Open3D
    或者,如果Open3D安装在自定义路径/path/to/Open3D/install,则指定:
    cmake .. -DOpen3D_DIR=/path/to/Open3D/install/lib/cmake/Open3D

问题2:链接错误,未定义引用

undefined reference to `open3d::visualization::gui::Application::Initialize()'

解决方案

  • 这几乎总是因为target_link_libraries没有正确链接Open3D::Open3D目标。请确保你的CMakeLists.txt中使用了target_link_libraries(${PROJECT_NAME} Open3D::Open3D),并且find_package(Open3D)成功。
  • 检查编译Open3D时是否使用了-DBUILD_SHARED_LIBS=ON。如果编译的是静态库,链接方式可能需要调整。

问题3:运行时找不到动态库

error while loading shared libraries: libOpen3D.so: cannot open shared object file: No such file or directory

解决方案

  • 如果你没有系统安装(sudo make install),而是直接链接build目录的库,需要告诉系统运行时库的路径:
    export LD_LIBRARY_PATH=/path/to/your/Open3D/build/lib:$LD_LIBRARY_PATH ./bin/Open3D_GUI_Tutorial
  • 永久解决方法是将库路径添加到系统配置中,或者直接进行系统安装。

问题4:窗口闪退或无法交互

  • 确保你的main函数中,app.Run()app.AddWindow(window)之后被调用。
  • 确保没有在app.Run()之前意外地让窗口对象被销毁(例如,使用了局部变量而非智能指针shared_ptr)。
  • 检查控制台输出,Open3D的Debug级别日志可能会提供线索。

6.3 在IDE中开发(以VSCode为例)

在终端敲命令固然直接,但在集成开发环境中编码体验更佳。以VSCode为例:

  1. 安装扩展:安装C/C++扩展(ms-vscode.cpptools)和CMake Tools扩展(ms-vscode.cmake-tools)。
  2. 打开项目:用VSCode打开MyOpen3DProject文件夹。
  3. 配置CMake:按下Ctrl+Shift+P,输入“CMake: Configure”,选择你的编译器套件(如GCC 9.3)。
  4. 选择构建目标:底栏状态栏会出现构建目标选择器,选择Open3D_GUI_Tutorial
  5. 构建与运行:点击状态栏的“Build”按钮进行编译,点击“Debug”按钮可以启动调试。你可以在main.cpp中设置断点,单步跟踪程序执行,观察变量状态,这对于理解GUI事件流和调试逻辑错误至关重要。

7. 从示例到实践:下一步探索方向

恭喜你,现在已经拥有了一个功能完整的Open3D C++ GUI应用骨架。但这只是一个起点。基于这个骨架,你可以向多个方向深入探索:

  1. 加载与处理真实数据:将示例中的CreateBoxCreateCoordinateFrame替换为从文件加载点云或网格。

    auto pcd = open3d::io::CreatePointCloudFromFile(“/path/to/pointcloud.ply”); if (pcd) { scene_widget->GetScene()->AddGeometry(“MyPointCloud”, pcd); }
  2. 实现复杂交互:利用鼠标和键盘事件回调,实现物体的平移、旋转、缩放,或者框选、测量等工具。

  3. 构建复杂UI界面:探索Open3D GUI提供的更多控件,如LabelSliderCheckboxComboboxTreeView等,结合布局管理器,构建出类似MeshLab、CloudCompare那样的专业工具界面。

  4. 自定义渲染与着色:通过SceneGetScene()接口,可以获取Open3DScene对象,进而深入控制材质、灯光、后期处理效果,实现自定义的着色器或渲染通道。

  5. 多线程与异步操作:对于加载大型模型或进行耗时计算(如点云配准、重建),需要将任务放在后台线程,避免阻塞GUI主线程导致界面卡死。Open3D GUI的Application提供了PostTask函数,可以将任务抛回主线程安全地更新UI。

记住,Open3D的C++接口文档和源码是你最好的老师。多查阅include/open3d目录下的头文件,里面的注释通常很详细。从第一个窗口出发,逐步添加功能,你就能构建出满足自己特定需求的强大3D可视化应用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询