오픈 소스 도구를 사용한 3D 데이터 시각화: VTK를 사용한 자습서
게시 됨: 2022-03-11Toptal의 블로그에 대한 최근 기사에서 숙련된 데이터 과학자 Charles Cook은 오픈 소스 도구를 사용한 과학 컴퓨팅에 대해 썼습니다. 그의 튜토리얼은 오픈 소스 도구와 데이터를 쉽게 처리하고 결과를 얻는 데 있어 도구가 할 수 있는 역할에 대해 중요한 점을 설명합니다.
그러나 이러한 복잡한 미분 방정식을 모두 풀자 마자 또 다른 문제가 발생합니다. 이러한 시뮬레이션에서 나오는 엄청난 양의 데이터를 어떻게 이해하고 해석합니까? 대규모 시뮬레이션 내에서 수백만 개의 그리드 포인트가 있는 데이터와 같은 잠재적인 기가바이트의 데이터를 시각화하는 방법은 무엇입니까?
석사 학위 논문의 유사한 문제에 대한 작업을 하는 동안 데이터 시각화에 특화된 강력한 그래픽 라이브러리인 Visualization Toolkit 또는 VTK를 접하게 되었습니다.
이 튜토리얼에서는 VTK와 그 파이프라인 아키텍처에 대해 간략히 소개하고 임펠러 펌프에서 시뮬레이션된 유체의 데이터를 사용하는 실제 3D 시각화 예제에 대해 논의할 것입니다. 마지막으로 라이브러리의 장점과 내가 만난 단점을 나열하겠습니다.
데이터 시각화 및 VTK 파이프라인
오픈 소스 라이브러리 VTK에는 정교한 시각화 알고리즘이 많이 포함된 견고한 처리 및 렌더링 파이프라인이 포함되어 있습니다. 그러나 시간이 지남에 따라 이미지 및 메쉬 처리 알고리즘도 추가되었으므로 기능은 여기서 그치지 않습니다. 치과 연구 회사와의 현재 프로젝트에서 Qt 기반 CAD와 유사한 응용 프로그램 내에서 메쉬 기반 처리 작업에 VTK를 활용하고 있습니다. VTK 사례 연구는 광범위한 적합한 애플리케이션을 보여줍니다.
VTK의 아키텍처는 강력한 파이프라인 개념을 중심으로 합니다. 이 개념의 기본 개요는 다음과 같습니다.
- 소스 는 파이프라인의 맨 처음에 있으며 "무에서 나온 것"을 만듭니다. 예를 들어,
vtkConeSource
는 3D 원뿔을 생성하고vtkSTLReader
는*.stl
3D 지오메트리 파일을 읽습니다. - 필터 는 소스 또는 다른 필터의 출력을 새로운 것으로 변환합니다. 예를 들어
vtkCutter
는 암시적 함수(예: 평면)를 사용하여 알고리즘에서 이전 객체의 출력을 자릅니다. VTK와 함께 제공되는 모든 처리 알고리즘은 필터로 구현되며 함께 자유롭게 연결할 수 있습니다. - 매퍼 는 데이터를 그래픽 프리미티브로 변환합니다. 예를 들어, 과학 데이터를 색칠하기 위한 조회 테이블을 지정하는 데 사용할 수 있습니다. 표시할 항목을 지정하는 추상적인 방법입니다.
- 액터 는 장면 내의 객체(기하학 및 디스플레이 속성)를 나타냅니다. 색상, 불투명도, 음영 또는 방향과 같은 항목이 여기에 지정됩니다.
- Renderers & Windows 는 마침내 플랫폼에 독립적인 방식으로 화면에 렌더링을 설명합니다.
일반적인 VTK 렌더링 파이프라인은 하나 이상의 소스로 시작하여 다양한 필터를 사용하여 여러 출력 개체로 처리한 다음 매퍼와 액터를 사용하여 별도로 렌더링됩니다. 이 개념의 힘은 업데이트 메커니즘입니다. 필터 또는 소스의 설정이 변경되면 모든 종속 필터, 매퍼, 액터 및 렌더링 창이 자동으로 업데이트됩니다. 반면에 파이프라인 아래에 있는 개체가 작업을 수행하기 위해 정보가 필요한 경우 쉽게 얻을 수 있습니다.
또한 OpenGL과 같은 렌더링 시스템을 직접 다룰 필요가 없습니다. VTK는 플랫폼 및 (부분적으로) 렌더링 시스템 독립적인 방식으로 모든 저수준 작업을 캡슐화합니다. 개발자는 훨씬 더 높은 수준에서 작업합니다.
로터 펌프 데이터세트가 있는 코드 예
IEEE Visualization Contest 2011에서 회전 임펠러 펌프의 유체 흐름 데이터 세트를 사용하는 데이터 시각화 예제를 살펴보겠습니다. 데이터 자체는 Charles Cook의 기사에서 설명한 것과 매우 유사한 전산 유체 역학 시뮬레이션의 결과입니다.
주요 펌프의 압축 시뮬레이션 데이터는 크기가 30GB 이상입니다. 여러 부분과 여러 시간 단계를 포함하므로 크기가 큽니다. 이 가이드에서는 압축된 크기가 약 150MB인 이러한 시간 단계 중 하나의 로터 부분을 가지고 놀 것입니다.
VTK를 사용하기 위해 선택한 언어는 C++이지만 Tcl/Tk, Java 및 Python과 같은 다른 여러 언어에 대한 매핑이 있습니다. 대상이 단일 데이터 세트의 시각화일 경우 코드를 전혀 작성할 필요가 없으며 대신 대부분의 VTK 기능에 대한 그래픽 프론트 엔드인 Paraview를 사용할 수 있습니다.
데이터 세트와 64비트가 필요한 이유
Paraview에서 하나의 타임스텝을 열고 로터 부분을 별도의 파일로 추출하여 위에 제공된 30GB 데이터 세트에서 로터 데이터 세트를 추출했습니다. 정육면체, 사면체 등과 같이 점과 3D 셀로 구성된 3D 볼륨인 비정형 그리드 파일입니다. 각 3D 점에는 연관된 값이 있습니다. 때로는 셀에 연관된 값도 있지만 이 경우에는 그렇지 않습니다. 이 교육은 지점의 압력과 속도에 집중하고 3D 컨텍스트에서 이를 시각화하려고 합니다.
압축 파일 크기는 약 150MB이고 메모리 내 크기는 VTK로 로드할 때 약 280MB입니다. 그러나 VTK에서 처리하면 데이터 세트가 VTK 파이프라인 내에서 여러 번 캐시되고 32비트 프로그램의 경우 2GB 메모리 제한에 빠르게 도달합니다. VTK를 사용할 때 메모리를 절약하는 방법이 있지만 간단하게 유지하기 위해 예제를 64비트로 컴파일하고 실행합니다.
감사 의 말: 데이터 세트는 독일 클라우스탈 대학교 응용 역학 연구소(Dipl. Wirtsch.-Ing. Andreas Lucius)에서 제공한 것입니다.
목표
VTK를 도구로 사용하여 달성할 것은 아래 이미지에 표시된 시각화입니다. 3D 컨텍스트로 데이터세트의 윤곽이 부분적으로 투명한 와이어프레임 렌더링을 사용하여 표시됩니다. 그런 다음 데이터 세트의 왼쪽 부분은 표면의 간단한 색상 코딩을 사용하여 압력을 표시하는 데 사용됩니다. (이 예에서는 더 복잡한 볼륨 렌더링을 건너뛸 것입니다.) 속도 필드를 시각화하기 위해 데이터 세트의 오른쪽 부분은 속도의 크기에 따라 색상으로 구분된 유선으로 채워집니다. 이 시각화 선택은 기술적으로 이상적이지 않지만 VTK 코드를 가능한 한 단순하게 유지하고 싶었습니다. 또한 이 예가 시각화 문제의 일부인 이유가 있습니다. 즉, 흐름의 난류가 많습니다.
단계별로
VTK 코드를 단계별로 논의하여 각 단계에서 렌더링 출력이 어떻게 보이는지 보여줍니다. 전체 소스 코드는 교육이 끝나면 다운로드할 수 있습니다.
VTK에서 필요한 모든 것을 포함하고 기본 기능을 여는 것으로 시작하겠습니다.
#include <vtkActor.h> #include <vtkArrayCalculator.h> #include <vtkCamera.h> #include <vtkClipDataSet.h> #include <vtkCutter.h> #include <vtkDataSetMapper.h> #include <vtkInteractorStyleTrackballCamera.h> #include <vtkLookupTable.h> #include <vtkNew.h> #include <vtkPlane.h> #include <vtkPointData.h> #include <vtkPointSource.h> #include <vtkPolyDataMapper.h> #include <vtkProperty.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkRibbonFilter.h> #include <vtkStreamTracer.h> #include <vtkSmartPointer.h> #include <vtkUnstructuredGrid.h> #include <vtkXMLUnstructuredGridReader.h> int main(int argc, char** argv) {
다음으로 결과를 표시하기 위해 렌더러와 렌더 창을 설정합니다. 배경색과 렌더 창 크기를 설정합니다.
// Setup the renderer vtkNew<vtkRenderer> renderer; renderer->SetBackground(0.9, 0.9, 0.9); // Setup the render window vtkNew<vtkRenderWindow> renWin; renWin->AddRenderer(renderer.Get()); renWin->SetSize(500, 500);
이 코드를 사용하면 이미 정적 렌더링 창을 표시할 수 있습니다. 대신 장면을 대화식으로 회전, 확대/축소 및 팬하기 위해 vtkRenderWindowInteractor
를 추가하기로 결정했습니다.
// Setup the render window interactor vtkNew<vtkRenderWindowInteractor> interact; vtkNew<vtkInteractorStyleTrackballCamera> style; interact->SetRenderWindow(renWin.Get()); interact->SetInteractorStyle(style.Get());
이제 회색의 빈 렌더링 창을 보여주는 실행 중인 예제가 있습니다.
다음으로 VTK와 함께 제공되는 많은 판독기 중 하나를 사용하여 데이터 세트를 로드합니다.
// Read the file vtkSmartPointer<vtkXMLUnstructuredGridReader> pumpReader = vtkSmartPointer<vtkXMLUnstructuredGridReader>::New(); pumpReader->SetFileName("rotor.vtu");
VTK 메모리 관리에 대한 간략한 설명: VTK는 참조 카운팅을 중심으로 하는 편리한 자동 메모리 관리 개념을 사용합니다. 그러나 대부분의 다른 구현과 달리 참조 카운트는 스마트 포인터 클래스 대신 VTK 개체 자체 내에서 유지됩니다. 이것은 VTK 개체가 원시 포인터로 전달되더라도 참조 횟수를 늘릴 수 있다는 이점이 있습니다. 관리되는 VTK 개체를 만드는 두 가지 주요 방법이 있습니다. vtkNew<T>
및 vtkSmartPointer<T>::New()
, 주요 차이점은 vtkSmartPointer<T>
가 원시 포인터 T*
에 대해 암시적으로 캐스트 가능하고 함수에서 반환될 수 있다는 것입니다. vtkNew<T>
인스턴스의 경우 원시 포인터를 얻기 위해 .Get()
을 호출해야 하며 vtkSmartPointer
로 래핑해야만 반환할 수 있습니다. 이 예에서는 함수에서 반환하지 않고 모든 개체가 항상 살아 있으므로 짧은 vtkNew
를 사용하고 데모 목적으로만 위의 예외를 사용합니다.
이 시점에서 아직 파일에서 아무 것도 읽지 않았습니다. 우리나 더 아래에 있는 필터는 파일 읽기가 실제로 발생하려면 Update()
를 호출해야 합니다. 일반적으로 VTK 클래스가 업데이트를 자체적으로 처리하도록 하는 것이 가장 좋은 방법입니다. 그러나 예를 들어 이 데이터 세트의 압력 범위를 가져오기 위해 필터 결과에 직접 액세스하려는 경우가 있습니다. 그런 다음 Update()
를 수동으로 호출해야 합니다. (결과가 캐시되므로 Update()
를 여러 번 호출해도 성능이 저하되지 않습니다.)
// Get the pressure range pumpReader->Update(); double pressureRange[2]; pumpReader->GetOutput()->GetPointData()->GetArray("Pressure")->GetRange(pressureRange);
다음으로 vtkClipDataSet
을 사용하여 데이터 세트의 왼쪽 절반을 추출해야 합니다. 이를 달성하기 위해 먼저 분할을 정의하는 vtkPlane
을 정의합니다. 그런 다음, VTK 파이프라인이 어떻게 함께 연결되는지 처음으로 볼 것입니다: successor->SetInputConnection(predecessor->GetOutputPort())
. clipperLeft
에서 업데이트를 요청할 때마다 이 연결은 이제 이전의 모든 필터도 최신 상태인지 확인합니다.
// Clip the left part from the input vtkNew<vtkPlane> planeLeft; planeLeft->SetOrigin(0.0, 0.0, 0.0); planeLeft->SetNormal(-1.0, 0.0, 0.0); vtkNew<vtkClipDataSet> clipperLeft; clipperLeft->SetInputConnection(pumpReader->GetOutputPort()); clipperLeft->SetClipFunction(planeLeft.Get());
마지막으로 첫 번째 액터와 매퍼를 만들어 왼쪽 절반의 와이어프레임 렌더링을 표시합니다. 매퍼는 필터가 서로에 대해 정확히 동일한 방식으로 해당 필터에 연결되어 있습니다. 대부분의 경우 렌더러 자체가 모든 액터, 매퍼 및 기본 필터 체인의 업데이트를 트리거합니다!
자명하지 않은 유일한 줄은 아마도 leftWireMapper->ScalarVisibilityOff();
- 현재 활성 배열로 설정된 압력 값에 의한 와이어프레임의 색상 지정을 금지합니다.
// Create the wireframe representation for the left part vtkNew<vtkDataSetMapper> leftWireMapper; leftWireMapper->SetInputConnection(clipperLeft->GetOutputPort()); leftWireMapper->ScalarVisibilityOff(); vtkNew<vtkActor> leftWireActor; leftWireActor->SetMapper(leftWireMapper.Get()); leftWireActor->GetProperty()->SetRepresentationToWireframe(); leftWireActor->GetProperty()->SetColor(0.8, 0.8, 0.8); leftWireActor->GetProperty()->SetLineWidth(0.5); leftWireActor->GetProperty()->SetOpacity(0.8); renderer->AddActor(leftWireActor.Get());
이 시점에서 렌더 창은 마침내 무언가, 즉 왼쪽 부분의 와이어프레임을 보여줍니다.

