open3dのメッシュを可視化するためのコードを纏めておく。
#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; } }
#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);