在完成和理解第一个C#的VTK示例后,是不是迫不及待的想往程序里添加自己的三维角色了呢?首先,梳理一下"角色Actor"、"渲染器Renderer"和C#中"renderWindowControl.RenderWindow"的关系。打个比方说,"RenderWindow"是剧院,"渲染器Renderer”是剧院中的舞台舞台,"角色Actor”就是舞台上的演员。一个剧院可以有多个相对独立的舞台,自然舞台上也可以有许多演员。在一个剧院内,舞台可以现对独立,演员也可以到不同的舞台去演出。
在前一示例的基础上,增加"角色Actor"和"渲染器Renderer",程序运行效果如下:
C#程序代码如下:
private void renderWindowControl1_Load(object sender, EventArgs e)
{
// 1.Create a simple sphere. A pipeline is created.
// 1.新建球体,创建“管道pipeline”。
// 1.1 新建数据--“数据源Source”
// (1)球体
vtkSphereSource sphere = vtkSphereSource.New(); // 新建球
sphere.SetThetaResolution(8); // 设置球纬度参数
sphere.SetPhiResolution(16); // 设置球经度参数
sphere.SetRadius(0.5); // 设置球的半径
// (2)柱体
vtkCylinderSource cylinder = vtkCylinderSource.New();
cylinder.SetHeight(3.0);
cylinder.SetRadius(0.1);
cylinder.SetResolution(10);
// 1.2 数据加工 -- "过滤器Filter" -- 收缩
vtkShrinkPolyData shrink = vtkShrinkPolyData.New(); // 新建数据收缩操作器
shrink.SetInputConnection(sphere.GetOutputPort()); // 连接管道
shrink.SetShrinkFactor(0.9); // 收缩“面”操作
// 1.3 数据制图 -- "制图器Mapper"
// (1)球体
vtkPolyDataMapper sphereMapper = vtkPolyDataMapper.New(); // 新建制图器
sphereMapper.SetInputConnection(shrink.GetOutputPort()); // 连接管道
// (2)柱体
vtkPolyDataMapper cylinderMapper = vtkPolyDataMapper.New(); // 新建制图器
cylinderMapper.SetInputConnection(cylinder.GetOutputPort()); // 连接管道
// 2.The actor links the data pipeline to the rendering subsystem
// 2.创建“角色Actor”,连接“管道pipeline”和“渲染系统rendering subsystem”
// 2.1 新建角色--“角色Actor”
// (1)球体
vtkActor sphereActor = vtkActor.New(); // 新建角色
sphereActor.SetMapper(sphereMapper); // 传递制图器
sphereActor.GetProperty().SetColor(1, 0, 0); // 设置“角色”颜色[RGB]
// (2)柱体
vtkActor cylinderActor = vtkActor.New(); // 新建角色
cylinderActor.SetMapper(cylinderMapper); // 传递制图器
cylinderActor.GetProperty().SetColor(0, 1, 0); // 设置“角色”颜色[RGB]
// 2.2 Create components of the rendering subsystem
// 2.2 创建渲染--“渲染系统rendering subsystem”
// (1)新建“渲染器Renderer”和“渲染窗口RenderWindow”
// renderWindowControl1控件提供“渲染窗口”
//vtkRenderer ren1 = renderWindowControl1.RenderWindow.GetRenderers().GetFirstRenderer();
vtkRenderer render1 = vtkRenderer.New(); // 新建渲染器
vtkRenderer render2 = vtkRenderer.New(); // 新建渲染器
vtkRenderWindow renWin = renderWindowControl1.RenderWindow;
renWin.AddRenderer(render1); // 添加渲染器
renWin.AddRenderer(render2); // 添加渲染器
// Add the actors to the renderer, set the window size
// (2)将“角色Actor”添加到“渲染器Renderer”并渲染
render1.AddActor(cylinderActor);
render1.AddActor(sphereActor);
render1.SetViewport(0.0, 0.0, 0.5, 0.5); // 设置Viewport窗口
render1.SetBackground(0.0,0.0,1.0); // 设置背景色
render2.AddActor(cylinderActor);
render2.SetViewport(0.5, 0.5, 1.0, 1.0); // 设置Viewport窗口
render2.SetBackground(1.0, 1.0, 1.0); // 设置背景色
//ren1.AddViewProp(sphereActor); // 渲染器添加角色
//renWin.SetSize(500, 500); // 设置渲染窗口大小[无效语句]
renWin.Render(); // 渲染渲染窗口
// (3)设置"相机Camera"
//vtkCamera camera = render1.GetActiveCamera(); // 新建相机
//camera.Zoom(1.0); // 相机缩放
}
1. 添加“角色Actor"
上一个示例中,唯一的演员是“球体”,为了方便区分添加一个新演员“柱体”。添加演员是一个完整的流程操作,“数据源Souce”-->“过滤器Filter”--> “制图器Mapper”--> “角色Actor”-->“渲染器Renderer”。其中,“过滤器Filter”是可由可无的,其他步骤一步都不能少。换句话说,单纯新建角色语句(vtkActor cylinderActor = vtkActor.New(); )并不会产生角色。 数据进入管道,角色进入渲染器,才能在视窗中见到角色。
另注意调节角色的大小,VTK默认的角色位置为VTK的世界坐标原点,请避免角色的重叠和遮挡。后续会讨论控件坐标和转换问题。
2. 添加“渲染器Renderer"
创建新的浏览器后,通过AddActor()添加角色,角色可以在多个不同浏览器中出现。通过SetViewport()设置浏览器在可视化控件中的位置,SetBackground()给浏览器赋予背景色。
注意:
(1)Viewport窗口的坐标赋值,控件的左下角为原点,X轴由左向右[0.0,1.0],Y轴由下向上[0.0,1.0];
(2)各自“浏览器Renderer”的交互操作是独立完整的;
(3)同一控件中的“浏览器Renderer”是可以相互重叠或遮挡的,具体效果请自行测试。