スポンサーリンク

VTK from Open3D (Mesh)

open3dのメッシュを可視化するためのコードを纏めておく。

vtkFromO3dMesh.hpp

#pragma once


#include <vtkTriangle.h>
#include <vtkProperty.h>
#include <vtkActor.h>


#include <open3d/Open3D.h>
#include <open3d/geometry/PointCloud.h>
#include <Eigen/Core>

#include "vtkFromO3dCommon.hpp"

namespace vtko3d {
    vtkSmartPointer<vtkPolyData> toMeshPolyData(const open3d::geometry::TriangleMesh& mesh, USEVALUE usedata, bool withpoints = false) {

        vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
        vtkSmartPointer<vtkCellArray> triangles = vtkSmartPointer<vtkCellArray>::New();
        vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New();

        // 色情報の配列
        vtkSmartPointer<vtkDoubleArray> colors = vtkSmartPointer<vtkDoubleArray>::New();
        colors->SetNumberOfComponents(3);
        colors->SetName("Colors");

        vtkSmartPointer<vtkDoubleArray> normals = vtkSmartPointer<vtkDoubleArray>::New();
        normals->SetNumberOfComponents(3);
        normals->SetName("Normals");

        for (size_t i = 0; i < mesh.vertices_.size(); ++i) {


            double x = mesh.vertices_[i].x();
            double y = mesh.vertices_[i].y();
            double z = mesh.vertices_[i].z();

            vtkIdType pid = points->InsertNextPoint(x, y, z);

            if (withpoints) {
                vertices->InsertNextCell(1, &pid);
            }


            if (usedata & POINT_RGB) {
                double r = mesh.vertex_colors_[i].x();
                double g = mesh.vertex_colors_[i].y();
                double b = mesh.vertex_colors_[i].z();
                colors->InsertNextTuple3(r, g, b); // 色情報追加
            }

            if (usedata & POINT_NORMAL) {
                double nx = mesh.vertex_normals_[i].x();
                double ny = mesh.vertex_normals_[i].y();
                double nz = mesh.vertex_normals_[i].z();
                normals->InsertNextTuple3(nx, ny, nz);
            }
        }

        //////////////////////////////////////////////////////////////////////
        for (size_t i = 0; i < mesh.triangles_.size(); ++i) {
            size_t p1 = mesh.triangles_[i](0);
            size_t p2 = mesh.triangles_[i](1);
            size_t p3 = mesh.triangles_[i](2);

            // 三角形1 (p1, p2, p3)
            vtkSmartPointer<vtkTriangle> tri = vtkSmartPointer<vtkTriangle>::New();
            tri->GetPointIds()->SetId(0, p1);
            tri->GetPointIds()->SetId(1, p2);
            tri->GetPointIds()->SetId(2, p3);
            triangles->InsertNextCell(tri);

        }



        // vtkPolyData の作成
        vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
        polyData->SetPoints(points);

        if (withpoints) {
            polyData->SetVerts(vertices);
        }
        polyData->SetPolys(triangles);  // 三角形セルを設定

        if(usedata & POINT_RGB) {
            polyData->GetPointData()->SetScalars(colors);
        }

        if (usedata & POINT_NORMAL) {
            polyData->GetPointData()->SetNormals(normals);
        }

        return polyData;

    }

    struct wireframe_option {
        bool show_faces = false;
        float line_width = 1.2f;
        std::array<double, 3> line_color = { 1.0, 1.0, 1.0 };
    };

