VTK 9.4 + QtQuick6从编译到Demo
- 编写这篇博客的主要原因是个人接触到的3D相关开发需求越来越多了,比如在3D Slicer上开发一些简单插件,处理3D数据并显示之类的
- 其次直接使用OpenGL函数库编写难度又比较大,Slicer的渲染使用了VTK的代码,所以个人也打算进行尝试
- 个人参加工作后使用的UI技术就是QML,VTK网上看到的示例一般是很旧的Widget,本着学新不学旧的原则,还是坚持使用QML+VTK的方式进行测试开发
- 博客的测试时间: 2025.05.25
文章目录
一、基础环境安装
1. Visual Studio 2019
https://docs.vtk.org/en/latest/build_instructions/index.html
- 没错就是2019, 官方的编译指导说的很重,所以个人也没有去测试其他的编译器类型
- 微软官方似乎有意减少旧版的编译器使用,如果需要安装还是搜索一些大哥的安装器, 这里贴一个: https://zhuanlan.zhihu.com/p/740245143
2. Qt6开发环境
- Qt Online Installer下载地址: https://download.qt.io/official_releases/online_installers/
- 选择一个比较新的版本(个人是6.7.0)直接全勾上就行了
- 可以将Tools中的CMake勾上(如果没有的话)
二、开始进行库编译
1. VTK源码下载
- 在官方下载页面: https://vtk.org/download/
- 下载Source那个压缩包就可以了,这里贴一下gitlab地址: https://gitlab.kitware.com/vtk/vtk,不是很推荐除非遇上了奇怪的问题需要最新的代码解决
2. 开始添加CMake编译参数
这里的官方的编译指导就没有什么特别的指导意义了,由社区以及各种帖子给出,这里给出一些简单说明
- VTK_QT_VERSION: 指定为6否则容易在自动搜索的时候出错
- VTK_GROUP_ENABLE_Qt: 开源项目Qt-VTK-viewer中看到的,大意是给Qt编译一些接口,以允许访问VTK的数据结构
- QML的支持在源码的
GUISupport/QtQuick
中,其中有个vtk.module的文件描述了其依赖关系(没错不是直接通过cmake组织的,所以编译的时候推荐在CLion中进行,只要参数填对后代码提示可以正常显示,那这个参数就是正确的)- GUISupportQtQuick模块依赖于GUISupportQt,所以这两个都需要开启
- 关于开启方法来自于社区的一个编译bug:
https://discourse.vtk.org/t/unable-to-build-vtk-9-4-with-qt-6-8/14857/6
,个人看了老半天还是感谢前人探路
- 最后的两个是Qt的开发环境
- VTK用到了Qt的一些基础事件需要QtCore
- Qt6QmlTools则是GUISupportQtQuick生成插件使用的工具
set(VTK_QT_VERSION 6)
set(VTK_GROUP_ENABLE_Qt YES)
set(VTK_MODULE_ENABLE_VTK_GUISupportQt YES)
set(VTK_MODULE_ENABLE_VTK_GUISupportQtQuick YES)
set(Qt6_DIR "D:/Development/Envs/QtEnv/6.7.0/msvc2019_64/lib/cmake/Qt6")
set(Qt6QmlTools_DIR "D:/Development/Envs/QtEnv/6.7.0/msvc2019_64/lib/cmake/Qt6QmlTools")
- 当Clion能够正常跳转类、函数的时候,说明参数填写正确
3. 编译以及安装
- 编译的话简单点击
Build All
即可,编译过程比较长只要能通过说明编译成功,如果中间失败的话需要自寻大佬解决
- 这里贴一些安装命令,以方便包管理
cd D:\Development\Envs\PACS-env\Archive\VTK-9.4.2\cmake-build-debug
cmake --install . --prefix=D:\Development\Envs\vtk-9.4.2-debug
- 请注意此文件夹,这是成功的标志
- 还有就是别忘记把bin目录加入环境变量中
三、从源码中复现Demo
1. 创建基础Quick项目
- 一路按下去,无中文路径即可,然后开始添加VTK支持
- 此修改遵守示例:
Examples/GUI/QML/QtQuickChartsOn3DScene/CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(01-VTKQtBuildVertify VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
### 添加VTK支持, 模块内容来自Example ########
set(VTK_DIR "D:/Development/Envs/vtk-9.4.2-debug/lib/cmake/vtk-9.4")
find_package(VTK
COMPONENTS
CommonCore
CommonColor
ChartsCore
GUISupportQtQuick
RenderingContextOpenGL2
)
#####################
find_package(Qt6 REQUIRED COMPONENTS Quick)
qt_standard_project_setup()
qt_add_executable(app01-VTKQtBuildVertify
main.cpp
)
qt_add_qml_module(app01-VTKQtBuildVertify
URI app01-VTKQtBuildVertify
VERSION 1.0
QML_FILES
Main.qml
)
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
set_target_properties(app01-VTKQtBuildVertify PROPERTIES
# MACOSX_BUNDLE_GUI_IDENTIFIER com.example.app01-VTKQtBuildVertify
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
target_link_libraries(app01-VTKQtBuildVertify
PRIVATE Qt6::Quick ${VTK_LIBRARIES}
)
########### VTK模块初始化 ##############
vtk_module_autoinit(
TARGETS app01-VTKQtBuildVertify
MODULES ${VTK_LIBRARIES}
)
######################################
include(GNUInstallDirs)
install(TARGETS app01-VTKQtBuildVertify
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
2. 允许QML编辑器对VTK进行代码提示
参考了GUISupport/QtQuick/qml/QQmlVTKPlugin.h
- 官方说直接添加第二章最后编译出来的QML文件夹到环境变量即可,但
个人尝试无效
- 下列是个人成功的方法,将编译出的插件目录直接贴到Qt开发的QML目录即可
3. UI部分逻辑
完成2的步骤后,
import VTK
就不会报错了
- 注意这个import后面的数字应该是你贴到QtQML组件的文件夹,
个人查看里面的qmltypes文件时发现其描述的9.1
,倍感迷惑 - 并且在qmltypes中,qml可以调用的组件只有三个,所以推荐大家直接放弃在QML中直接绘制逻辑的想法,求大佬封装一个牛逼的Quick3D库,或者推荐推荐也行
import QtQuick
import QtQuick.Controls
import VTK 9.4
// M300的可能解决方案: https://forum.qt.io/topic/92025/unknown-component-m300-for-custom-qml-class
Window {
width: 800
height: 600
visible: true
title: qsTr("Hello World")
Row{
Button{
width: 200
height: 40
text: "hhhhhh"
onClicked: {
console.log("hhhhhhh")
}
}
Button{
width: 200
height: 40
text: "hhhhhh"
onClicked: {
console.log("hhhhhhh")
}
}
Button{
width: 200
height: 40
text: "hhhhhh"
onClicked: {
console.log("hhhhhhh")
}
}
}
VTKRenderWindow{
id: vtkWindow
// anchors和width,height一样,无效,即便存在父对象
// 源码的sync()函数似乎直接设置成了窗口大小
// anchors.fill: parent
width: 100
height: 100
}
VTKRenderItem{
objectName: "ConeView"
x: 200
y: 200
width: 200
height: 200
renderWindow: vtkWindow
}
}
4. main文件部分
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "QQuickVTKItem.h"
#include "QQuickVTKRenderItem.h"
#include "vtkPolyDataMapper.h"
#include "vtkConeSource.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickVTKItem::setGraphicsApi();
// 等价于使用环境变量QML2_IMPORT_PATH
// https://doc.qt.io/qt-5/qtqml-syntax-imports.html#qml-import-path
QQmlApplicationEngine engine;
// engine.addImportPath("D:/Development/Envs/vtk-9.4.2-debug/lib/qml/VTK.9.4");
// qDebug() << "Import Path List: "
// << engine.importPathList();
// load ui
const QUrl url(QStringLiteral("qrc:/app01-VTKQtBuildVertify/Main.qml"));
QObject::connect(
&engine,
&QQmlApplicationEngine::objectCreationFailed,
&app,
[]() { QCoreApplication::exit(-1); },
Qt::QueuedConnection);
engine.load(url);
// Fetch the QQuick window using the standard object name set up in the constructor
QObject* topLevel = engine.rootObjects().value(0);
QQuickVTKRenderItem* qquickvtkItem = topLevel->findChild<QQuickVTKRenderItem*>("ConeView");
// Create a cone pipeline and add it to the view
vtkNew<vtkActor> actor;
vtkNew<vtkPolyDataMapper> mapper;
vtkNew<vtkConeSource> cone;
mapper->SetInputConnection(cone->GetOutputPort());
actor->SetMapper(mapper);
qquickvtkItem->renderer()->AddActor(actor);
qquickvtkItem->renderer()->ResetCamera();
qquickvtkItem->renderer()->SetBackground(0.5, 0.5, 0.7);
qquickvtkItem->renderer()->SetBackground2(0.7, 0.7, 0.7);
qquickvtkItem->renderer()->SetGradientBackground(true);
qquickvtkItem->update();
return app.exec();
}
5. 最后效果
3,4的实现参考了源码的GUISupport/QtQuick/QQuickVTKRenderWindow.h中的注释
- 虽然成功完成了一个Demo的制作和显示,但确实又诸多不足
- 如果大家跟着做后会发现,QQuickVTKRenderWindow,QQmlVTKPlugin均已经被标记了遗弃标签,并且现在的代码是直接在事件循环前添加的,也就是运行期间无法修改
- 所以本博客将这次试错定义为一个测试模块是否正确编译的Demo
- 正常开发的话,还是得看看社区大佬的实现,否则过于玩具了
四、没有解决的问题
在试错过程中发现的一些恶性问题,如果有
大神,评论区指点下
1. QQuickVTKRenderWindow
- 无法正确调整组件大小,会直接覆盖整个界面
- 源码中的sync()函数似乎直接将整个窗体作为了绘制对象
- 然后有种Qt绘制到了VTK上,而不是VTK被QML的容器接管的奇妙现象
2. QML编辑器M300问题
- 没有尝试过纯QQuickItem的发布方式,个人只能保证导入VTK的时候以及运行的时候不报错,不知道大神有没有解决方案
参考
- https://discourse.vtk.org/t/qml-vtkrenderwindow-inside-a-rectangle/11850
- https://github.com/martijnkoopman/Qt-VTK-viewer/blob/master/doc/Build-VTK.md
- https://discourse.vtk.org/t/unable-to-build-vtk-9-4-with-qt-6-8/14857/6
- https://forum.qt.io/topic/92025/unknown-component-m300-for-custom-qml-class