You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Open3D C++ 3D点云动画失效问题排查

Open3D C++点云动画窗口冻结问题解决

问题背景

在Open3D C环境中实现3D点云堆叠动画时,代码可编译运行且能显示初始点,但动画无法渲染,窗口出现冻结。参考Python方案未解决,且无相关C示例。

问题根源

代码存在三个核心错误:

  • sleep(2)阻塞主线程:sleep会直接卡住UI渲染线程,导致窗口失去响应。
  • 动画回调内嵌套visualizer->Run():Run()是阻塞式主循环,在回调中调用会彻底打乱渲染流程。
  • 动画回调逻辑错误:回调函数应负责单次帧更新,而非内部写循环执行所有动画步骤。Open3D的动画回调会被主渲染循环反复调用,需控制单次回调仅完成一步更新。

修正后的代码

#include <Eigen/Dense>
#include <iostream>
#include <memory>
#include <chrono>

#include "open3d/Open3D.h"

using namespace open3d;

void PrintPointCloud(const std::shared_ptr<geometry::PointCloud> &pointcloud) {
    bool pointcloud_has_normal = pointcloud->HasNormals();
    utility::LogInfo("Pointcloud has %d points.",
                     (int)pointcloud->points_.size());

    Eigen::Vector3d min_bound = pointcloud->GetMinBound();
    Eigen::Vector3d max_bound = pointcloud->GetMaxBound();
    utility::LogInfo(
            "Bounding box is: ({:.4f}, {:.4f}, {:.4f}) - ({:.4f}, {:.4f}, "
            "{:.4f})",
            min_bound(0), min_bound(1), min_bound(2), max_bound(0),
            max_bound(1), max_bound(2));

    for (size_t i = 0; i < pointcloud->points_.size(); i++) {
        if (pointcloud_has_normal) {
            const Eigen::Vector3d &point = pointcloud->points_[i];
            const Eigen::Vector3d &normal = pointcloud->normals_[i];
            utility::LogInfo("{:.6f} {:.6f} {:.6f} {:.6f} {:.6f} {:.6f}",
                             point(0), point(1), point(2), normal(0), normal(1),
                             normal(2));
        } else {
            const Eigen::Vector3d &point = pointcloud->points_[i];
            utility::LogInfo("{:.6f} {:.6f} {:.6f}", point(0), point(1),
                             point(2));
        }
    }
    utility::LogInfo("End of the list.");
}

std::shared_ptr<geometry::PointCloud> pointcloud(new geometry::PointCloud);
int animation_step = 0;
std::chrono::steady_clock::time_point last_update_time;

bool AnimatePointCloud(visualization::Visualizer *visualizer) {
    if (!visualizer) return false;

    auto now = std::chrono::steady_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - last_update_time).count();
    if (animation_step < 10 && elapsed >= 2) {
        pointcloud->points_.push_back(Eigen::Vector3d(0.0, 0.0, animation_step + 1.0));
        pointcloud->points_.push_back(Eigen::Vector3d(1.0, 0.0, animation_step + 1.0));
        pointcloud->points_.push_back(Eigen::Vector3d(0.0, 1.0, animation_step + 1.0));
        
        PrintPointCloud(pointcloud);
        
        visualizer->UpdateGeometry(pointcloud);
        visualizer->UpdateRender();
        
        animation_step++;
        last_update_time = now;
    }

    return animation_step < 10;
}

int main(int argc, char *argv[]) {
    pointcloud->points_.push_back(Eigen::Vector3d(0.0, 0.0, 0.0));
    pointcloud->points_.push_back(Eigen::Vector3d(1.0, 0.0, 0.0));
    pointcloud->points_.push_back(Eigen::Vector3d(0.0, 1.0, 0.0));
    PrintPointCloud(pointcloud);

    visualization::Visualizer visualizer;
    visualizer.CreateVisualizerWindow("Open3D", 1600, 900);
    visualizer.AddGeometry(pointcloud);
    
    last_update_time = std::chrono::steady_clock::now();
    visualizer.RegisterAnimationCallback(AnimatePointCloud);
    
    visualizer.Run();
    visualizer.DestroyVisualizerWindow();

    return 0;
}

关键修改说明

  • 替换sleep为时间差判断:使用std::chrono记录上次更新时间,避免阻塞UI线程,保证窗口正常响应。
  • 移除回调内的Run()调用:主循环仅在main中调用一次,回调仅处理单次帧的更新逻辑。
  • 全局变量控制动画进度:通过animation_step跟踪当前动画阶段,确保每次回调仅执行一步更新,直到完成10次循环。
  • 回调返回值控制动画启停:返回true继续动画,返回false停止,符合Open3D回调的设计规范。

内容的提问来源于stack exchange,提问作者fghoussen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 19:10:34