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

Ori*_*ney 18 c# 3d wpf cad unity-game-engine

我想在WPF中开发一个新的CAD软件而不是使用WPF 3D,是否可以使用Unity3D作为我的图形引擎,它能够根据WPF中的数据对象旋转,平移,缩放和查看3D图形对象?

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

我在团结论坛上问了这个问题,找不到任何好的答案,所以要求更多的观众.

Pro*_*mer 30

这可以做到,但值得注意的是它只能在Windows上运行.

过去很难做到这一点,但Unity最近(4.5.5p1)添加-parentHWND了可用于将程序嵌入另一个程序的命令.您所要做的就是构建Unity应用程序,然后从WPF开始,使用ProcessAPI 启动它.然后,您可以将-parentHWND参数传递给Unity应用程序.

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

对于两者之间的换向,您可以使用TCP或命名管道.

以下是Unity网站上嵌入代码的完整示例.你可以在这里获得整个项目.确保将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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢。但这是针对 Windows 窗体项目的。要使其在 WPF 中工作,请使用 xmlns:wf="clr-namespace:System.Windows.Forms; assembly=System.Windows.Forms" <WindowsFormsHost Grid.Row="1"> <wf:Panel x:Name="panel1 " Resize="panel1_Resize" Height="500" Width="500"/> </WindowsFormsHost> c# 几乎相同。执行“attachUnity();” 在 Window_Loaded 而不是构造函数中,因为 Hwnd 尚未准备好。 (4认同)