vue中安装使用vtk,亲测版

lxf2023-03-10 19:16:01

前提:

最近让提前预研究vtk,一个医学影像资料的3D库,百度谷歌发现基本搜不到啥有用的信息,基本都是用python和c写的,这里做一个自己使用的分享

VTK的api官网:kitware.github.io/vtk-js/api/ ITK的api官网:wasm.itk.org/api/node_io…

安装步骤:

npm i @kitware/vtk.js@21.3.0 --save

// vue.config.js文件中
const vtkChainWebpack = require('@kitware/vtk.js/Utilities/config/chainWebpack')

module.exports = {
	chainWebpack: (config) => {
        vtkChainWebpack(config)
        // do not cache worker files
        // https://github.com/webpack-contrib/worker-loader/issues/195
        config.module.rule('js').exclude.add(/\.worker\.js$/)
    },
    configureWebpack: {
		resolve: {
            alias: {
                vue$: 'vue/dist/vue.esm.js',
                '@': path.resolve('src'),
                cesium: path.resolve(__dirname, cesiumSource),
                '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps.json':
                    '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/LiteColorMaps.json',
            },
        },
        plugins: [
			new webpack.NormalModuleReplacementPlugin(/^webvr-polyfill$/, (resource) => {
                /* eslint-disable-next-line no-param-reassign */
                resource.request = '@/src/vtk/webvr-empty.js'
            }),
            // 需要安装itk使用时需要配置
            new CopyWebpackPlugin([
                {
                    from: path.join(__dirname, 'node_modules', 'itk', 'WebWorkers'),
                    to: path.join(__dirname, 'dist', 'itk', 'WebWorkers'),
                },
                {
                    from: path.join(__dirname, 'node_modules', 'itk', 'ImageIOs'),
                    to: path.join(__dirname, 'dist', 'itk', 'ImageIOs'),
                },
                {
                    from: path.join(__dirname, 'src', 'io', 'itk-dicom', 'web-build', 'dicom*'),
                    to: path.join(__dirname, 'dist', 'itk', 'Pipelines'),
                    flatten: true,
                },
            ]),
		]
	}
}

实际应用

其中ccHeader和ccScroll是我自己的组件,可以忽略掉不会影响代码vtk正常使用,这里封装方式有点参照平时封装threejs的习惯

<template>
    <div class="basic-model-page">
        <cc-header :headtitle="'BasicModel(基础模型)'" />
        <cc-scroll>
            <div class="vtkDiv"></div>
        </cc-scroll>
    </div>
</template>
<script>
import ccHeader from '@/components/cc-header/cc-header.vue'
import ccScroll from '@/components/cc-scroll/cc-scroll.vue'

// import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow'
import vtkCalculator from '@kitware/vtk.js/Filters/General/Calculator'
import vtkCubeAxesActor from '@kitware/vtk.js/Rendering/Core/CubeAxesActor'
import vtkInteractorStyleTrackballCamera from '@kitware/vtk.js/Interaction/Style/InteractorStyleTrackballCamera'

import vtkRenderer from '@kitware/vtk.js/Rendering/Core/Renderer'
import vtkRenderWindow from '@kitware/vtk.js/Rendering/Core/RenderWindow'
import vtkRenderWindowInteractor from '@kitware/vtk.js/Rendering/Core/RenderWindowInteractor'

import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor'
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper'
import vtkConeSource from '@kitware/vtk.js/Filters/Sources/ConeSource'
import vtkCubeSource from '@kitware/vtk.js/Filters/Sources/CubeSource'
import vtkURLExtract from '@kitware/vtk.js/Common/Core/URLExtract'
// DataSetAttributes用于表示和操作属性数据(例如,标量、向量、法线、纹理坐标、张量、全局 id、谱系 id 和字段数据)
import { AttributeTypes } from '@kitware/vtk.js/Common/DataModel/DataSetAttributes/Constants'
// DataSet为数据集对象指定一个接口,提供有关数据的信息,例如中心、边界框和代表长度,常放于过滤器中
import { FieldDataTypes } from '@kitware/vtk.js/Common/DataModel/DataSet/Constants'
// 加载我们想要使用的渲染片段(对于 WebGL 和 WebGPU)
import '@kitware/vtk.js/favicon'
import '@kitware/vtk.js/Rendering/Profiles/Geometry'
// 强制 DataAccessHelper 可以访问各种数据源
import '@kitware/vtk.js/IO/Core/DataAccessHelper/HtmlDataAccessHelper'
import '@kitware/vtk.js/IO/Core/DataAccessHelper/HttpDataAccessHelper'
import '@kitware/vtk.js/IO/Core/DataAccessHelper/JSZipDataAccessHelper'

