Hololens与ARcore结合实现第三视角(二)

1.开发工具及SDK

Unity2018

ARcore-unity-sdk-1.6 

Vuforia for hololens

项目演示效果:

人手不够就直接在Hololens上录了一个第一视角

2.原理:

Hololens及支持ARcore的手机均有各自的空间连续定位功能,我们要做的就是这两种设备能够统一空间坐标,这样就能准确的同步各自的操作。

最早的使用两台Hololens和一台相机的第三视角方案,原理是同步两台Holoens的锚点数据,这样就知道摄像机上面的那个Hololens的位置了,再通过Calibration软件通过获取Hololens及相机拍摄照片经过算法处理,生产一个校准文件,这个校准文件校准的就是Hololens和相机的位置角度偏移值、unity camera相机的fov,这样最后合成的视频就是正确的。

整个流程复杂,涉及C++语言和图像图形技术等,需要自己编译库,安装采集卡及驱动,有一个环节出问题就会运行不起来,就白忙活了,我之前折腾时就在相机这块踩坑了,先用的佳能,最后换了尼康的采可以,在相机这块官方也没有给出具体的适配型号...

Hololens官方第三视角技术

总之,这一套第三视角确实不太好用,下面我们就开始Hololens&ARcore的第三视角折腾之旅吧~

3.定位同步

3.1网络:

 

Hololens与ARcore结合实现第三视角(二)_第1张图片

本案例使用的是异步SocketAsyncEventArgs,支持手机及Hololens平台

关键代码:

private Socket client;
    private IPEndPoint hostEndPoint;
    private List buffer;
    private AutoResetEvent connetEvent;
    
    public delegate void OnConnectResult(bool result);
    public  OnConnectResult ConnectResultEvent;

    public delegate void OnDataReceived(byte[] data);
    public  OnDataReceived DataReceiveEvent;

    public delegate void OnDisconnet();
    public  OnDisconnet DisconnectEvent;

    private int PoolCapacity; 
    private Stack SendAsyncPool;
    private SocketAsyncEventArgs ReceiveAsync;
    public bool Connected
    {
        get { return client != null && client.Connected; }
    }
    public void ConnectServer(string serverIP,int port)
    {
        if (Connected) return;

        hostEndPoint = new IPEndPoint(IPAddress.Parse(serverIP),port);
        buffer = new List();
        client = new Socket(hostEndPoint.AddressFamily,SocketType.Stream,ProtocolType.Tcp);
        connetEvent = new AutoResetEvent(false);

        SendAsyncPool = new Stack();

        SocketAsyncEventArgs connectAsync = new SocketAsyncEventArgs();
        connectAsync.UserToken = client;
        connectAsync.RemoteEndPoint = hostEndPoint;
        connectAsync.Completed += new EventHandler(ConnectResult);
        client.ConnectAsync(connectAsync);

        connetEvent.WaitOne(5000); 

        ConnectResultEvent?.Invoke(Connected);

        if (Connected)
        {
            isConnected = true;

            ReceiveAsync = new SocketAsyncEventArgs();
            ReceiveAsync.Completed +=new EventHandler(Completed);
            ReceiveAsync.RemoteEndPoint = hostEndPoint;
            byte[] buffer = new byte[1024];
            ReceiveAsync.SetBuffer(buffer,0,buffer.Length);

            if (!client.ReceiveAsync(ReceiveAsync))
            {
                ProcessReceive(ReceiveAsync);
            }
        }
    }
    private void ConnectResult(object sender, SocketAsyncEventArgs e)
    {
        connetEvent.Set();
    }


    public void Send(byte[] data)
    {
        if (data == null || !Connected ) return;

        SocketAsyncEventArgs async;
        if (SendAsyncPool.Count > 0)
        {
            lock (SendAsyncPool)
            {
                async = SendAsyncPool.Pop();
            }
        }
        else
        {
            if (PoolCapacity >= 5) return;

            async = new SocketAsyncEventArgs();
            async.Completed += new EventHandler(Completed);
            async.RemoteEndPoint = hostEndPoint;

            PoolCapacity++;
        }

        async.SetBuffer(data, 0, data.Length);

        if (!client.SendAsync(async))
        {
            ProcessSend(async);
        }
    }
    private void Completed(object sender, SocketAsyncEventArgs e)
    {
        try
        {
            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Receive:
                    ProcessReceive(e);
                    break;

                case SocketAsyncOperation.Send:
                    ProcessSend(e);
                    break;
                default:
                    break;
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Completed Error:"+ex.Message+","+ex.StackTrace);
        }
      
    }

    private void ProcessSend(SocketAsyncEventArgs e)
    {
        if (e.SocketError == SocketError.Success)
        {
            if (e != null)
            {
                lock (SendAsyncPool)
                {
                    SendAsyncPool.Push(e);
                }
            }
        }
        else
        {
            ProcessError(e);
        }
    }

    private void ProcessReceive(SocketAsyncEventArgs e)
    {
        if (e.SocketError == SocketError.Success && e.BytesTransferred > 0 )
        {
            byte[] data = new byte[e.BytesTransferred];
            Array.Copy(e.Buffer, e.Offset, data, 0, e.BytesTransferred);
            lock (buffer)
            {
                buffer.AddRange(data);
            }

            do
            {
                byte[] lengthBytes = buffer.GetRange(0, 4).ToArray();
                int dataLength = BitConverter.ToInt32(lengthBytes,0);
                if (dataLength <= buffer.Count - 4)
                {
                    byte[] rev = buffer.GetRange(4, dataLength).ToArray();
                    lock (buffer)
                    {
                        buffer.RemoveRange(0, dataLength + 4);
                    }
                    DataReceiveEvent?.Invoke(rev);
                }
                else
                {
                    break;
                }

            } while (buffer.Count >= 4);

            if (!client.ReceiveAsync(e))
                ProcessReceive(e);
        }
        else
        {
            ProcessError(e);
        }
    }
    private void ProcessError(SocketAsyncEventArgs e)
    {
        try
        {
            DisConnectServer();
        }
        catch (Exception ex) 
        {
            Debug.WriteLine("ProcessError:"+ ex.Message+","+ ex.StackTrace);
        }
    }

    bool isConnected;
    public void DisConnectServer()
    {
        if (isConnected)
        {
            isConnected = false;

            client.Dispose();

            connetEvent?.Dispose();

            for (int i = 0; i < SendAsyncPool.Count; i++)
            {
                foreach (var async in SendAsyncPool)
                {
                    async.Completed -= Completed;
                }
            }
            SendAsyncPool.Clear();

            PoolCapacity = 0;

            ReceiveAsync.Completed -= Completed;

            DisconnectEvent?.Invoke();
        }
    }

3.2Hololens:

HoloLens定位

https://blog.csdn.net/ShanGuUncle/article/details/89398095

3.3ARcore:

ARcore定位

https://blog.csdn.net/ShanGuUncle/article/details/89398134

视频教程:

https://edu.csdn.net/course/detail/23985/

 

 

 

你可能感兴趣的:(Hololens开发)