unity楼层内摄像头模型设计碰撞点击、hover等功能及与web交互视频流显示全流程记录

一、Unity端开发

(1)楼层模型设计碰撞点击

在unity工程中依次点击左侧层级楼层内的摄像头模型----点击右侧检查器内的【添加组件】按钮----点击 Box Collider----在Box Collider组件内点击【编辑碰撞器】----调整碰撞器的四周位置,使得摄像头模型被碰撞器边界线完全包裹

image

image

 以上方法依次处理各个摄像头模型。

(3)编写碰撞体碰撞处理脚本

(3.1)

  在unity项目层级下的Scripts文件夹下新建脚本CameraColliderAndHover.cs;在脚本内部删除自动生成的void Start(),void Update()方法(用于该脚本用户处理hover事件和click事件,用不到帧相关操作);在脚本追加摄像头的基础属性配置信息

image

image

 (3.2)依次将脚本绑定到摄像头中,并填写摄像头基础属性信息

image

 (3.3)在unity项目层级下的Plugins下新建CameraHover&Click.jslib中间件文件,用于后续unity事件被监听后,调用中间件指定方法,再通过该方法内部调用web端暴露的js函数,实现unity--->web通信交互

 image

 (3.4)引入jslib中间件函数、编写C#脚本hover事件与点击事件的业务逻辑

CameraHover&Click.jslib中间件内部定义:

 1 mergeInto(LibraryManager.library, {
 2 //摄像头被hover时
 3     CameraBeHovering: function (cameraname, cameraip,x, y) {
 4         var cameraname = UTF8ToString(cameraname);
 5         var cameraip = UTF8ToString(cameraip);
 6 
 7         // 调用网页上暴露的全局方法
 8         if (window.ShowCameraTooltip) {
 9             window.ShowCameraTooltip(cameraname, cameraip,x, y);
10         }
11     },
12 //摄像头被hover后离开时
13     CameraBeHovered: function () {
14         if (window.HideCameraTooltip) {
15             window.HideCameraTooltip();
16         }
17     },
18 //摄像头被点击时
19     CameraBeClicked: function (cameraname, cameraip) {
20         var cameraname = UTF8ToString(cameraname);
21         var cameraip = UTF8ToString(cameraip);
22 
23         if (window.HandleCameraClick) {
24             window.HandleCameraClick(cameraname, cameraip);
25         }
26     }
27 });

CameraColliderAndHover.cs内部定义: 

1 using System.Collections; 
2 using System.Collections.Generic 
3 using System.Runtime.InteropServices;

4
using UnityEngine; 5 using UnityEngine.EventSystems; 6 7 /// <summary> 8 /// 用于处理第二页楼层内摄像头模型的点击事件和hover事件的处理(也会涉及unity通知jslib进而调用webjs逻辑) 9 /// </summary> 10 public class CameraColliderAndHover : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler,IPointerClickHandler 11 { 12 [Header("摄像头名称/位置")] 13 public string cameraName; 14 15 [Header("摄像头IP")] 16 public string cameraIP; 17 18 19 ////--------------- 引入中间件jslib定义的中间方法 (会自动搜索中间件方法)---------------------- 20 //注意: 21 //.jslib 定义的函数只会在 WebGL 构建产物里被 Unity 的 WebGL 桥接系统生成/绑定成可调用的符号;在 **Editor 里运行(UNITY_EDITOR)**时,这个符号根本不存在 22 //所以在函数调用处,加 #if UNITY_WEBGL && !UNITY_EDITOR #else #endif等判断,避免unity editor调试时报错!! 23 24 //摄像头被hover时 25 [DllImport("__Internal")] 26 private static extern void CameraBeHovering(string cameraname,string cameraip,float x,float y ); 27 28 //摄像头被hover后离开时 29 [DllImport("__Internal")] 30 private static extern void CameraBeHovered(); 31 32 //摄像头被点击时 33 [DllImport("__Internal")] 34 private static extern void CameraBeClicked(string cameraname, string cameraip); 35 36 37 ////--------------- hover、click业务逻辑方法 ---------------------- 38 39 40 /// <summary> 41 /// 1. 实现IPointerEnterHandler接口方法 42 /// 43 /// 摄像头被hover时 44 /// </summary> 45 /// <param name="eventData"></param> 46 public void OnPointerEnter(PointerEventData eventData) 47 { 48 //获取鼠标hover时的转换到屏幕平面的(X,Y)位置 49 float webX = Input.mousePosition.x; 50 //注意:Unity的Y轴是从下往上;而Web的Y轴是从上往下 51 float webY = Screen.height - Input.mousePosition.y; 52 #if UNITY_WEBGL && !UNITY_EDITOR 53 CameraBeHovering(cameraName, cameraIP, webX, webY);//调用中间件方法 54 #else 55 Debug.Log($"摄像头被hoverl了,webX,WebY:{webX},{webY}"); 56 #endif 57 } 58 59 60 /// <summary> 61 /// 2. 实现IPointerExitHandler接口方法 62 /// </summary> 63 /// <param name="eventData"></param> 64 65 public void OnPointerExit(PointerEventData eventData) 66 { 67 #if UNITY_WEBGL && !UNITY_EDITOR 68 CameraBeHovered();//调用中间件方法 69 #else 70 Debug.Log($"摄像头hover离开,触发隐藏!"); 71 #endif 72 } 73 74 75 /// <summary> 76 /// 3. 实现IPointerClickHandler接口方法
    /// (这个点击不会被触发,因为该脚本挂在摄像头模型上,摄像头模型又在11层模型内部,而楼层模型都挂载了抽屉监控脚本,他也是监控左键点击事件。所以当摄像头模型被点击,他只会当成楼层被点击了,所以不起作用。)
    ///  改用下面的OnPointerDown方法
