//================================================================================================================================ // // Copyright (c) 2015-2019 VisionStar Information Technology (Shanghai) Co., Ltd. All Rights Reserved. // EasyAR is the registered trademark or trademark of VisionStar Information Technology (Shanghai) Co., Ltd in China // and other countries for the augmented reality technology developed by VisionStar Information Technology (Shanghai) Co., Ltd. // //================================================================================================================================ using System; using System.Collections.Generic; using UnityEngine; namespace easyar { /// /// +-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .-- .--+ /// | . /// . +---------------------------------------------------------------+ | /// | | | . /// . | + -> ObjectTracker - - - - + | | /// | v ' ' | . /// . +--> i2FAdapter --> fbFrameFork - - > ImageTracker - - - + ' | | /// | | ' ' | . /// v | v v | | /// FrameSource --> iFrameThrottler --> iFrameFork --> i2OAdapter ------------------------------------> oFrameJoin --> oFrameFork --> oFrameBuffer ~~> o /// ' ^ /// ' ' /// ' ' /// + - - - - - - - - - - - - - - - - - > SurfaceTracker - - - -+ /// ' /// ' /// + - - - - - - - - - - - - - - - - - > CloudRecognizer ~ ~ > o /// [Serializable] public class ARAssembly : IDisposable { public Camera Camera; public Transform CameraRoot; public List RenderCameras = new List(); public FrameSource FrameSource; public List FrameFilters = new List(); protected InputFrameThrottler iFrameThrottler; protected InputFrameFork iFrameFork; protected InputFrameToOutputFrameAdapter i2OAdapter; protected InputFrameToFeedbackFrameAdapter i2FAdapter; protected FeedbackFrameFork fbFrameFork; protected OutputFrameJoin oFrameJoin; protected OutputFrameFork oFrameFork; protected OutputFrameBuffer oFrameBuffer; ~ARAssembly() { DisposeAll(); } public enum AssembleMode { Auto, Manual, } public bool Ready { get; private set; } public bool RequireWorldCenter { get; private set; } public Optional OutputFrame { get { if (!Ready) { return null; } return oFrameBuffer.peek(); } } public virtual void Dispose() { DisposeAll(); GC.SuppressFinalize(this); } public virtual void Assemble(ARSession session) { if (session.AssembleMode == AssembleMode.Auto) { Camera = Camera.main; CameraRoot = Camera.transform; RenderCameras = new List(session.GetComponentsInChildren()); FrameSource = session.GetComponentInChildren(); FrameFilters = new List(session.GetComponentsInChildren()); } foreach (var renderCamera in RenderCameras) { renderCamera.OnAssemble(session); } if (FrameSource) { FrameSource.OnAssemble(session); } foreach (var filter in FrameFilters) { filter.OnAssemble(session); } try { Assemble(); } catch (Exception ex) { Debug.LogError("Fail to Assemble: " + ex.Message); } } public void Break() { Ready = false; } public void Pause() { if (!Ready) { return; } oFrameBuffer.pause(); } public void Resume() { if (!Ready) { return; } oFrameBuffer.resume(); } public void ResetBufferCapacity() { if (FrameSource is CameraSource) { var cameraSource = FrameSource as CameraSource; cameraSource.BufferCapacity = GetBufferRequirement(); } } protected int GetBufferRequirement() { int count = 1; // for OutputFrameBuffer.peek if (FrameSource != null) { count += 1; } if (iFrameThrottler != null) { count += iFrameThrottler.bufferRequirement(); } if (i2FAdapter != null) { count += i2FAdapter.bufferRequirement(); } if (oFrameBuffer != null) { count += oFrameBuffer.bufferRequirement(); } foreach (var filter in FrameFilters) { if (filter != null) { count += filter.BufferRequirement; } } return count; } protected int GetFrameFilterCount() { if (FrameFilters == null) { return 0; } int count = 0; foreach (var filter in FrameFilters) { if (filter is T) { count++; } } return count; } private void Assemble() { // throttler iFrameThrottler = InputFrameThrottler.create(); // fork input iFrameFork = InputFrameFork.create(2 + GetFrameFilterCount()); iFrameThrottler.output().connect(iFrameFork.input()); var iFrameForkIndex = 0; i2OAdapter = InputFrameToOutputFrameAdapter.create(); iFrameFork.output(iFrameForkIndex).connect(i2OAdapter.input()); iFrameForkIndex++; i2FAdapter = InputFrameToFeedbackFrameAdapter.create(); iFrameFork.output(iFrameForkIndex).connect(i2FAdapter.input()); iFrameForkIndex++; foreach (var filter in FrameFilters) { if (filter is FrameFilter.IInputFrameSink) { FrameFilter.IInputFrameSink unit = filter as FrameFilter.IInputFrameSink; var sink = unit.InputFrameSink(); if (sink != null) { iFrameFork.output(iFrameForkIndex).connect(unit.InputFrameSink()); } if (filter is FrameFilter.IInputFrameSinkDelayConnect) { var delayUnit = filter as FrameFilter.IInputFrameSinkDelayConnect; delayUnit.ConnectedTo(iFrameFork.output(iFrameForkIndex), ResetBufferCapacity); } iFrameForkIndex++; } } // feedback fbFrameFork = FeedbackFrameFork.create(GetFrameFilterCount()); i2FAdapter.output().connect(fbFrameFork.input()); var fbFrameForkIndex = 0; foreach (var filter in FrameFilters) { if (filter is FrameFilter.IFeedbackFrameSink) { FrameFilter.IFeedbackFrameSink unit = filter as FrameFilter.IFeedbackFrameSink; fbFrameFork.output(fbFrameForkIndex).connect(unit.FeedbackFrameSink()); fbFrameForkIndex++; } } // join oFrameJoin = OutputFrameJoin.create(1 + GetFrameFilterCount()); var joinIndex = 0; foreach (var filter in FrameFilters) { if (filter is FrameFilter.IOutputFrameSource) { FrameFilter.IOutputFrameSource unit = filter as FrameFilter.IOutputFrameSource; unit.OutputFrameSource().connect(oFrameJoin.input(joinIndex)); joinIndex++; } } i2OAdapter.output().connect(oFrameJoin.input(joinIndex)); // fork output for feedback oFrameFork = OutputFrameFork.create(2); oFrameJoin.output().connect(oFrameFork.input()); oFrameBuffer = OutputFrameBuffer.create(); oFrameFork.output(0).connect(oFrameBuffer.input()); oFrameFork.output(1).connect(i2FAdapter.sideInput()); // signal throttler oFrameBuffer.signalOutput().connect(iFrameThrottler.signalInput()); // connect source if (FrameSource != null) { FrameSource.Connect(iFrameThrottler.input()); } // set BufferCapacity ResetBufferCapacity(); if (FrameSource.HasSpatialInformation) { RequireWorldCenter = true; } foreach (var filter in FrameFilters) { if (filter is SurfaceTrackerFrameFilter) { if (RequireWorldCenter) { throw new InvalidOperationException(typeof(SurfaceTracker) + " + VIOCameraDevice is not supported"); } RequireWorldCenter = true; } } Ready = true; } private void DisposeAll() { if (iFrameThrottler != null) { iFrameThrottler.Dispose(); } if (iFrameFork != null) { iFrameFork.Dispose(); } if (i2OAdapter != null) { i2OAdapter.Dispose(); } if (i2FAdapter != null) { i2FAdapter.Dispose(); } if (fbFrameFork != null) { fbFrameFork.Dispose(); } if (oFrameJoin != null) { oFrameJoin.Dispose(); } if (oFrameFork != null) { oFrameFork.Dispose(); } if (oFrameBuffer != null) { oFrameBuffer.Dispose(); } Ready = false; } } }