오른쪽 부분에 대한 와이어프레임 렌더링은 (새로 생성된) vtkClipDataSet
의 평면 법선을 반대 방향으로 전환하고 (새로 생성된) 매퍼와 액터의 색상과 불투명도를 약간 변경하여 비슷한 방식으로 생성됩니다. 여기서 VTK 파이프라인은 동일한 입력 데이터 세트에서 두 방향(오른쪽 및 왼쪽)으로 분할됩니다.
// Clip the right part from the input vtkNew<vtkPlane> planeRight; planeRight->SetOrigin(0.0, 0.0, 0.0); planeRight->SetNormal(1.0, 0.0, 0.0); vtkNew<vtkClipDataSet> clipperRight; clipperRight->SetInputConnection(pumpReader->GetOutputPort()); clipperRight->SetClipFunction(planeRight.Get()); // Create the wireframe representation for the right part vtkNew<vtkDataSetMapper> rightWireMapper; rightWireMapper->SetInputConnection(clipperRight->GetOutputPort()); rightWireMapper->ScalarVisibilityOff(); vtkNew<vtkActor> rightWireActor; rightWireActor->SetMapper(rightWireMapper.Get()); rightWireActor->GetProperty()->SetRepresentationToWireframe(); rightWireActor->GetProperty()->SetColor(0.2, 0.2, 0.2); rightWireActor->GetProperty()->SetLineWidth(0.5); rightWireActor->GetProperty()->SetOpacity(0.1); renderer->AddActor(rightWireActor.Get());
이제 출력 창에 예상대로 두 와이어프레임 부분이 모두 표시됩니다.
이제 유용한 데이터를 시각화할 준비가 되었습니다! 왼쪽 부분에 압력 시각화를 추가하기 위해 많은 작업을 수행할 필요가 없습니다. 새 매퍼를 만들어 clipperLeft
에도 연결하지만 이번에는 압력 배열로 색상을 지정합니다. 여기에서 위에서 도출한 pressureRange
를 마침내 활용합니다.
// Create the pressure representation for the left part vtkNew<vtkDataSetMapper> pressureColorMapper; pressureColorMapper->SetInputConnection(clipperLeft->GetOutputPort()); pressureColorMapper->SelectColorArray("Pressure"); pressureColorMapper->SetScalarRange(pressureRange); vtkNew<vtkActor> pressureColorActor; pressureColorActor->SetMapper(pressureColorMapper.Get()); pressureColorActor->GetProperty()->SetOpacity(0.5); renderer->AddActor(pressureColorActor.Get());
이제 출력이 아래 표시된 이미지와 같이 표시됩니다. 중간의 압력이 매우 낮아 재료를 펌프로 빨아들입니다. 그런 다음이 물질은 외부로 운반되어 빠르게 압력을 얻습니다. (물론 실제 값이 포함된 색상 맵 범례가 있어야 하지만 예제를 더 짧게 유지하기 위해 생략했습니다.)
이제 더 까다로운 부분이 시작됩니다. 오른쪽 부분에 속도 유선을 그리고 싶습니다. 유선은 소스 포인트에서 벡터 필드 내 통합에 의해 생성됩니다. 벡터 필드는 이미 "Velocity" 벡터 배열 형태의 데이터 세트의 일부입니다. 따라서 소스 포인트만 생성하면 됩니다. vtkPointSource
는 임의의 점 구를 생성합니다. 1500개의 소스 포인트를 생성할 것입니다. 대부분이 데이터 세트 내에 있지 않고 스트림 추적 프로그램에서 무시되기 때문입니다.
// Create the source points for the streamlines vtkNew<vtkPointSource> pointSource; pointSource->SetCenter(0.0, 0.0, 0.015); pointSource->SetRadius(0.2); pointSource->SetDistributionToUniform(); pointSource->SetNumberOfPoints(1500);
다음으로 스트림 트레이서를 생성하고 입력 연결을 설정합니다. "잠깐, 여러 연결이 있습니까?"라고 말할 수 있습니다. 예 - 이것은 여러 입력이 있는 첫 번째 VTK 필터입니다. 일반 입력 연결은 벡터 필드에 사용되며 소스 연결은 시드 포인트에 사용됩니다. "Velocity"는 clipperRight
의 "활성" 벡터 배열이므로 여기에서 명시적으로 지정할 필요가 없습니다. 마지막으로 통합이 시드 포인트에서 양방향으로 수행되어야 한다고 지정하고 통합 방법을 Runge-Kutta-4.5로 설정합니다.
vtkNew<vtkStreamTracer> tracer; tracer->SetInputConnection(clipperRight->GetOutputPort()); tracer->SetSourceConnection(pointSource->GetOutputPort()); tracer->SetIntegrationDirectionToBoth(); tracer->SetIntegratorTypeToRungeKutta45();
다음 문제는 속도 크기로 유선형을 색칠하는 것입니다. 벡터의 크기에 대한 배열이 없기 때문에 단순히 크기를 새 스칼라 배열로 계산합니다. 짐작했듯이 이 작업에도 VTK 필터가 있습니다. vtkArrayCalculator
. 데이터 세트를 가져와 변경하지 않고 출력하지만 하나 이상의 기존 배열에서 계산된 정확히 하나의 배열을 추가합니다. "Velocity" 벡터의 크기를 취하여 "MagVelocity"로 출력하도록 이 배열 계산기를 구성합니다. 마지막으로 새 배열의 범위를 파생시키기 위해 Update()
를 수동으로 다시 호출합니다.
// Compute the velocity magnitudes and create the ribbons vtkNew<vtkArrayCalculator> magCalc; magCalc->SetInputConnection(tracer->GetOutputPort()); magCalc->AddVectorArrayName("Velocity"); magCalc->SetResultArrayName("MagVelocity"); magCalc->SetFunction("mag(Velocity)"); magCalc->Update(); double magVelocityRange[2]; magCalc->GetOutput()->GetPointData()->GetArray("MagVelocity")->GetRange(magVelocityRange);
vtkStreamTracer
는 폴리라인을 직접 출력하고 vtkArrayCalculator
는 폴리라인을 변경하지 않고 전달합니다. 따라서 새로운 매퍼와 액터를 사용하여 magCalc
의 출력을 직접 표시할 수 있습니다.
대신 이 교육에서는 대신 리본을 표시하여 출력을 좀 더 멋지게 만들기로 했습니다. vtkRibbonFilter
는 입력의 모든 폴리라인에 대한 리본을 표시하는 2D 셀을 생성합니다.
// Create and render the ribbons vtkNew<vtkRibbonFilter> ribbonFilter; ribbonFilter->SetInputConnection(magCalc->GetOutputPort()); ribbonFilter->SetWidth(0.0005); vtkNew<vtkPolyDataMapper> streamlineMapper; streamlineMapper->SetInputConnection(ribbonFilter->GetOutputPort()); streamlineMapper->SelectColorArray("MagVelocity"); streamlineMapper->SetScalarRange(magVelocityRange); vtkNew<vtkActor> streamlineActor; streamlineActor->SetMapper(streamlineMapper.Get()); renderer->AddActor(streamlineActor.Get());
이제 여전히 누락되고 중간 렌더링을 생성하는 데 실제로 필요한 것은 실제로 장면을 렌더링하고 인터랙터를 초기화하는 마지막 5줄입니다.
// Render and show interactive window renWin->Render(); interact->Initialize(); interact->Start(); return 0; }
마지막으로 완성된 시각화에 도달했습니다. 여기에서 다시 한 번 소개하겠습니다.
위의 시각화에 대한 전체 소스 코드는 여기에서 찾을 수 있습니다.
좋은 것, 나쁜 것, 못생긴 것
VTK 프레임워크의 개인적인 장단점 목록으로 이 기사를 마무리하겠습니다.
장점 : 적극적인 개발 : VTK는 주로 연구 커뮤니티 내에서 여러 기여자들로부터 활발히 개발되고 있습니다. 이것은 일부 첨단 알고리즘을 사용할 수 있고 많은 3D 형식을 가져오고 내보낼 수 있으며 버그가 적극적으로 수정되고 문제는 일반적으로 토론 게시판에 기성품 솔루션이 있음을 의미합니다.
단점 : 신뢰성 : VTK의 개방형 파이프라인 설계와 다양한 기여자의 많은 알고리즘을 결합하면 비정상적인 필터 조합에 문제가 발생할 수 있습니다. 복잡한 필터 체인이 원하는 결과를 생성하지 못하는 이유를 파악하기 위해 VTK 소스 코드로 몇 번 이동해야 했습니다. 디버깅을 허용하는 방식으로 VTK를 설정하는 것이 좋습니다.
장점 : 소프트웨어 아키텍처 : VTK의 파이프라인 설계 및 일반 아키텍처는 잘 고려된 것으로 보이며 작업하는 것이 즐겁습니다. 몇 줄의 코드로 놀라운 결과를 얻을 수 있습니다. 내장 데이터 구조는 이해하고 사용하기 쉽습니다.
단점 : 마이크로 아키텍처 : 일부 마이크로 아키텍처 설계 결정은 내 이해를 벗어납니다. Const-correctness는 거의 존재하지 않으며 배열은 명확한 구분 없이 입력 및 출력으로 전달됩니다. 나는 약간의 성능을 포기하고
typedef std::array<double, 3> Pnt3d;
vtkMath
.장점 : 마이크로 문서 : 모든 클래스와 필터에 대한 Doxygen 문서는 광범위하고 사용 가능하며 위키의 예제와 테스트 사례도 필터 사용 방법을 이해하는 데 큰 도움이 됩니다.
단점 : 매크로 문서 : 웹에 VTK에 대한 몇 가지 좋은 튜토리얼과 소개가 있습니다. 그러나 내가 아는 한 특정 작업이 수행되는 방법을 설명하는 큰 참조 문서는 없습니다. 새로운 일을 하고 싶다면 얼마 동안 그 일을 하는 방법을 찾아보세요. 또한 작업에 대한 특정 필터를 찾기가 어렵습니다. 그러나 일단 찾으면 Doxygen 문서로 충분합니다. VTK 프레임워크를 탐색하는 좋은 방법은 Paraview를 다운로드하여 실험하는 것입니다.
장점 : 암시적 병렬화 지원 : 소스를 독립적으로 처리할 수 있는 여러 부분으로 분할할 수 있는 경우 병렬화는 단일 부분을 처리하는 각 스레드 내에서 별도의 필터 체인을 만드는 것처럼 간단합니다. 대부분의 대규모 시각화 문제는 일반적으로 이 범주에 속합니다.
단점 : 명시적 병렬화 지원 없음 : 분할 가능한 크고 문제가 많은 축복을 받지 못했지만 여러 코어를 활용하려는 경우 스스로 해결해야 합니다. 어떤 클래스가 스레드로부터 안전한지, 시행착오를 통해 재진입하거나 소스를 읽어야 하는지 파악해야 합니다. 한 번 C 라이브러리를 호출하기 위해 정적 전역 변수를 사용하는 VTK 필터에 대한 병렬화 문제를 추적했습니다.
장점 : Buildsystem CMake : 멀티 플랫폼 메타 빌드 시스템 CMake도 Kitware(VTK 제조사)에서 개발했으며 Kitware 외부의 많은 프로젝트에서 사용됩니다. VTK와 매우 잘 통합되어 여러 플랫폼에 대한 빌드 시스템을 훨씬 덜 고통스럽게 설정할 수 있습니다.
장점 : 플랫폼 독립성, 라이선스 및 수명 : VTK는 기본적으로 플랫폼 독립적이며 매우 관대한 BSD 스타일 라이선스에 따라 라이선스가 부여됩니다. 또한 이를 필요로 하는 중요한 프로젝트에 대해 전문적인 지원을 받을 수 있습니다. Kitware는 많은 연구 기관 및 기타 회사의 지원을 받으며 한동안 사용할 수 있습니다.
마지막 단어
전반적으로 VTK는 내가 좋아하는 종류의 문제에 대한 최고의 데이터 시각화 도구입니다. 시각화, 메쉬 처리, 이미지 처리 또는 이와 유사한 작업이 필요한 프로젝트를 발견한 경우 입력 예제로 Paraview를 실행하고 VTK가 도구가 될 수 있는지 평가하십시오.