안녕하세요!
이번 글에서는 WPF 프로젝트에서 VTK라이브러리를 사용하는 방법에 대해 공유해 볼까 합니다.
기존 MFC 에서만 사용하던 VTK 라이브러리를 WPF에 적용하게 되었는데, 메인 윈도우 에서 RenderWindowControl이 배치가 되지 않아 며칠간 고생하다 알아낸 방법입니다. 다른 좋은 방법이 있다면 댓글로 알려주시면 감사하겠습니다.
1. Activiz 라이브러리 설치
WPF프로젝트 생성 후 [도구] → [Nuget패키지 관리자] → [솔루션용 Nuget 패키지 관리...] → [찾아보기] 순으로 진입하여 'Activiz'라이브러리를 검색해 'Activiz.NET.x86'패키지를 설치하여줍니다.
- 테스트 시 Activiz.NET.x64 패키지 설치 과정에서 오류가 발생해 32비트 전용 패키지를 설치하여 사용했습니다.
2. 프로젝트에 Form 추가
WPF 프로젝트를 우클릭 후 [추가] → [새항목] 순으로 진입하여 [양식(Window Forms)]를 추가하여 줍니다.
3. RenderWindowControl추가
생성된 [Form1.cs]를 더블클릭하여 디자인 탭으로 이동 후 [도구상자]를 열고 Activiz의 [RenderWindowControl]을 폼에 드래그&드롭해줍니다.
4. 폼, 컨트롤 속성 변경
- Form의 [FormBorderStyle]속성을 'None'으로 변경해줍니다.
- RenderWindowControl의 [Dock]속성을 'Fill'로 변경해 줍니다.
5. WPF의 MainWindow.xaml 수정
추가한 Form 클래스를 생성하여 부착할 Grid를 추가해 줍니다.
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid Name="grid"/>
</Grid>
</Window>
- <Grid>와 </Grid> 사이 "grid"라는 이름을 가진 Grid를 추가해 주었습니다.
6. 참조 추가
WPF프로젝트 하위 [참조]를 우클릭 참조추가를 눌러 참조 관리자를 열어줍니다.
참조관리자의 [어셈블리] 탭에서 'System.Windows.Forms'와 'WindowsFormsIntegration'을 찾아 체크해 줍니다.
7. MainWindow 코드작성
MainWindow.xaml.cs로 이동하여 주가 한 Form객체를 생성하고 WPF윈도우 grid에 부착하는 코드를 작성하여 줍니다.
/* 위 네임스페이스 using 생략 */
using System.Windows.Forms.Integration;
namespace WpfApp1
{
/// <summary>
/// MainWindow.xaml에 대한 상호 작용 논리
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//추가 한 Form1클래스 객체
Form1 renderWindowForm = new Form1();
//Form1을 호스트 해줄 객체
WindowsFormsHost host = new WindowsFormsHost();
//Form을 최상위 레벨로 설정하지 않는다.
renderWindowForm.TopMost = false;
renderWindowForm.TopLevel = false;
//호스트 객체의 child로 폼을 할당.
host.Child = renderWindowForm;
//xaml에서 생성해준 grid에 추가
this.grid.Children.Add(host);
}
}
}
- 코드 해석은 주석을 참고해 주세요.
8. 빌드
- 렌더윈도우와 Form 객체가 잘 부착되어 까만 화면이 나옵니다.
9. 렌더윈도우에 ConeSource 추가 후 렌더링 테스트
Form1 클래스 메서드 작성 (Form1.cs)
/* 위 네임스페이스 using 생략 */
using Kitware.VTK;
namespace WpfApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//renderWindowControl1 로드 이벤트 메서드
private void renderWindowControl1_Load(object sender, EventArgs e)
{
try
{
Cone();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK);
}
}
//Cone 생성 후 렌더링
private void Cone()
{
// Cone생성.
vtkConeSource coneSource = vtkConeSource.New();
coneSource.SetCapping(1);
coneSource.SetRadius(0.5);
coneSource.SetResolution(32);
/* 파이프라인 연결 */
//Mapper
vtkPolyDataMapper mapper = vtkPolyDataMapper.New();
mapper.SetInputConnection(coneSource.GetOutputPort());
//Actor
vtkActor actor = vtkActor.New();
actor.SetMapper(mapper);
//RenderWindow
vtkRenderWindow renderWindow = renderWindowControl1.RenderWindow;
//Renderer
vtkRenderer renderer = renderWindow.GetRenderers().GetFirstRenderer();
renderer.SetBackground(0.3, 0.2, 0.1);
renderer.AddActor(actor);
renderer.ResetCamera();
}
}
}
- renderWindowControl1 로드 이벤트 메서드 [renderWindowControl1_Load] 추가
- 원뿔 생성 후 렌더윈도우에 렌더링 해주는 메서드[Cone] 추가
RenderWindowControl에 이벤트 추가(Form1.Designer.cs)
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.renderWindowControl1 = new Kitware.VTK.RenderWindowControl();
this.SuspendLayout();
//
// renderWindowControl1
//
this.renderWindowControl1.AddTestActors = false;
this.renderWindowControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.renderWindowControl1.Location = new System.Drawing.Point(0, 0);
this.renderWindowControl1.Margin = new System.Windows.Forms.Padding(5, 4, 5, 4);
this.renderWindowControl1.Name = "renderWindowControl1";
this.renderWindowControl1.Size = new System.Drawing.Size(800, 450);
this.renderWindowControl1.TabIndex = 0;
this.renderWindowControl1.TestText = null;
this.renderWindowControl1.Load += new System.EventHandler(this.renderWindowControl1_Load); // renderWIndowControl1의 로드 이벤트에 함수 추가.
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 18F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.renderWindowControl1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
- InitializeComponent메서드 내 이벤트함수를 추가해 주는 코드 작성
10. 빌드
여기까지 WPF 프로젝트에서 Activiz 라이브러리를 사용하여 렌더링 하는 방법을 공유해 드렸습니다.
더 좋은 방법이 있을 수도 있지만 제가 일주일 동안 찾은 방법 중 가장 쉽고 정확한 방법인 거 같습니다.
WPF프로젝트에서 3D렌더링이 필요하신 분들께 도움이 되었으면 좋겠습니다.
혹시 더 좋은 방법이 있다면 댓글로 알려주시면 너무나 감사하겠습니다.
감사합니다!
'[C#] > WPF' 카테고리의 다른 글
[C#] WPF : MVVM 패턴 (19) | 2023.08.31 |
---|---|
[C#] WPF : Graphic (31) | 2023.08.21 |
[C#] WPF : Control Handling (22) | 2023.08.17 |
[C#] WPF : XAML (37) | 2023.08.10 |
[C#] WPF : 프로젝트 생성 (24) | 2023.08.09 |