// 需要在vtk工厂中注册的polydata
import '@kitware/vtk.js/Common/Core/StringArray'
import '@kitware/vtk.js/Common/DataModel/PolyData'

import '@kitware/vtk.js/Rendering/OpenGL/RenderWindow'
import '@kitware/vtk.js/Rendering/WebGPU/RenderWindow'

export default {
    name: 'basic-model-page',
    components: {
        ccScroll,
        ccHeader,
    },
    data() {
        return {}
    },
    methods: {
        // DataArray:vtkDataArray 是包含数值数据的数据数组对象的抽象超类
        // PolyData:vtkPolyData是一个数据集,它表示由顶点、直线、多边形和/或条带组成的几何结构
        // Glyph3DMapper:使用 vtkGlyph3DMapper 特性来装饰给定对象(publicAPI+model)的方法
        initView() {
            // 找到div标签
            const vtkContainer = document.querySelector('.vtkDiv')
            // 来自url的参数
            const userParams = vtkURLExtract.extractURLParameters()

            // 渲染器,过滤器,数据图元,场景实体
            let renderer, calculatorFilter
            let coneMapper, coneActor, cubeMapper, cubeActor
            // 圆锥体,辅助线
            let coneSource, cubeSource, cubeAxes
            // 鼠标事件,渲染窗口
            let interactor, renderWindow, apiSpecificRenderWindow

            main() // 主函数允许
            render() // 渲染器执行

            function main() {
                // initFullScreenRender() // 全屏视图渲染,除initRenderer的另一种渲染方式(不建议使用)
                initRenderer() // 渲染窗口操作
                initInteractor() // 设置鼠标交互事件
                initConeSource() // 绘制圆锥
                initCubeSource() // 绘制立方体
                initCalculatorFilter() // 绘制过滤器
                initMapper() // 绘制数据图元接口
                initActor() // 渲染场景实体
                initCubeAxes() // 绘制cube辅助线
            }

            // vtkFullScreenRenderWindow 提供了实现全屏, newInstance用于创建 vtkFullScreenRenderWindow 新实例的方法
            // function initFullScreenRender() {
            //     const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
            //         rootContainer: vtkContainer,
            //         // background: [0, 0, 0, 255],  // 黑色
            //         background: [0, 0, 0, 0], // 透明色
            //     })
            //     renderer = fullScreenRenderer.getRenderer()
            //     renderWindow = fullScreenRenderer.getRenderWindow()
            //     renderWindow.addRenderer(renderer)
            // }

            // 标染窗口, 图形用户界面中渲染器绘制图像的窗口,提供了同步渲染过程、设置窗口大小和控制双缓冲的方法
            // renderer vtkRenderer 是一个用于保存 3D 属性的视口。它包含一个 vtkCamera 实例、一个 vtkLights 集合和 vtkActors。它存在
            // 于 RenderWindow 中。一个 RenderWindow 可能有多个 Renderer代表窗口的不同视口,Renderer 也可以相互叠加
            function initRenderer() {
                renderWindow = vtkRenderWindow.newInstance()
                // renderer = vtkRenderer.newInstance({ background: [255, 255, 255] })
                renderer = vtkRenderer.newInstance({ background: [0, 0, 0] })
                renderWindow.addRenderer(renderer)
                // 获取此数据的 API 特定视图,绑定dom标签
                apiSpecificRenderWindow = renderWindow.newAPISpecificView(userParams.viewAPI)
                renderWindow.addView(apiSpecificRenderWindow)
                apiSpecificRenderWindow.setContainer(vtkContainer)
                // 捕获容器的大小并将其设置为 renderWindow
                const { width, height } = vtkContainer.getBoundingClientRect()
                apiSpecificRenderWindow.setSize(width, height)
            }

            function initConeSource() {
                // vtkConeSource 创建一个以指定点为中心并指向指定方向的圆锥体, 参数是高度、半径、分辨率(0:一条线,1:三角形,2:交叉三角形,>2:3D锥体)
                coneSource = vtkConeSource.newInstance({ height: 1.0, radius: 1, resolution: 80 })
            }

            function initCubeSource() {
                cubeSource = vtkCubeSource.newInstance()
            }

            // 创建一个内联过滤器
            function initCalculatorFilter() {
                calculatorFilter = vtkCalculator.newInstance()
                calculatorFilter.setInputConnection(coneSource.getOutputPort())
                calculatorFilter.setFormula({
                    getArrays: () => ({
                        input: [],
                        output: [
                            {
                                location: FieldDataTypes.CELL, // FieldDataTypes.CELL:3
                                name: 'Random',
                                dataType: 'Float32Array',
                                attribute: AttributeTypes.SCALARS, // AttributeTypes.SCALARS:0
                            },
                        ],
                    }),
                    evaluate: (arraysIn, arraysOut) => {
                        const [scalars] = arraysOut.map((d) => d.getData())
                        for (let i = 0; i < scalars.length; i++) {
                            scalars[i] = Math.random()
                        }
                    },
                })
            }

            // vtkMapper 用于指定数据和图形基元间的接口
            function initMapper() {
                coneMapper = vtkMapper.newInstance()
                coneMapper.setInputConnection(calculatorFilter.getOutputPort())
                // coneMapper.setInputConnection(coneSource.getOutputPort())
                cubeMapper = vtkMapper.newInstance()
                cubeMapper.setInputConnection(cubeSource.getOutputPort())
            }

            // actor 用于表示渲染场景中的实体,具有缩放功能,并维护对定义几何体(即映射器)、渲染属性以及可能的纹理贴图的引用
            function initActor() {
                // actor.setMapper 设置映射器,将参与者连接到可视化管道末端的方法
                coneActor = vtkActor.newInstance()
                coneActor.setMapper(coneMapper)
                coneActor.setPosition(0.0, 0.0, -20.0)

                cubeActor = vtkActor.newInstance()
                // actor.getProperty():获取控制此actor表面
                // cubeActor.getProperty().setRepresentation(1) // setRepresentation:控制显示线条
                cubeActor.getProperty().setColor(0, 1, 0) // setColor:设置颜色(r,g,b)
                // cubeActor.getProperty().setAmbientColor(255, 182, 193)
                // cubeActor.getProperty().setSpecularColor(255, 182, 193)
                cubeActor.setMapper(cubeMapper)
                cubeActor.setPosition(0.0, 0.0, -20.0)
            }

            // 添加cube辅助线
            function initCubeAxes() {
                cubeAxes = vtkCubeAxesActor.newInstance()
                cubeAxes.setCamera(renderer.getActiveCamera())
                cubeAxes.setDataBounds(coneActor.getBounds())
                renderer.addActor(cubeAxes)
            }

            // vtkRenderWindowInteractor提供了鼠标/按键/时间事件的交互机制,还提供了用于拾取、渲染帧速率的控件
            function initInteractor() {
                interactor = vtkRenderWindowInteractor.newInstance()
                // setView: 设置视图
                interactor.setView(apiSpecificRenderWindow)
                // initialize: 视图初始化
                interactor.initialize()
                // bindEvents: 绑定事件
                interactor.bindEvents(vtkContainer)
                // 设置要使用的交互器样式
                interactor.setInteractorStyle(vtkInteractorStyleTrackballCamera.newInstance())
            }

            // 将actor添加到渲染器并根据它设置相机
            function render() {
                renderer.addActor(coneActor)
                renderer.addActor(cubeActor)
                renderer.resetCamera()
                renderer.resetCameraClippingRange()
                renderWindow.render()
            }
        },
    },
    mounted() {
        this.initView()
    },
}
</script>
<style lang="scss" scoped>
.vtkDiv {
    position: relative;
    width: 100%;
    height: 100%;
}
</style>

贴出效果图

vue中安装使用vtk,亲测版

后续会继续分享cbct文件的解析和xyz轴的切面图 如果觉得有用关注点赞分享收藏!!!!!!!