    vtkSmartPointer<vtkActor> toMeshActor(
        vtkSmartPointer<vtkPolyDataMapper> mapper,
        bool usephong=false,
        std::optional<wireframe_option> wireopt = std::nullopt,
        std::optional< std::array<double, 3> > single_color = std::nullopt,
        int point_size = 5
    ) {

        vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
        actor->SetMapper(mapper);

        if (single_color.has_value()) {
            actor->GetProperty()->SetColor(single_color.value()[0], single_color.value()[1], single_color.value()[2]);
        }
        else {
            actor->GetProperty()->SetColor(1.0, 1.0, 1.0); // デフォルトは白色
        }

        vtkPolyData* poly = mapper->GetInput();
        if (poly->GetVerts()->GetNumberOfCells() > 0) {
            actor->GetProperty()->SetPointSize(point_size); // 点のサイズを設定
        }

        if (usephong) {
            actor->GetProperty()->SetInterpolationToPhong(); // またはSetInterpolationToGouraud()
        }

        if (wireopt.has_value()) {
            if (wireopt->show_faces) {
                actor->GetProperty()->SetRepresentationToSurface();
                actor->GetProperty()->EdgeVisibilityOn();
                actor->GetProperty()->SetEdgeColor( wireopt->line_color.data() ); // エッジ色
                actor->GetProperty()->SetLineWidth(wireopt->line_width);
            }
            else {
                actor->GetProperty()->SetRepresentationToWireframe();
                actor->GetProperty()->SetLineWidth(wireopt->line_width);

                actor->GetProperty()->SetLighting(false);
                actor->GetProperty()->BackfaceCullingOff();
                actor->GetProperty()->FrontfaceCullingOff();
            }
        }

        return actor;
    }

    // テスト用のメッシュを作成
    std::shared_ptr<open3d::geometry::TriangleMesh> createSampleMesh() {

        std::shared_ptr<open3d::geometry::TriangleMesh> mesh = std::make_shared<open3d::geometry::TriangleMesh>();

        int xcount = 20;
        int ycount = 20;
        float width = 1.0f;
        float height = 1.0f;
        float depth = 0.1f;
        float density = 10.0f;
        // 頂点の登録
        for (int i = 0; i < xcount; ++i) {
            for (int j = 0; j < ycount; ++j) {
                double x = -0.5 + 1.0 * i / (xcount - 1);
                double y = -0.5 + 1.0 * j / (ycount - 1);
                double z = sin(x * density) * depth + sin(y * density) * depth;
                mesh->vertices_.emplace_back(x, y, z);
                mesh->vertex_colors_.emplace_back(x + 0.5, y + 0.5, z + 0.5);

            }
        }

        // メッシュ(三角形)の作成
        for (int i = 0; i < xcount - 1; ++i) {
            for (int j = 0; j < ycount - 1; ++j) {
                // 四角形を2つの三角形に分割
                int p1 = i * ycount + j;       // 左下
                int p2 = (i + 1) * ycount + j; // 右下
                int p3 = i * ycount + (j + 1); // 左上
                int p4 = (i + 1) * ycount + (j + 1); // 右上

                mesh->triangles_.emplace_back(Eigen::Vector3i(p1, p2, p3));
                mesh->triangles_.emplace_back(Eigen::Vector3i(p2, p4, p3));

            }
        }

        return mesh;

    }

}

vtkFromO3dCommon.hpp

#pragma once

#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>

namespace vtko3d {

    enum USEVALUE {
        POINT_XYZ = 0b0001,
        POINT_RGB = 0b0010,
        POINT_NORMAL = 0b0100,
        POINT_RGBNORMAL = POINT_RGB | POINT_NORMAL,
    };


    vtkSmartPointer<vtkPolyDataMapper> toMapper(vtkSmartPointer<vtkPolyData> polydata) {
        auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
        mapper->SetInputData(polydata);
        return mapper;
    }
}

使用例

    auto mesh = vtko3d::createSampleMesh();
    mesh->ComputeVertexNormals(); // 法線ベクトルを計算
    auto polyData = vtko3d::toMeshPolyData(*mesh, vtko3d::POINT_RGBNORMAL,false);
    auto mapper = vtko3d::toMapper(polyData);
    auto actor = vtko3d::toMeshActor(mapper, true, vtko3d::wireframe_option{ false });

    auto renderer = vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor(actor);

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: