web-dev-qa-db-fra.com

Intégrer l'application Unity3D dans l'application WPF

Je souhaite développer un nouveau logiciel CAD dans WPF et au lieu d'utiliser WPF 3D, est-il possible d'utiliser Unity3D comme moteur graphique capable de faire pivoter, de faire un panoramique, de zoomer et d'afficher des objets graphiques 3D basé sur mes objets de données dans WPF?

La raison pour laquelle je pose cette question est que Unity est un moteur de jeu, il utilise C # comme script mais il ne fournit aucune intégration à partir de l'application WPF (intègre Unity dans WPF).

J'ai posé la question dans le forum de l'unité, je n'ai pas trouvé de bonne réponse, donc je le demande à un public plus large.

Cela peut être fait, mais il convient de noter que cela ne fonctionnera que sous Windows.

Auparavant, c'était difficile, mais Unity a récemment ajouté (4.5.5p1) -parentHWND commande qui peut être utilisée pour incorporer son programme dans un autre programme. Tout ce que vous avez à faire est de créer votre application Unity, puis à partir de WPF, démarrez-la avec l'API Process. Vous pouvez ensuite passer le -parentHWND paramètre de l'application Unity.

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

Pour la commutation entre les deux, vous pouvez utiliser TCP ou Named Pipes .

Vous trouverez ci-dessous un exemple complet du code d'intégration du site Web d'Unity. Vous pouvez obtenir l'ensemble du projet ici . Assurez-vous de nommer le fichier exe de construction d'Unity "UnityGame.exe" , puis placez-le dans le même répertoire que le programme exe WPF.

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();
        }
    }
}
27
Programmer