77 /// </summary> 78 /// <param name="eventData"></param> 79

// public void OnPointerClick(PointerEventData eventData)
// {
//#if UNITY_WEBGL && !UNITY_EDITOR
// CameraBeClicked(cameraName, cameraIP);
//#else
// Debug.Log($"摄像头被点击,触发通知web端显示弹出框并显示视频流!");
//#endif
// }

 


public void OnPointerDown(PointerEventData eventData)
{
#if UNITY_WEBGL && !UNITY_EDITOR
CameraBeClicked(cameraName, cameraIP);
#else
Debug.Log($"摄像头被点击,触发通知web端显示弹出框并显示视频流!");
#endif
}

88 }

二、Web端开发

 (1)构建浮动框div结构及CSS样式 (先占物理位置,未动态在js中生成div结构)、以及hover进/hover出的全局js脚本

(1.1)在第二页tab页内追加编写浮动框div结构:

image

 (1.2)编写上述div结构配套的CSS样式:

image

 可以看到效果已显示:

image

(1.3)编写全局js函数,处理用户hover进出unity摄像头模型动作 (中间件jslib调用的全局函数,就是此处web端定义的全局js函数)

 1 <!--第二页场景交互 摄像头hover以及点击交互,对应unity端的CameraHover&Click.jslib 中间件和 CameraColliderAndHover.cs C#脚本  -->
 2   <script>
 3 
 4     //(1)hover摄像头进行信息提示框显示
 5     window.ShowCameraTooltip = function (cameraName, cameraIP, screenX, screenY) {
 6       const tooltip = document.getElementById('cameraHoverTooltip');
 7       //根据cameraId调用后端接口获取数据,此处先用假数据代替
 8       //var data = GetCameraTooltipData;
 9 
10       document.getElementById('cameraHoverName').innerText = "位置:" + cameraName;
11       document.getElementById('cameraHoverIp').innerText = "IP:" + cameraIP;
12 
13       //设置tooltip的偏移位置
14       tooltip.style.left = screenX + 'px';
15       tooltip.style.top = screenY + 'px';
16       //让tootip显示
17       tooltip.style.display = 'block';
18     };
19 
20     //(2)hover离开摄像头取消信息提示框显示
21     window.HideCameraTooltip = function () {
22       const tooltip = document.getElementById("cameraHoverTooltip");
23       tooltip.style.display = "none";
    }
24  </script>
31

hover实际验证:

image

 (2)构建视频流显示div结构及CSS样式

 (2.1)在原有第二页tab页内部的html结构中的顶部追加视频弹出框的结构div

1  <!--第二页的视频弹出框(参考之前项目)-->
2              <div id="cameraModal" class="modal">
3               <div class="modal-content">
4                 <span id="camera-close-btn"  class="close-btn">&times;</span>
5                 <video id="modalCameraVideo" autoplay controls></video>
6                 <div id="modalCameraLabel" class="modal-camera-label">摄像头1(监控视角)</div>
7               </div>
8             </div> 

