vtkEDLShadingを使うと簡単にEDLシェーダを使用できる。
#pragma warning(disable:4996) //VTK_MODULE_INITに必要 #include <vtkAutoInit.h> //必須 VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle); //////////////////////////////////////////////////////////// #include <vtkOpenGLRenderer.h> #include <vtkOpenGLRenderWindow.h> //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// #include <vtkRenderStepsPass.h> #include <vtkEDLShading.h> //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// #include <vtkSmartPointer.h> #include <vtkActor.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// #include <vtkConeSource.h> #include <vtkCubeSource.h> #include <vtkPlaneSource.h> #include <vtkProperty.h> #include <vtkSphere.h> #include <vtkSphereSource.h> #include <vtkPolyDataMapper.h> //////////////////////////////////////////////////////////// //#include <vtkCamera.h> #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "Psapi.lib") #pragma comment(lib, "Dbghelp.lib") #pragma comment(lib,"opengl32.lib") //////////////////////////////////////////////////////////// void SetTestData(vtkSmartPointer<vtkOpenGLRenderer> renderer); //////////////////////////////////////////////////////////// int main() { auto renderer = vtkSmartPointer<vtkOpenGLRenderer>::New(); auto window = vtkSmartPointer<vtkRenderWindow>::New(); window->AddRenderer(renderer); SetTestData(renderer); // 表示データの設定 renderer->ResetCamera();
// EDL シェーダの設定 auto basicPasses = vtkSmartPointer<vtkRenderStepsPass>::New(); auto edl = vtkSmartPointer<vtkEDLShading>::New(); edl->SetDelegatePass(basicPasses); // renderer に EDL を適用 renderer->SetPass(edl); // マルチサンプリングオフ。EDL とは相性が悪い。深度バッファの計算が正しく行われないため。 window->SetMultiSamples(0);
// ウィンドウサイズ window->SetSize(800, 600); auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); window->SetInteractor(interactor); interactor->Initialize(); window->Render(); interactor->Start(); return 0; } void SetTestData(vtkSmartPointer<vtkOpenGLRenderer> renderer) { { auto planeSource = vtkSmartPointer<vtkPlaneSource>::New(); planeSource->SetOrigin(-5.0, 0.0, -5.0); planeSource->SetPoint1(5.0, 0.0, -5.0); planeSource->SetPoint2(-5.0, 0.0, 5.0); planeSource->SetResolution(50, 50); planeSource->Update(); planeSource->SetCenter(0.0, -5.0, 0.0); auto planeMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); planeMapper->SetInputConnection(planeSource->GetOutputPort()); auto planeActor = vtkSmartPointer<vtkActor>::New(); planeActor->SetMapper(planeMapper); planeActor->GetProperty()->SetColor(0.8, 0.8, 0.8); // 薄いグレー planeActor->GetProperty()->SetSpecular(0.1); planeActor->GetProperty()->SetDiffuse(0.9); renderer->AddActor(planeActor); } for (int i = 0; i < 10; i++) { // x,y,zを乱数で生成 double x, y, z; x = (-0.5 + rand() / double(RAND_MAX)) * 10; y = (-0.5 + rand() / double(RAND_MAX)) * 10; z = (-0.5 + rand() / double(RAND_MAX)) * 10; auto sphereSource = vtkSmartPointer<vtkSphereSource>::New(); sphereSource->SetCenter(-2.0, 1.0, 0.0); // 床から1.0上に sphereSource->SetRadius(1.0); sphereSource->SetThetaResolution(30); sphereSource->SetPhiResolution(30); sphereSource->Update(); sphereSource->SetCenter(x, y, z); auto sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); sphereMapper->SetInputConnection(sphereSource->GetOutputPort()); auto sphereActor = vtkSmartPointer<vtkActor>::New(); sphereActor->SetMapper(sphereMapper); sphereActor->GetProperty()->SetColor(1.0, 0.2, 0.2); // 赤っぽい色 renderer->AddActor(sphereActor); } for (int i = 0; i < 10; i++) { // x,y,zを乱数で生成 double x, y, z; x = (-0.5 + rand() / double(RAND_MAX)) * 10; y = (-0.5 + rand() / double(RAND_MAX)) * 10; z = (-0.5 + rand() / double(RAND_MAX)) * 10; auto coneSource = vtkSmartPointer<vtkConeSource>::New(); coneSource->SetCenter(2.0, 0.0, 0.0); coneSource->SetRadius(1.0); coneSource->SetHeight(2.5); coneSource->SetDirection(0.0, 1.0, 0.0); // Y軸方向に伸ばす coneSource->SetResolution(30); coneSource->Update(); coneSource->SetCenter(x, y, z); auto coneMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); coneMapper->SetInputConnection(coneSource->GetOutputPort()); auto coneActor = vtkSmartPointer<vtkActor>::New(); coneActor->SetMapper(coneMapper); coneActor->GetProperty()->SetColor(0.2, 0.4, 1.0); // 青系 renderer->AddActor(coneActor); } for (int i = 0; i < 10; i++) { // x,y,zを乱数で生成 double x, y, z; x = (-0.5 + rand() / double(RAND_MAX)) * 10; y = (-0.5 + rand() / double(RAND_MAX)) * 10; z = (-0.5 + rand() / double(RAND_MAX)) * 10; auto cubeSource = vtkSmartPointer<vtkCubeSource>::New(); cubeSource->SetCenter(0.0, 1.0, 2.0); cubeSource->SetXLength(1.5); cubeSource->SetYLength(1.5); cubeSource->SetZLength(1.5); cubeSource->Update(); cubeSource->SetCenter(x, y, z); auto cubeMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); cubeMapper->SetInputConnection(cubeSource->GetOutputPort()); auto cubeActor = vtkSmartPointer<vtkActor>::New(); cubeActor->SetMapper(cubeMapper); cubeActor->GetProperty()->SetColor(0.2, 1.0, 0.2); // 緑系 renderer->AddActor(cubeActor); } }
メッシュ1の頂点からメッシュ2の頂点を探索し、最も近い頂点への距離をスカラー値としてVTKに登録して、カラーテーブルを指定して着色する。
#include <iostream> //VTK_MODULE_INITに必要 #include <vtkAutoInit.h> #include <vtkSmartPointer.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> //円筒とその表示に必要 #include <vtkPointData.h> #include <vtkCellData.h> #include <vtkPolyData.h> #include <vtkActor.h> #include <vtkPolyDataMapper.h> #include <vtkLookupTable.h> #include <vtkFloatArray.h> #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"psapi.lib") #pragma comment(lib,"dbghelp.lib") #pragma comment(lib,"ws2_32.lib") #include <vtkCellArray.h> #include <vtkTriangle.h> #include <open3d/Open3D.h> #include <open3d/geometry/PointCloud.h> #include <open3d/geometry/TriangleMesh.h> // kdtree #include <open3d/geometry/KDTreeFlann.h> #pragma comment(lib,"Open3D.lib") //必須 VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle);
// baseの各頂点に対して、targetの最も近い頂点までの距離を計算する std::vector<double> calcNearestPoint(std::shared_ptr<open3d::geometry::TriangleMesh> base, std::shared_ptr<open3d::geometry::TriangleMesh> target) { std::vector<double> ret; // mymeshの頂点のkd-treeを作成 open3d::geometry::KDTreeFlann kdtree; kdtree.SetGeometry(*target); // 頂点Pに最も近い頂点を探す std::vector<double> distances; std::vector<int> indices; for (auto& p : base->vertices_) { int count = kdtree.SearchKNN(p,1,indices,distances); double distance = sqrt(distances[0]); ret.push_back(distance); } return ret; }
// テストデータを作成 void CreateMeshData_o3d_1(std::shared_ptr<open3d::geometry::TriangleMesh> mymesh, int xcount, int ycount, float width, float height,float offsetz, float depth, float density) { // 頂点の登録 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 + offsetz; mymesh->vertices_.push_back(Eigen::Vector3d(x * width, y * height, z)); } } // メッシュ(三角形)の作成 for (int i = 0; i < xcount - 1; ++i) { for (int j = 0; j < ycount - 1; ++j) { // 四角形を2つの三角形に分割 const int p1 = i * ycount + j; // 左下 const int p2 = (i + 1) * ycount + j; // 右下 const int p3 = i * ycount + (j + 1); // 左上 const int p4 = (i + 1) * ycount + (j + 1); // 右上 // 三角形1 (p1, p2, p3) mymesh->triangles_.push_back(Eigen::Vector3i(p1, p2, p3)); // 三角形2 (p2, p4, p3) mymesh->triangles_.push_back(Eigen::Vector3i(p2, p4, p3)); } } }
struct MeshData { std::shared_ptr<open3d::geometry::TriangleMesh> curve; std::shared_ptr<open3d::geometry::TriangleMesh> flat; }; MeshData createData(int xcount,int ycount) { std::shared_ptr<open3d::geometry::TriangleMesh> mymesh1 = std::make_shared<open3d::geometry::TriangleMesh>(); std::shared_ptr<open3d::geometry::TriangleMesh> mymesh2 = std::make_shared<open3d::geometry::TriangleMesh>(); CreateMeshData_o3d_1(mymesh1, xcount, ycount, 2, 2, 0.0, 0.1, 10); CreateMeshData_o3d_1(mymesh2, xcount, ycount, 2, 2,-0.3, 0.05, 17); return MeshData{ mymesh1,mymesh2 }; }
vtkSmartPointer<vtkPolyData> CreateVTKMeshData(std::shared_ptr<open3d::geometry::TriangleMesh> tri,int xcount,int ycount) { vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkCellArray> triangles = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New(); for(auto& p : tri->vertices_) { vtkIdType pid = points->InsertNextPoint(p.x(), p.y(), p.z()); vertices->InsertNextCell(1, &pid); } // メッシュ(三角形)の作成 for (int i = 0; i < xcount - 1; ++i) { for (int j = 0; j < ycount - 1; ++j) { // 四角形を2つの三角形に分割 vtkIdType p1 = i * ycount + j; // 左下 vtkIdType p2 = (i + 1) * ycount + j; // 右下 vtkIdType p3 = i * ycount + (j + 1); // 左上 vtkIdType p4 = (i + 1) * ycount + (j + 1); // 右上 // 三角形1 (p1, p2, p3) vtkSmartPointer<vtkTriangle> triangle1 = vtkSmartPointer<vtkTriangle>::New(); triangle1->GetPointIds()->SetId(0, p1); triangle1->GetPointIds()->SetId(1, p2); triangle1->GetPointIds()->SetId(2, p3); triangles->InsertNextCell(triangle1); // 三角形2 (p2, p4, p3) vtkSmartPointer<vtkTriangle> triangle2 = vtkSmartPointer<vtkTriangle>::New(); triangle2->GetPointIds()->SetId(0, p2); triangle2->GetPointIds()->SetId(1, p4); triangle2->GetPointIds()->SetId(2, p3); triangles->InsertNextCell(triangle2); } } // vtkPolyData の作成 vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New(); polyData->SetPoints(points); polyData->SetPolys(triangles); // 三角形セルを設定 return polyData; }
vtkSmartPointer<vtkActor> createActor(vtkSmartPointer<vtkPolyData> polyData, vtkSmartPointer<vtkLookupTable> table,double min_,double max_ ) { vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputData(polyData); if( table != nullptr) { mapper->SetLookupTable(table); mapper->SetScalarRange(min_, max_); mapper->SetInterpolateScalarsBeforeMapping(true); } vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); actor->SetMapper(mapper); return actor; }
//! @brief サーモグラフィー風のカラールックアップテーブルを生成する //! @param [in] scalar_min スカラー値の最小値 //! @param [in] scalar_max スカラー値の最大値 //! @param [in] division スカラー値の範囲を何分割するか //! @return カラールックアップテーブル vtkSmartPointer<vtkLookupTable> ThermographyColorTable(const double scalar_min, const double scalar_max, const int division) { vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New(); lut->SetNumberOfTableValues(division); // テーブルの要素数を設定 lut->SetTableRange(scalar_min, scalar_max); // スカラー値の範囲を設定 lut->Build(); // テーブルの i 番目の要素に対応する色を設定 for (int i = 0; i < division; i++) { double t = static_cast<double>(i) / float(division - 1); double r, g, b; if (t < 0.33) { // 青から緑への補間 double factor = t / 0.33; r = 0.0; g = factor; b = 1.0 - factor; } else if (t < 0.66) { // 緑から黄への補間 double factor = (t - 0.33) / 0.33; r = factor; g = 1.0; b = 0.0; } else { // 黄から赤への補間 double factor = (t - 0.66) / 0.34; r = 1.0; g = 1.0 - factor; b = 0.0; } // テーブルの i 番目の要素に色を設定 lut->SetTableValue( i // テーブルの要素番号 , r, g, b, 1.0 ); } return lut; }
int main(int /*argc*/, char** /*argv*/) { auto meshes = createData(100, 100); std::vector<double> scalar = calcNearestPoint(meshes.curve, meshes.flat); vtkSmartPointer<vtkPolyData> curve = CreateVTKMeshData(meshes.curve, 100, 100); vtkSmartPointer<vtkPolyData> flat = CreateVTKMeshData(meshes.flat, 100, 100); // scalarをvtkFloatArrayに変換 vtkSmartPointer<vtkFloatArray> scalars = vtkSmartPointer<vtkFloatArray>::New(); scalars->SetName("MyScalarValues"); double _min = *std::min_element(scalar.begin(), scalar.end()); double _max = *std::max_element(scalar.begin(), scalar.end()); for (auto& s : scalar) { scalars->InsertNextValue(s); } curve->GetPointData()->AddArray(scalars); curve->GetPointData()->SetActiveScalars("MyScalarValues"); vtkSmartPointer<vtkLookupTable> colortable = ThermographyColorTable(_min, _max, 100); vtkSmartPointer<vtkActor> actor1 = createActor(curve, colortable,_min,_max); vtkSmartPointer<vtkActor> actor2 = createActor(flat,nullptr,0,0); ////////////////////////////////////// auto renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->AddActor(actor1); renderer->AddActor(actor2); renderer->ResetCamera(); ////////////////////////////////////// auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); ////////////////////////////////////// auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); renderWindow->SetInteractor(interactor); renderWindow->Render(); interactor->Start(); //イベントループへ入る return 0; }
#include <iostream> //VTK_MODULE_INITに必要 #include <vtkAutoInit.h> #include <vtkSmartPointer.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkPointData.h> #include <vtkCellData.h> #include <vtkPolyData.h> #include <vtkActor.h> #include <vtkPolyDataMapper.h> #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"psapi.lib") #pragma comment(lib,"dbghelp.lib") #pragma comment(lib,"ws2_32.lib") #include <vtkCellArray.h> #include <vtkTriangle.h> //必須 VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle);
vtkSmartPointer<vtkPolyData> CreateMeshData(bool cloudonly,int xcount, int ycount,float width,float height,float depth,float density) { vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkCellArray> triangles = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New(); // 頂点の登録 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; vtkIdType pid = points->InsertNextPoint(x*width, y*height, z); if (cloudonly == true) { vertices->InsertNextCell(1, &pid); } } } if (cloudonly == true) { vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New(); polyData->SetPoints(points); polyData->SetVerts(vertices); return polyData; } // メッシュ(三角形)の作成 for (int i = 0; i < xcount - 1; ++i) { for (int j = 0; j < ycount - 1; ++j) { // 四角形を2つの三角形に分割 vtkIdType p1 = i * ycount + j; // 左下 vtkIdType p2 = (i + 1) * ycount + j; // 右下 vtkIdType p3 = i * ycount + (j + 1); // 左上 vtkIdType p4 = (i + 1) * ycount + (j + 1); // 右上 // 三角形1 (p1, p2, p3) vtkSmartPointer<vtkTriangle> triangle1 = vtkSmartPointer<vtkTriangle>::New(); triangle1->GetPointIds()->SetId(0, p1); triangle1->GetPointIds()->SetId(1, p2); triangle1->GetPointIds()->SetId(2, p3); triangles->InsertNextCell(triangle1); // 三角形2 (p2, p4, p3) vtkSmartPointer<vtkTriangle> triangle2 = vtkSmartPointer<vtkTriangle>::New(); triangle2->GetPointIds()->SetId(0, p2); triangle2->GetPointIds()->SetId(1, p4); triangle2->GetPointIds()->SetId(2, p3); triangles->InsertNextCell(triangle2); } } // vtkPolyData の作成 vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New(); polyData->SetPoints(points); polyData->SetPolys(triangles); // 三角形セルを設定 return polyData; }
int main(int /*argc*/, char** /*argv*/) { vtkSmartPointer<vtkPolyData> polyData = CreateMeshData(false,500, 500,2,2,0.1,10); vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputData(polyData); actor->SetMapper(mapper); ////////////////////////////////////// auto renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->AddActor(actor); renderer->ResetCamera(); ////////////////////////////////////// auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); ////////////////////////////////////// auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); renderWindow->SetInteractor(interactor); renderWindow->Render(); interactor->Start(); //イベントループへ入る return 0; }