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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44059182/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 14:05:26  来源:igfitidea点击:

Embed Unity3D app inside WPF application

c#wpfunity3d3dcad

提问by OrionSoftTechnologiesSydney

I want to develop a new CAD software in WPF and instead of using WPF 3D, is it possible to use Unity3D as my graphic engine that is capable of rotate, pan, zoom and view 3D graphic objects based on my data objects in WPF?

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

The reason I am asking this question is, Unity is a game engine, it uses C# as script but it does not provide any integration from WPF application (embeds Unity into WPF).

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

I asked the question in unity forum, could not find any good answer, so asking to a larger audience.

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

回答by Programmer

This can be done but it's worth noting that it will only work on Windows.

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

It used to be hard to do this but Unity recently(4.5.5p1) added -parentHWNDcommand that can be used to embed its program into another program. All you have to do is build your Unity app, then from WPF, start it with the ProcessAPI. You can then pass the -parentHWNDparameter to the Unity app.

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

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

For commutation between the two, you can either use TCP or Named Pipes.

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

Below is a complete sample of the embed code from Unity's website. You can get the whole project here. Make sure to name the Unity's build exe file "UnityGame.exe"then place it in the-same directory as the WPF exe program.

以下是来自 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();
        }
    }
}