(2.2)配套的CSS

 1 /* 弹窗样式 */
 2 .modal {
 3   display: none;
 4   position: fixed;
 5   z-index: 10000;
 6   left: 0;
 7   top: 0;
 8   width: 100%;
 9   height: 100%;
10   background-color: rgba(0, 0, 0, 0.8);
11   justify-content: center;
12   align-items: center;
13 
14   pointer-events: auto;
15 }
16 
17 .modal-content {
18   position: relative;
19   width: 50vw;
20   height: 65vh;
21   background-color: #000;
22   border-radius: 5px;
23   overflow: hidden;
24 }
25 
26 .close-btn {
27   position: absolute;
28   top: 10px;
29   right: 15px;
30   color: rgb(246, 6, 6);
31   font-size: 28px;
32   font-weight: bold;
33   cursor: pointer;
34   z-index: 10000;
35 }
36 
37 .close-btn:hover {
38   color: #f96d10;
39 }
40 
41 #modalCameraVideo{
42   width: 100%;
43   height: 100%;
44   object-fit: contain;
45 }
46 
47 .modal-camera-label {
48   position: absolute;
49   bottom: 10px;
50   left: 10px;
51   color: white;
52   background-color: rgba(0, 0, 0, 0.5);
53   padding: 5px 10px;
54   border-radius: 3px;
55   font-size: 14px;
56 }

 

(3)webrtc-streamer工具进行视频流转换,js使用逻辑编写

(3.1) webrtc-streamer rtsp视频流转换工具搭建

rtsp视频流是无法直接在浏览器中显示的(rtsp流可以直接在客户端编写的程序中显示),要想解决这个问题,可以使用轻量化的webrtc工具:webrtc-streamer.
下载地址:Release v0.8.15 · mpromonet/webrtc-streamer · GitHub

解压到本地,找到内部的bin文件夹,双击.exe文件即启动了该工具:

image

 注意:也可以通过cmd命令框参数命令来启动webrtc-streamer工具,自定义指定服务端口;也可以通过nssm工具,设置启动命令参数,配置成开机自启动服务。(此处不展示操作)

(3.2)编写unity摄像头物体被点击时,调用摄像头视频显示定义的方法

(unity监听到鼠标被按下---->调用jslib中间件函数CameraBeClicked(cameraName, cameraIP)--->进而调用js全局函数 window.HandleCameraClick ---->在该内部编写摄像头模型被点击时,web端要执行的逻辑)

1 //(3)点击摄像头进行视频弹窗显示
2       window.HandleCameraClick = function (cameraName, cameraIp) {
3         window.FloorCameraVideo(cameraName, cameraIp);
4       }

 

(3.3)上述摄像头弹出显示方法的具体业务逻辑

为了方便全局调用,定义了全局方法:window.FloorCameraVideo(cameraName, cameraIp)

 1 //全局公共变量
 2 var WEBRTC_SERVER = "http://localhost:8000";//webrtc-streamer工具部署的服务器地址
 3 window.FloorCameraVideo = function (cameraName, cameraIp) {
 4   //alert(`全局方法有效!点击了${cameraName},摄像头IP地址是${cameraIp},后续可在此处添加打开视频弹窗的功能!`);
 5   //把第一人称按钮、关闭楼层按钮等都先隐藏,等视频弹窗关闭后再恢复显示
 6   document.getElementById("fpsToggleBtn").style.display = "none";
 7   document.getElementById("closefloorBtn").style.display = "none";
 8 
 9   //获取元素
10   var modal = document.getElementById('cameraModal');//获取弹出框顶级div对象
11   modal.style.display = 'flex';//显示弹出框
12 
13   var modalVideo = document.getElementById('modalCameraVideo');//获取弹出框内video对象
14   var closeBtn = document.getElementById("camera-close-btn");//获取弹出框内关闭按钮对象
15   var videoLabel = document.getElementById("modalCameraLabel");//获取设置摄像头名称的元素对象
16 
17   //设置摄像头名称显示
18   videoLabel.textContent = cameraName;
19 
20   //核心的2步代码:实例化webrtc-streamer对象并进行连接    
21   var webrtc = new WebRtcStreamer(modalVideo, WEBRTC_SERVER);
22   //webrtc.connect(cameraIp,null,"rtptransport=tcp&timeout=60",null);//执行连接
23   webrtc.connect("rtsp://stream.strba.sk:1935/strba/VYHLAD_JAZERO.stream", null, "rtptransport=tcp&timeout=60", null);//临时测试
24 
25   //页面卸载时清理资源
26   window.addEventListener('beforeunload', function () {
27     webrtc.disconnect();
28   });
29 
30   // 关闭弹窗
31   closeBtn.onclick = function () {
32 
33     //再重新恢复button按钮的显示
34     document.getElementById("fpsToggleBtn").style.display = "block";
35     document.getElementById("closefloorBtn").style.display = "block";
36  
37     modal.style.display = 'none';
38     webrtc.disconnect();
39 
40   };
41 }

最终点击摄像头模型,显示了视频:

image

 

posted @ 2026-04-27 16:23  上清风  阅读(29)  评论(0)    收藏  举报