WinForm内嵌Unity3D
Unity3D可以C#脚本进行开,使用vstu2013.msi插件,可以实现在VS2013中的调试。在开发完成后,由于项目需要,需要将Unity3D嵌入到WinForm中。WinForm中的UnityWebPlayer Control可以载入Unity3D。先看效果图。
一、为了能够动态设置axUnityWebPlayer的Src,我使用用户控件来封装。看下面的代码。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;namespace UnityHost
{public partial class U3DPlayer : UserControl, IMessageFilter{#region 属性private String _src;/// <summary>/// Unity3D文件的路径/// </summary>public String Src{get { return _src; }private set { _src = value; }}private bool _disableMouseRight = true;/// <summary>/// 禁用鼠标右键/// </summary>public bool DisableMouseRight{get { return _disableMouseRight; }set { _disableMouseRight = value; }}#endregion#region 自定义事件//委托public delegate void ExternalCallHandler(object sender, AxUnityWebPlayerAXLib._DUnityWebPlayerAXEvents_OnExternalCallEvent e);/// <summary>/// 接收Unity调用宿主函数的消息/// </summary>[Browsable(true), Description("接收Unity调用宿主(如WinForm)函数的消息")]public event ExternalCallHandler UnityCall;//方法public void OnUnityCall(object sender, AxUnityWebPlayerAXLib._DUnityWebPlayerAXEvents_OnExternalCallEvent e){if (UnityCall != null){UnityCall(sender, e);}}#endregion#region 内部变量private AxUnityWebPlayerAXLib.AxUnityWebPlayer _axUnityWebPlayer=null;private ProgressBar _progressBarLoad=null;#endregionpublic U3DPlayer(){InitializeComponent();InitProgressBar();}private void InitProgressBar(){if (_progressBarLoad == null){_progressBarLoad = new ProgressBar();_progressBarLoad.Height = 100;_progressBarLoad.Style = ProgressBarStyle.Marquee;_progressBarLoad.Top = (this.Height - _progressBarLoad.Height) / 2;Controls.Add(_progressBarLoad);}}#region InitUnity/// <summary>/// 初始化UnityWebPlayer/// </summary>/// <param name="src">Unity3D文件的路径</param>public void InitUnity(String src){Src = src;if (!File.Exists(Src)){return;}var unity = new AxUnityWebPlayerAXLib.AxUnityWebPlayer();((System.ComponentModel.ISupportInitialize)(unity)).BeginInit();Controls.Add(unity);((System.ComponentModel.ISupportInitialize)(unity)).EndInit();unity.src = Src;//Application.StartupPath + "\\u.unity3d"; //改成自己想要的路径AxHost.State state = unity.OcxState;Controls.Remove(unity);unity.Dispose();unity = new AxUnityWebPlayerAXLib.AxUnityWebPlayer();((System.ComponentModel.ISupportInitialize)(unity)).BeginInit();this.SuspendLayout();unity.Dock = DockStyle.Fill;//unity.Name = "Unity";unity.OcxState = state;unity.TabIndex = 0;this.Controls.Add(unity); //panel1是我用的一个容器,改成this.Controls也可以((System.ComponentModel.ISupportInitialize)(unity)).EndInit();this.ResumeLayout(false);_axUnityWebPlayer = unity;if (_axUnityWebPlayer == null){throw new Exception("_axUnityWebPlayer init fail");}else{_axUnityWebPlayer.OnExternalCall += _axUnityWebPlayer_OnExternalCall;_axUnityWebPlayer.Hide();ShowProgressBar();}}#endregion#region 进度条private void ShowProgressBar(){ _progressBarLoad.Visible = true;_progressBarLoad.Left = 0;_progressBarLoad.Width = this.Width;}private void HideProgressBar(){if (_progressBarLoad!=null){_progressBarLoad.Visible = false; } }#endregionvoid _axUnityWebPlayer_OnExternalCall(object sender, AxUnityWebPlayerAXLib._DUnityWebPlayerAXEvents_OnExternalCallEvent e){if (e.value.StartsWith("LOAD_COMPLETE")){if (!_axUnityWebPlayer.Visible){_axUnityWebPlayer.Width = this.Width;_axUnityWebPlayer.Height = this.Height;_axUnityWebPlayer.Show();HideProgressBar();}}OnUnityCall(sender, e);}private void U3DPlayer_Load(object sender, EventArgs e){Graphics g = this.CreateGraphics();g.Clear(this.BackColor);if (DisableMouseRight){Application.AddMessageFilter(this);this.Disposed += U3DPlayer_Disposed;}}void U3DPlayer_Disposed(object sender, EventArgs e){if (DisableMouseRight){Application.RemoveMessageFilter(this);}}#region SendMessage/// <summary>/// 发送消息给Unity/// </summary>/// <param name="unityObjName">Unity中的对象名称</param>/// <param name="unityScriptyMethod">Unity脚本中的方法</param>/// <param name="val">传送的值.仅限于int、float、string</param>public void SendMessage(string unityObjName, string unityScriptyMethod, object val){if (_axUnityWebPlayer == null){return;}_axUnityWebPlayer.SendMessage(unityObjName, unityScriptyMethod, val);}#endregionprivate void U3DPlayer_MouseDown(object sender, MouseEventArgs e){}/// <summary>/// 过滤鼠标右键/// </summary>/// <param name="m"></param>/// <returns></returns>public bool PreFilterMessage(ref System.Windows.Forms.Message m){if (_axUnityWebPlayer == null){return false;}const int WM_RBUTTONDOWN = 0x204;const int WM_RBUTTONUP = 0x205;const int WM_RBUTTONDBLCLK = 0x206;// 屏蔽右键消息区域。System.Drawing.Rectangle my_Area = new System.Drawing.Rectangle(_axUnityWebPlayer.Location, _axUnityWebPlayer.Size);if (my_Area.Contains(this.PointToClient(Control.MousePosition))){switch (m.Msg){case WM_RBUTTONDOWN:return true;case WM_RBUTTONUP:return true;case WM_RBUTTONDBLCLK:return true;default:return false;}}return false;}}
}
注:代码中还实现了其他的功能,如下
1.增加InitUnity方法,方便外层控件调用。这里最关键的是OcxState,必须使用AxUnityWebPlayer才能依据Src动态产生。
2.动态增加进度条。
3.在实始化后对_axUnityWebPlayer进行隐藏,同时启动进度条,并绑定Unity的回调事件OnExternalCall。在OnExternalCall事件中,监听Unity发来的LOAD_COMPLETE值,然后判断是否显示_axUnityWebPlayer.
4.为了能让外层也收到Unity发来的消息,使用委托二次实现了OnExternalCall,也就是OnUnityCall方法。
5.SendMessage的实现,第一个参数为Unity中的对象名称,第二个参数为Unity脚本中的方法,第三个参数是传送的值(仅限于int、string,其他的会失败或者异常)。
6.继承IMessageFilter接口,捕获消息,然后过滤_axUnityWebPlayer区域内产生的鼠标右键消息,同时增加DisableMouseRight属性来控制。
7.一定要将项目调成x86的模式,否则会报“没有注册类XXX”的信息。
8.axUnityWebPlayer控件需要在工具箱中添加,如下图。
二、窗体界面的代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;namespace UnityHost
{public partial class FormHost : Form{public FormHost(){InitializeComponent();}private void buttonSendToUnity_Click(object sender, EventArgs e){String info = textBoxSendMessage.Text;if (String.IsNullOrWhiteSpace(info)){MessageBox.Show("请输入内容");return;}u3DPlayer1.SendMessage("Main Camera", "CallUnity", info);}private void FormHost_Load(object sender, EventArgs e){String src = Application.StartupPath + "\\UnityWeb\\UnityWeb.unity3d";u3DPlayer1.InitUnity(src);}private void u3DPlayer1_UnityCall(object sender, AxUnityWebPlayerAXLib._DUnityWebPlayerAXEvents_OnExternalCallEvent e){this.Text = "收到Unity的消息:" + e.value;}}
}
三、Unity3D的C#脚本
using UnityEngine;
using System.Collections;
using System;public class Main : MonoBehaviour
{private string _messageReceive = string.Empty;private bool _isButtonClick = false;private int _notifyTimeAfterLoadComplete = 3;// Use this for initializationvoid Start(){}// Update is called once per framevoid Update(){}void OnGUI(){if (GUI.Button(new Rect(100, 10, 80, 20), "测试")){_isButtonClick = !_isButtonClick;}GUI.Label(new Rect(50, 30, 150, 30), _messageReceive);if (_isButtonClick){Application.ExternalCall("ToWinform", Guid.NewGuid().ToString());_isButtonClick = false;}if (_notifyTimeAfterLoadComplete>0){Application.ExternalCall("LOAD_COMPLETE", "");_notifyTimeAfterLoadComplete--;}}void CallUnity(object val){_messageReceive = string.Format("{0}", val);}
}
注:
1.CallUnity是响应WinForm发来消息的函数。
2.Application.ExternalCall是向WinForm发出消息,第一参数是函数的名称,第二个之后的参数是函数的参数。
四、Unity3D要在WebPlayer模式下编译
转载请注明出处
代码下载http://download.csdn.net/detail/xxdddail/9277447
相关文章:
WinForm内嵌Unity3D
Unity3D可以C#脚本进行开,使用vstu2013.msi插件,可以实现在VS2013中的调试。在开发完成后,由于项目需要,需要将Unity3D嵌入到WinForm中。WinForm中的UnityWebPlayer Control可以载入Unity3D。先看效果图。 一、为了能够动态设置ax…...
关于vue中v-for绑定数据重新渲染的问题
我修改被v-for绑定的数据,发现居然不能重新渲染。 查找后得知一下方法: $set 是 Vue 提供的一个全局方法,用于向响应式对象中添加或更新属性,并触发视图更新。它接受三个参数:对象、要添加/更新的属性名或索引,以及新…...
全面解析 Axios 请求库的基本使用方法
Axios 是一个流行的基于 Promise 的 HTTP 请求库,用于在浏览器和 Node.js 中进行 HTTP 请求。它提供了简单易用的 API,可以发送各种类型的请求(如 GET、POST、PUT、DELETE等),并处理响应数据,Axios 在前端工…...
rust踩雷笔记3——生命周期的理解
目录 概念和基本使用一个例子彻底理解最基本的内容 一个例子理解函数签名为什么要有生命周期标注⭐️能不能对编译器蒙混过关? 生命周期是rust中最难的概念——鲁迅 这一块内容即便是看rust圣经,第一遍也有点懵。今天早上二刷突然有了更直观的认识&…...
windows权限维持—黄金白银票据隐藏用户远控RustDeskGotoHttp
windows权限维持—黄金白银票据&隐藏用户&远控&RustDesk&GotoHttp 1. 前置1.1. 初始问题1.1.1. 解决办法 2. 隐藏用户2.1. 工具原理2.2. 案例操作2.2.1. 单机添加用户2.2.1.1. 工具添加用户2.2.1.2. 工具查看隐藏用户2.2.1.3. 本地查看隐藏用户 2.2.2. 域内添加…...
vscode conda activate激活环境出错
vscode conda activate 出错 conda-script.py: error: argument COMMAND: invalid choice: ‘activate’ To initialize your shell, run$ conda init <SHELL_NAME>Currently supported shells are:- bash- fish- tcsh- xonsh- zsh- powershellSee conda init --help f…...
信息与通信工程面试准备——数学知识|正态分布|中心极限定理
目录 正态分布 正态分布的参数 正态分布的第一个参数是均值 正态分布的第二个参数是标准差SD 所有正态分布的共同特征 标准正态分布:正态分布的特例 中心极限定理 理解定义 示例# 1 示例# 2 知道样本均值总是正态分布的实际含义是什么? 正态分…...
Mybatis多表查询与动态SQL的使用
目录 1. Mybatis多表查询 1.1 添加文章表实体类 1.2 文章Interface 1.3 文章.xml 1.4 lombok的toString()有关对象打印的说明 1.5 场景: 一个用户查询多篇文章 2. 复杂情况: 动态SQL的使用 2.1 为什么要使用动态SQL? 2.2 <if>标签 2.3 <trim>标签 2.4 <where&g…...
url 和 uri 有什么区别?
URL(Uniform Resource Locator)和URI(Uniform Resource Identifier)是两个与网络资源定位和标识相关的概念,它们有一些区别,但也存在一些重叠。 URI(Uniform Resource Identifier)是…...
HCIP VLAN实验
VLAN实验 拓扑图配置和分析分析配置LSW1LSW2R1 测试dhcp获取ipICMP测试 拓扑图 配置和分析 分析 从题目来看,因为 pc 1 3都是vlan2而且还是不同网段,pc 2 4 5 6在同一网段,所以可以将pc 1 2 5 4 6分在一个网段 pc4不通5 6 ,那就…...
无涯教程-Perl - waitpid函数
描述 该函数等待ID为PID的子进程终止,返回已故进程的进程ID。如果PID不存在,则返回-1。进程的退出状态包含在$?中。 可以将标志设置为各种值,这些值等于waitpid()UNIX系统调用使用的值。 FLAGS的值为0应该在支持进程的所有操作系统上工作。 语法 以下是此函数的简单语法- …...
Redis之缓存雪崩、缓存击穿、缓存穿透问题
文章目录 前言一、缓存雪崩1.1、原因分析2.2、常用解决方案 二、缓存击穿2.1、原因分析2.2、常用解决方案2.2.1、使用互斥锁2.2.2、逻辑过期方案2.3、方案对比 三、缓存穿透3.1、原因分析3.2、解决方案3.2.1、缓存空对象3.2.3、布隆过滤3.3、方案对比 总结 前言 本文谈谈Redis…...
九五从零开始的运维之路(其三十五)
文章目录 前言一、概述1.概念2.组成3.特点4.工作原理5.优点: 二、各节点及其ip地址三、构建MHA1.ssh免密登录2.构建mysql主从复制(一)安装mariadb数据库并启动(二)master服务器(三)slave服务器&…...
5G科技防汛,助力守护一方平安
“立秋虽已至,炎夏尚还在”,受台风席卷以及季节性影响全国多地正面临强降水的严峻挑战。“落雨又顺秋,绵绵雨不休”,正值“七下八上” 防汛关键时期,贵州省水文水资源局已全面进入备战状态。 为确保及时响应做好防汛抢…...
用easyui DataGrid编辑树形资料
easyui显示编辑树形资料有TreeGrid元件,但是这个元件的vue版本和react版本没有分页功能。virtual scroll功能也表现不佳。 我用DataGrid来处理。要解决的问题点: (1)如何显示成树形。即,子节点如何有缩进。 先计算好…...
Azure存储账户
存储账户的概念 Azure存储账户是Azure提供的一种云存储解决方案,用于存储和访问各种类型的数据,包括文件、磁盘、队列、表格和Blob(二进制大对象)数据。存储账户可以基于访问模式和冗余需求来选择不同的类型,以满足应…...
数字人服装布料解算技术服务,让数字人驱动更真实
一个数字人通过三维建模、骨骼绑定、表情绑定后,对于数字人有两种使用场景,可以使用动捕设备实时驱动,将静态的3D模型结合动捕设备实时“活”起来。数字人通过动捕设备实时驱动的过程,则是基于实时布料毛发解算方案进行技术处理的…...
达梦数据库安装与初始化超详细教程
陈老老老板🦸 👨💻本文专栏:国产数据库-达梦数据库(主要讲一些达梦数据库相关的内容) 👨💻本文简述:本文讲一下达梦数据库的下载与安装教程(Windows版&am…...
vue输入框只能输入数字类型,禁止输入和粘贴e
js怎么去除1e里面e 方法一:使用 Number() 函数将科学计数法表示的字符串转换为数字。然后,使用 toString() 方法将其转换回字符串形式,这样就会自动移除科学计数法中的 "e" var num 1e10; // 科学计数法表示的数字 var numStr …...
金盘 微信管理平台 getsysteminfo 未授权访问漏洞[2023-HW]
金盘 微信管理平台 getsysteminfo 未授权访问漏洞 一、漏洞描述二、漏洞影响三、网络测绘四、漏洞复现小龙POC检测: 五、 修复建议 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...
数据挖掘是什么?数据挖掘技术有哪些?
目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…...
