VTK.js的核心是标准可视化工具包(VTK)库的JavaScript移植,这是一个c++库,旨在促进数据可视化,在此基础上构建了科学可视化应用程序Paraview。VTK.js没有使用OpenGL,而是利用WebGL,主要关注几何和体渲染。因此,它为不同类型的3D对象提供了大量的读取器。OBJ, . stl, . vtk等)。
在本教程中,我们将构建一个基本的VTK.js应用程序,并学习VTK渲染过程的一些基础知识。VTK库(尤其是它最初的c++实现)是一个巨大而强大的资源,如果你对它感兴趣,我强烈建议你查看VTK用户指南和VTK教科书以获得更多信息。
注意:本教程基于VTK.js应用程序示例。最初的教程没有太多的解释,所以我在这里更深入地解释了web开发和渲染过程的每个部分。
开始
首先,确保你的计算机上已经安装了node .js/npm(你可以通过在终端上运行node -v或npm -v来确认它们是否已经安装)。在为项目下载所需的JavaScript包时,这是必要的。
然后,在你希望项目基于的目录中,创建一个名为MyWebProject的目录,并将其初始化为一个带有包的npm存储库。json文件:
mkdir MyWebProject
cd MyWebProject
npm init
The package.json文件为你的项目指定了各种控件和选项。例如,包。json包含快捷“脚本”,你可以从你的终端运行,如“test”,当你从你的终端运行“npm test”时,将运行“echo \”错误:没有测试指定\“&& exit 1”。包。Json还跟踪项目依赖项及其版本。
说到依赖项,我们现在可以安装我们的两个依赖项:
npm install vtk.js --save
npm install kw-web-suite --save-dev
这些命令将这些库安装到项目的node_modules目录中,这是一个包含所有依赖项的方便文件夹。
现在,在项目的根目录中创建一个名为webpack.config.js的文件,并复制并粘贴以下代码:
var path = require('path');
var webpack = require('webpack');
var vtkRules = require('vtk.js/Utilities/config/dependency.js').webpack.core.rules;
// Optional if you want to load *.css and *.module.css files
// var cssRules = require('vtk.js/Utilities/config/dependency.js').webpack.css.rules;
var entry = path.join(__dirname, './src/index.js');
const sourcePath = path.join(__dirname, './src');
const outputPath = path.join(__dirname, './dist');
module.exports = {
entry,
output: {
path: outputPath,
filename: 'MyWebApp.js',
},
module: {
rules: [
{ test: /\.html$/, loader: 'html-loader' },
].concat(vtkRules),
},
resolve: {
modules: [
path.resolve(__dirname, 'node_modules'),
sourcePath,
],
},
};
Webpack是一个用于web开发的模块捆绑器。它的功能超出了本教程的范围,但从本质上讲,这个配置文件为如何转译JavaScript文件和依赖项设置了某些选项,这样所有的JavaScript类和功能都可以压缩到一个文件中,以便在web浏览器中使用。欲了解更多信息,请访问https://webpack.js.org/。
In package.json,在“scripts”对象下添加以下脚本:
{
[...],
"scripts": {
"build": "webpack --progress --colors --mode development",
"build:release": "webpack --progress --colors --mode production",
"start": "webpack-dev-server --content-base ./dist",
"commit": "git cz",
"semantic-release": "semantic-release"
}
}
现在我们已经准备好构建我们的VTK.js应用程序了!
应用程序
在根目录下创建两个文件夹:./src和./dist。在dist/中,创建一个名为index.html的文件,并将以下代码复制到其中:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script type="text/javascript" src="MyWebApp.js"></script>
</body>
</html>
这是一个HTML文件,最终经过转译、捆绑的JS代码将被呈现到这个文件中。如果你有敏锐的眼光,你可能已经注意到在webpack.config.js中,我们应用程序的输出捆绑文件叫做MyWebApp.js,位于dist文件夹中。该文件随后由<script>标记引用。
现在,在src/中,创建一个名为controller.html的文件,并将以下代码复制到其中:
<table>
<tr>
<td>
<select class='representations' style="width: 100%">
<option value='0'>Points</option>
<option value='1'>Wireframe</option>
<option value='2' selected>Surface</option>
</select>
</td>
</tr>
<tr>
<td>
<input class='resolution' type='range' min='4' max='80' value='6' />
</td>
</tr>
</table>
这个HTML文件表示可视化的查看控件。我们将能够选择什么表示我们的可视化采取(即点,线框或表面),以及该可视化的分辨率。我们将很快对此展开更多内容。
最后,同样在src/中,创建一个index.js文件,并将以下代码复制到其中:
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow';
import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor';
import vtkCalculator from 'vtk.js/Sources/Filters/General/Calculator';
import vtkConeSource from 'vtk.js/Sources/Filters/Sources/ConeSource';
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
import { AttributeTypes } from 'vtk.js/Sources/Common/DataModel/DataSetAttributes/Constants';
import { FieldDataTypes } from 'vtk.js/Sources/Common/DataModel/DataSet/Constants';
import controlPanel from './controller.html';
// ----------------------------------------------------------------------------标准呈现代码设置
// ----------------------------------------------------------------------------
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance();
const renderer = fullScreenRenderer.getRenderer();
const renderWindow = fullScreenRenderer.getRenderWindow();
// ----------------------------------------------------------------------------
// 代码示例
// ----------------------------------------------------------------------------
const coneSource = vtkConeSource.newInstance({ height: 1.0 });
const filter = vtkCalculator.newInstance();
filter.setInputConnection(coneSource.getOutputPort());
filter.setFormula({
getArrays: inputDataSets => ({
input: [],
output: [
{ location: FieldDataTypes.CELL, name: 'Random', dataType: 'Float32Array', attribute: AttributeTypes.SCALARS },
],
}),
evaluate: (arraysIn, arraysOut) => {
const [scalars] = arraysOut.map(d => d.getData());
for (let i = 0; i < scalars.length; i++) {
scalars[i] = Math.random();
}
},
});
const mapper = vtkMapper.newInstance();
mapper.setInputConnection(filter.getOutputPort());
const actor = vtkActor.newInstance();
actor.setMapper(mapper);
renderer.addActor(actor);
renderer.resetCamera();
renderWindow.render();
// -----------------------------------------------------------
// UI 操作处理
// -----------------------------------------------------------
fullScreenRenderer.addController(controlPanel);
const representationSelector = document.querySelector('.representations');
const resolutionChange = document.querySelector('.resolution');
representationSelector.addEventListener('change', (e) => {
const newRepValue = Number(e.target.value);
actor.getProperty().setRepresentation(newRepValue);
renderWindow.render();
});
resolutionChange.addEventListener('input', (e) => {
const resolution = Number(e.target.value);
coneSource.setResolution(resolution);
renderWindow.render();
});
这段代码是应用程序的核心。在我们继续之前,让我们构建并运行这个项目:
npm run build
npm start
导航到http://localhost:8080/查看我们的应用程序正在运行!
在引擎盖下-探索代码
让我们打开index.js,看看里面发生了什么。幸运的是,VTK开发人员已经用注释清晰地分割了JS代码的重要部分,所以我们可以把它作为起点。
渲染设置
这段代码设置了三个变量,fullScreenRenderer, renderer和renderWindow。
fullScreenRenderer提供了一个全屏上下文,其中呈现的模型和控件共存。
renderWindow是一个包含多个渲染器的窗口。在每个动画帧上,renderWindow调用每个渲染器并将所有相关模型渲染到窗口。
渲染器为要渲染到相关渲染窗口的模型提供了一个入口点(在vtkActor对象中包装了其他信息——稍后将详细介绍)。渲染器还包含一个vtkLights集合和一个vtkCamera实例。
创建和渲染模型- VTK可视化管道的基础知识
这部分代码创建一个模型,过滤它的数据,将这个数据连接到一个映射器,将这个映射器连接到一个参与者,最后将参与者添加到渲染的场景中。
coneSource只是一个程序生成的圆锥的3D模型。VTK.js提供了许多程序生成的3D模型源代码,包括ArrowSource和PointSource。源代码是VTK可视化管道的开始。
filter是Calculator过滤器的一个实例。过滤器从源中获取输出数据,并以各种方式修改它们,然后继续在呈现管道中进行进一步处理。在本例中,使用了两个函数:
getArrays()——给定一个输入数据集,返回两个数组,指定要传递给函数的vtkDataArray类型的输入和输出数组
在本例中,filter.getArrays()将coneSource的输出数据作为输入,并返回类型为“CELL”的输出数组,名称为“Random”,数据类型为“Float32Array”,并带有标量属性。
evaluate()——给定一个输入数组vtkDataArray和输出数组vtkDataArray,使用输入数组构造一个输出数组
在本例中,filter.evaluate()生成一个与输出数据长度相同的随机标量值数组。
mapper是mapper的一个实例。映射器终止了可视化管道,并充当可视化子系统和图形子系统之间的接口。在本例中,创建了一个映射器,它将过滤器的输出作为输入。
actor是actor的一个实例,actor是vtkProp3D最常见的子类。actor将渲染属性信息分组,如表面属性(例如,环境、漫反射和高光颜色)、表示(例如,表面、线框)、纹理映射和/或几何定义(通过映射器)。在本例中,我们的参与者与之前创建的映射器链接,映射器将呈现过滤器输出的几何数据。
然后我们的渲染器将这个actor添加到场景中。renderWindow被重新渲染以反映更新后的状态。我们已经成功地从source -> filter -> mapper -> actor -> renderWindow创建了一个可视化管道,并且我们对该管道中的任何元素所做的任何后续更改都将反映在我们的最终渲染中,正如我们将在下一节中看到的那样。
UI控件
这部分代码封装了UI逻辑,允许我们操作呈现的对象。如果你还记得的话,我们在src/controller.html中定义了2个交互控件——一个控制对象的表示,另一个控制对象的解析。在这里,我们添加了JS事件监听器逻辑,该逻辑对其值的变化做出反应。
从本质上讲,在将这些控件与我们的fullScreenRenderer关联之后,这段代码只是从DOM中抓取元素(即representationSelector和resolutionChange),并将简单的eventlistener添加到每个元素中。
例如,对于representationSelector,添加了一个监听值中的“变化”的事件侦听器。当用户更改对象表示时,该侦听器将被触发,获取元素的更新值,相应地设置参与者表示,并重新呈现窗口。它对resolutionChange做了非常类似的事情。
结论
现在你知道了!我们已经成功地建立并运行了一个VTK.js web应用程序示例,并且在此过程中我们已经学习了一些web开发的基础知识和VTK可视化管道。欲了解更多信息,或者如果您想尝试VTK.js中的其他示例查看器,请查看官方网站。另外,请填写教程的反馈表!https://goo.gl/forms/41Mgd6zTTctPwBWs2