VTK
Vtk,(visualization toolkit)是一個開源的免費軟件系統,主要用於三維計算機圖形學、圖像處理和可視化。Vtk是在面向對象原理的基礎上設計和實現的,它的內核是用C++構建的,包含有大約250,000行代碼,2000多個類,還包含有幾個轉換界面,因此也可以自由的通過Java,Tcl/Tk和Python各種語言使用vtk。通過VTK將科學實驗數據如建築學、氣象學、醫學、生物學或者航空航天學,對體、面、光源等等的逼真渲染,從而幫助人們理解那些採取錯綜複雜而又往往規模龐大的數字呈現形式的科學概念或結果。
目的
本文目的是構建VTK+QT+VS的應用程序開發環境。
QT版本:5.7.0
VTK版本:7.1.1
VS版本:2013(VC12)
前置條件:Cmake在你的環境裏已經安裝好,QT5.7.0和VS2013已經安裝配置好,安裝配置很簡單,如果配置有問題可以參考http://blog.csdn.net/goodtomsheng/article/details/45719205
VTK編譯安裝
1. 下載VTK7.1.1http://www.vtk.org/download/,目前官網上最新版本是VTK8.0.1,保守起見我選擇了VTK7.1.1版本,下載的文件VTK-7.1.1.zip、VTKData-7.1.1.zip。
2. 創建一個叫vtk的目錄(名字隨便起),將CTK-7.1.1.zip、VTKData-7.1.1.zip解壓壓到vtk目錄下,並創建一個vtk_bin_x64的目錄存放CMake後面生成的vtk工程,解壓之後目錄結構如圖。
3. 打開CMake-gui,Where is thesource code處選擇VTK-7.1.1目錄,Where to build the binaries處選擇上面創建的vtk_bin_x64。點擊Configure,在彈出的對話框中選擇Visual Studio12 2013,點Finish。等Configue配置完成之後,有幾個宏需要配置:
BUILD_SHARED_LIBS – 指示編譯共享庫還是靜態庫,默認是編譯選上的狀態,我們要編譯共享庫,所以保持默認狀態;
BUILD_EXAMPLES – 指示編譯示例工程,這裏選上,方便學習使用。
CMAKE_INSTALL_PREFIX – VTK完成編譯完成之後,安裝目錄,bin、lib、include等文件會被拷貝到它指定的目錄下,x64編譯默認安裝目錄是“C:/ProgramFiles /VTK”,但是VTK7.1.1貌似設置這個項不起作用,真正起作用的是設置這幾個宏:INSTALL_BIN_DIR、INSTALL_INC_DIR、INSTALL_LIB_DIR、INSTALL_MAN_DIR、INSTALL_PKGCONFIG_DIR。我這裏就按默認路徑安裝,如果你不是管理員賬號,這裏安裝到默認目錄下因爲權限問題會失敗。
VTK_Group_Qt – QT支持,默認不支持,我們要支持QT集成開發,所以勾選上這一項。同樣爲了支持QT將宏Module_vtkGUISupportQt、Module_vtkGUISupportQtOpenGL也勾選上。
VTK_QT_VERSION – QT版本,我使用的QT5所以設置爲5,這個選項在Configure之後是沒有的,沒關係,等後面點擊Generate之後會報告Qt版本失敗,這時候就可以找到這個選項並設置之後重新Generate就沒問題了。
VTK_DATA_STORE – Vtk數據存儲位置,就是之前從VTK官網下下來的VTKData-7.1.1.zip,指定到解壓的目錄下兩層,我這裏是“E:\OpenSource\vtk\VTKData-7.1.1\VTK-7.1.1\.ExternalData”。
Module_vtkGUISupportMFC – 指定產生和MFC框架集成的庫,我這裏用不着,所以不勾選。
點擊Add Entry,添加CacheEntry,CMAKE_PREFIX_PATH,Value設置爲你的QT安裝目錄,我這裏是“D:\Qt\Qt5.7.0\5.7\msvc2013_64”。
上面這些選項設置完成之後點擊Generate,這裏會因爲Qt的版本問題失敗一次,正確設置VTK_QT_VERSION之後重新生成就沒問題了。CMake工作完成之後的界面如下圖,這裏CMake的工作也就結束了。
4. 等Generate完成之後點擊OpenProject打開配置好的VS2013工程。點擊菜單生成 ->批生成 ,選擇ALL_BUILD生成Debug版本和Release版本。生成完成之後點擊彩當生成->批生成,選擇INSTALL生成 Debug,這會將Debug版本的lib、bin、inlcude等都拷貝到前面設置的“C:/Program Files /VTK”目錄下。
5. 和Qt Designer結合,將Release版本生成的bin路徑(的路徑是E:\OpenSource\vtk\vtk_bin_x64\bin\Release)下的QVTKWidgetPlugin.dll和lib路徑下的QVTKWidgetPlugin.lib、QVTKWidgetPlugin.exp拷貝到QT安裝路徑下的plugins\designer下(我的路徑是D:\Qt\Qt5.7.0\5.7\msvc2013_64\plugins\designer),這裏不要用Debug版本編譯產生的文件,Qt Designer會讀不出來。設置好之後再打開QtDesigner會看到QVTKWidget,如下圖所示。
6. VS工程配置(vtk官方文檔都是建議用CMake來管理工程,這裏會介紹到不用CMake管理有些特別注意的地方)
a) 新創建一個VS工程(可以是QT工程也可以是普通C++工程)
b) 配置Debug-平臺X64,設置頭文件路徑,和普通C++工程一樣,我這裏的路徑是“C:\Program Files\VTK\include\vtk-7.1”,在連接器裏設置庫路徑,我這裏是“C:\Program Files\VTK\lib”。連接器裏添加輸入庫,要添加的項比較多,這裏一個好的方法是打開Examples下的一個工程,將它的工程配置裏輸入庫直接拷貝過來。
c) 這時候如果你把示例程序Cone的代碼拷貝到當前工程下(Cone代碼在下面給出),編譯什麼都通過了,運行的時候發現程序不能正常運行或者說是運行之後會直接掛掉,調試跟進之後發現vtkPolyDataMapper::New()返回的始終爲NULL,而同樣代碼的Examples下的實例工程Cone就能正常運行和顯示效果。分析Cone工程,發現它多了一些預處理指令,而這其中起關鍵作用的一個預處理指令就是:
vtkRenderingCore_INCLUDE="E:/OpenSource/vtk/vtk_bin_x64/CMakeFiles/vtkRenderingCore_AUTOINIT_vtkInteractionStyle_vtkRenderingOpenGL2.h"。
解決思路1:我們同樣添加這個預處理指令,可以把vtkRenderingCore_AUTOINIT_vtkInteractionStyle_vtkRenderingOpenGL2.h拷貝到vtk的indluce目錄下,再在自己的VS工程中添加預處理指令:
vtkRenderingCore_INCLUDE="vtkRenderingCore_AUTOINIT_vtkInteractionStyle_vtkRenderingOpenGL2.h"
解決思路2:看看這個預處理指令做了什麼,打開.h文件發現它只定義了一條宏:
#define vtkRenderingCore_AUTOINIT2(vtkInteractionStyle,vtkRenderingOpenGL2),其實就是初始化VTK模塊,按照官方說明,可以在所有包含文件之前定義這個宏:
#define vtkRenderingCore_AUTOINIT2(vtkInteractionStyle,vtkRenderingOpenGL2),這樣也能解決問題。另外還可以,像下面這樣,在代碼最開始,所有頭文件包含之前。
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);// VTK was built withvtkRenderingOpenGL2
VTK_MODULE_INIT(vtkInteractionStyle);
用上面的任何一種方法均能解決問題。更詳細的解釋可以參考http://www.vtk.org/Wiki/VTK/VTK_6_Migration/Factories_now_require_defines。Cone工程運行的結果如下,圖中圓錐體旋轉幾秒鐘之後窗口自動關閉。
編譯好的庫地址:https://pan.baidu.com/s/1pLMChzP wfd6
#include "vtkConeSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkRenderWindow.h"
#include "vtkCamera.h"
#include "vtkActor.h"
#include "vtkRenderer.h"
int main()
{
// Next we create an instance of vtkConeSource and set some of its
// properties. The instance of vtkConeSource "cone" is part of a
// visualization pipeline (it is a source process object); it produces data
// (output type is vtkPolyData) which other filters may process.
vtkConeSource *cone = vtkConeSource::New();
cone->SetHeight( 3.0 );
cone->SetRadius( 1.0 );
cone->SetResolution( 10 );
// In this example we terminate the pipeline with a mapper process object.
// (Intermediate filters such as vtkShrinkPolyData could be inserted in
// between the source and the mapper.) We create an instance of
// vtkPolyDataMapper to map the polygonal data into graphics primitives. We
// connect the output of the cone souece to the input of this mapper.
vtkPolyDataMapper *coneMapper = vtkPolyDataMapper::New();
coneMapper->SetInputConnection( cone->GetOutputPort() );
// Create an actor to represent the cone. The actor orchestrates rendering
// of the mapper's graphics primitives. An actor also refers to properties
// via a vtkProperty instance, and includes an internal transformation
// matrix. We set this actor's mapper to be coneMapper which we created
// above.
vtkActor *coneActor = vtkActor::New();
coneActor->SetMapper( coneMapper );
// Create the Renderer and assign actors to it. A renderer is like a
// viewport. It is part or all of a window on the screen and it is
// responsible for drawing the actors it has. We also set the background
// color here.
vtkRenderer *ren1= vtkRenderer::New();
ren1->AddActor( coneActor );
ren1->SetBackground( 0.1, 0.2, 0.4 );
// Finally we create the render window which will show up on the screen.
// We put our renderer into the render window using AddRenderer. We also
// set the size to be 300 pixels by 300.
vtkRenderWindow *renWin = vtkRenderWindow::New();
renWin->AddRenderer( ren1 );
renWin->SetSize( 300, 300 );
// Now we loop over 360 degrees and render the cone each time.
int i;
for (i = 0; i < 360; ++i)
{
// render the image
renWin->Render();
// rotate the active camera by one degree
ren1->GetActiveCamera()->Azimuth( 1 );
}
//
// Free up any objects we created. All instances in VTK are deleted by
// using the Delete() method.
//
cone->Delete();
coneMapper->Delete();
coneActor->Delete();
ren1->Delete();
renWin->Delete();
return 0;
}