在WPF应用程序内嵌入Unity3D应用程序

问题描述:

我想在WPF中开发一个新的CAD软件,而不是使用WPF 3D,是否可以使用Unity3D作为我的图形引擎,可以旋转,平移,缩放和查看3D图形对象基于我在WPF中的数据对象?在WPF应用程序内嵌入Unity3D应用程序

我问这个问题的原因是,Unity是一个游戏引擎,它使用C#作为脚本,但它没有提供任何WPF应用程序的集成(将Unity嵌入到WPF中)。

我在统一论坛上问过这个问题,找不到任何好的答案,所以要求更多的观众。

+0

是的,它可以处理Unity。尽管如此,你可以用任何3D游戏引擎进行平移,旋转和缩放,所以我不能说出这个问题的关键。 – Programmer

+0

非常感谢。我修改了我的问题,请看看。你有没有试过使用WPF作为你的主应用程序,并调用Unity3D来显示图形显示? – ParkAtStreet

+0

之前使用过WPF,但没有使用Unity。 WPF仅适用于Windows。如果你想使用它,然后使用它。如果你想使用Unity,那么去Unity。我认为没有必要混合两者。您最终将只能在Windows上运行一个复杂的应用程序。 – Programmer

这可以做到,但值得注意的是它只能在Windows上工作。

它曾经很难做到这一点,但最近Unity(4.5.5p1)添加了-parentHWND命令,可用于将其程序嵌入到另一个程序中。所有你需要做的就是构建你的Unity应用程序,然后从WPF开始,使用Process API。然后,您可以将-parentHWND参数传递给Unity应用程序。

process.StartInfo.FileName = "YourUnityApp.exe"; 
process.StartInfo.Arguments = "-parentHWND " + panel1.Handle.ToInt32() + " " + Environment.CommandLine; 

对于两者之间的换向,可以使用TCP或Named Pipes

下面是来自Unity网站的嵌入代码的完整示例。你可以得到整个项目here。确保命名Unity的构建EXE文件“UnityGame.exe”然后将其放在与WPF EXE程序相同的目录中。

namespace Container 
{ 
    public partial class Form1 : Form 
    { 
     [DllImport("User32.dll")] 
     static extern bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw); 

     internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam); 
     [DllImport("user32.dll")] 
     internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam); 

     [DllImport("user32.dll")] 
     static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); 

     private Process process; 
     private IntPtr unityHWND = IntPtr.Zero; 

     private const int WM_ACTIVATE = 0x0006; 
     private readonly IntPtr WA_ACTIVE = new IntPtr(1); 
     private readonly IntPtr WA_INACTIVE = new IntPtr(0); 

     public Form1() 
     { 
      InitializeComponent(); 

      try 
      { 
       process = new Process(); 
       process.StartInfo.FileName = "UnityGame.exe"; 
       process.StartInfo.Arguments = "-parentHWND " + panel1.Handle.ToInt32() + " " + Environment.CommandLine; 
       process.StartInfo.UseShellExecute = true; 
       process.StartInfo.CreateNoWindow = true; 

       process.Start(); 

       process.WaitForInputIdle(); 
       // Doesn't work for some reason ?! 
       //unityHWND = process.MainWindowHandle; 
       EnumChildWindows(panel1.Handle, WindowEnum, IntPtr.Zero); 

       unityHWNDLabel.Text = "Unity HWND: 0x" + unityHWND.ToString("X8"); 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message + ".\nCheck if Container.exe is placed next to UnityGame.exe."); 
      } 

     } 

     private void ActivateUnityWindow() 
     { 
      SendMessage(unityHWND, WM_ACTIVATE, WA_ACTIVE, IntPtr.Zero); 
     } 

     private void DeactivateUnityWindow() 
     { 
      SendMessage(unityHWND, WM_ACTIVATE, WA_INACTIVE, IntPtr.Zero); 
     } 

     private int WindowEnum(IntPtr hwnd, IntPtr lparam) 
     { 
      unityHWND = hwnd; 
      ActivateUnityWindow(); 
      return 0; 
     } 

     private void panel1_Resize(object sender, EventArgs e) 
     { 
      MoveWindow(unityHWND, 0, 0, panel1.Width, panel1.Height, true); 
      ActivateUnityWindow(); 
     } 

     // Close Unity application 
     private void Form1_FormClosed(object sender, FormClosedEventArgs e) 
     { 
      try 
      { 
       process.CloseMainWindow(); 

       Thread.Sleep(1000); 
       while (!process.HasExited) 
        process.Kill(); 
      } 
      catch (Exception) 
      { 

      } 
     } 

     private void Form1_Activated(object sender, EventArgs e) 
     { 
      ActivateUnityWindow(); 
     } 

     private void Form1_Deactivate(object sender, EventArgs e) 
     { 
      DeactivateUnityWindow(); 
     } 
    } 
} 
+1

非常感谢... – ParkAtStreet