//================================================================================================================================ // // Copyright (c) 2015-2021 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; using UnityEngine; namespace easyar { /// /// which controls in the scene, providing a few extensions in the Unity environment. Use directly when necessary. /// 在场景中控制,在Unity环境下提供功能扩展。如有需要可以直接使用 /// public class ImageTargetController : TargetController { /// /// EasyAR Sense API. Accessible after TargetAvailable event. /// EasyAR Sense API,可以在TargetAvailable event之后访问。 /// public ImageTarget Target { get; private set; } /// /// Target data source. /// Target数据来源。 /// public DataSource SourceType = DataSource.ImageFile; /// /// Image data source for target creation. Valid when == . /// 创建target的图像数据来源。在 == 的时候有效。 /// [HideInInspector, SerializeField] public ImageFileSourceData ImageFileSource = new ImageFileSourceData(); /// /// Target data source for target creation. Valid when == . /// 创建target的target data来源。在 == 的时候有效。 /// [HideInInspector, SerializeField] public TargetDataFileSourceData TargetDataFileSource = new TargetDataFileSourceData(); /// /// Target source when using a target already created. Valid when == . /// 直接使用创建好的target时的target来源。在 == 的时候有效。 /// public ImageTarget TargetSource; #if UNITY_EDITOR /// /// data storage. /// 数据存储。 /// public GizmoStorage GizmoData = new GizmoStorage(); #endif [HideInInspector, SerializeField] private bool trackerHasSet; [HideInInspector, SerializeField] private ImageTrackerFrameFilter tracker; private ImageTrackerFrameFilter loader; private float scale = 0.1f; private float scaleX = 0.1f; private bool preHFlip; /// /// Event when can be used. /// 可以使用的事件。 /// public event Action TargetAvailable; /// /// Target load finish event. The bool value indicates the load success or not. /// Target加载完成的事件。bool值表示加载是否成功。 /// public event Action TargetLoad; /// /// Target unload finish event. The bool value indicates the unload success or not. /// Target卸载完成的事件。bool值表示卸载是否成功。 /// public event Action TargetUnload; /// /// Target data source type. /// Target数据来源类型。 /// public enum DataSource { /// /// Image file (*.jpg, *.png). /// 图像文件(*.jpg, *.png)。 /// ImageFile, /// /// Target data file (*.etd). /// Target data文件(*.etd)。 /// TargetDataFile, /// /// object. /// 对象。 /// Target, } /// /// The which loads the target after . When set to null, the target will be unloaded from tracker previously set. Modify at any time and takes effect immediately. /// 之后加载target的。如果设为null,target将会被从之前设置的tracker中卸载。可随时修改,立即生效。 /// public ImageTrackerFrameFilter Tracker { get { return tracker; } set { tracker = value; UpdateTargetInTracker(); } } /// /// Physical size of in meter. /// 的物理大小,单位为米。 /// public Vector2 Size { get { if (Target == null) { return new Vector2(); } return new Vector2(Target.scale(), Target.scale() / Target.aspectRatio()); } private set { } } /// /// MonoBehaviour Start /// protected override void Start() { base.Start(); if (!EasyARController.Initialized) { return; } switch (SourceType) { case DataSource.ImageFile: LoadImageFile(new ImageFileSourceData() { PathType = ImageFileSource.PathType, Path = ImageFileSource.Path, Name = ImageFileSource.Name, Scale = ImageFileSource.Scale }); break; case DataSource.TargetDataFile: LoadTargetDataFile(new TargetDataFileSourceData() { PathType = TargetDataFileSource.PathType, Path = TargetDataFileSource.Path }); break; case DataSource.Target: LoadTarget(TargetSource); break; default: break; } } /// /// MonoBehaviour Update /// protected virtual void Update() { CheckScale(); } /// /// MonoBehaviour OnDestroy /// protected virtual void OnDestroy() { if (tracker) { tracker = null; UpdateTargetInTracker(); } if (Target != null) { Target.Dispose(); Target = null; } } protected override void OnTracking() { CheckScale(); } private void LoadImageFile(ImageFileSourceData source) { EasyARController.Instance.StartCoroutine(FileUtil.LoadFile(source.Path, source.PathType, (Buffer buffer) => { EasyARController.Instance.StartCoroutine(LoadImageBuffer(buffer.Clone(), source)); })); } private void LoadTargetDataFile(TargetDataFileSourceData source) { EasyARController.Instance.StartCoroutine(FileUtil.LoadFile(source.Path, source.PathType, (Buffer buffer) => { EasyARController.Instance.StartCoroutine(LoadTargetDataBuffer(buffer.Clone())); })); } private void LoadTarget(ImageTarget source) { Target = source; if (Target != null && TargetAvailable != null) { TargetAvailable(); } UpdateScale(); UpdateTargetInTracker(); } private IEnumerator LoadImageBuffer(Buffer buffer, ImageFileSourceData source) { using (buffer) { Optional imageOptional = null; bool taskFinished = false; EasyARController.Instance.Worker.Run(() => { imageOptional = ImageHelper.decode(buffer); taskFinished = true; }); while (!taskFinished) { yield return 0; } if (imageOptional.OnNone) { throw new Exception("invalid buffer"); } using (var image = imageOptional.Value) using (var param = new ImageTargetParameters()) { param.setImage(image); param.setName(source.Name); param.setScale(source.Scale); param.setUid(Guid.NewGuid().ToString()); param.setMeta(string.Empty); var targetOptional = ImageTarget.createFromParameters(param); if (targetOptional.OnSome) { Target = targetOptional.Value; if (Target != null && TargetAvailable != null) { TargetAvailable(); } } else { throw new Exception("invalid parameter"); } } } UpdateTargetInTracker(); } private IEnumerator LoadTargetDataBuffer(Buffer buffer) { using (buffer) { Optional targetOptional = null; bool taskFinished = false; EasyARController.Instance.Worker.Run(() => { targetOptional = ImageTarget.createFromTargetData(buffer); taskFinished = true; }); while (!taskFinished) { yield return 0; } if (targetOptional.OnSome) { Target = targetOptional.Value; if (Target != null && TargetAvailable != null) { TargetAvailable(); } } else { throw new Exception("invalid buffer"); } } UpdateTargetInTracker(); } private void UpdateTargetInTracker() { if (Target == null) { return; } if (loader && loader != tracker) { loader.UnloadImageTarget(this, (target, status) => { if (TargetUnload != null) { TargetUnload(target, status); } if (status) { IsLoaded = false; } }); loader = null; } if (tracker && tracker != loader) { var trackerLoad = tracker; tracker.LoadImageTarget(this, (target, status) => { if (trackerLoad == tracker && !status) { loader = null; } UpdateScale(); if (TargetLoad != null) { TargetLoad(target, status); } IsLoaded = status; }); loader = tracker; } } private void UpdateScale() { if (Target == null) return; scale = Target.scale(); var vec3Unit = Vector3.one; if (HorizontalFlip) { vec3Unit.x = -vec3Unit.x; } transform.localScale = vec3Unit * scale; scaleX = transform.localScale.x; preHFlip = HorizontalFlip; } private void CheckScale() { if (Target == null) return; if (scaleX != transform.localScale.x) { Target.setScale(Math.Abs(transform.localScale.x)); UpdateScale(); } else if (scale != transform.localScale.y) { Target.setScale(Math.Abs(transform.localScale.y)); UpdateScale(); } else if (scale != transform.localScale.z) { Target.setScale(Math.Abs(transform.localScale.z)); UpdateScale(); } else if (scale != Target.scale()) { UpdateScale(); } else if (preHFlip != HorizontalFlip) { UpdateScale(); } } /// /// Image data for target creation. /// 创建target的图像数据。 /// [Serializable] public class ImageFileSourceData { /// /// File path type. /// 文件路径类型。 /// public PathType PathType = PathType.StreamingAssets; /// /// File path. /// 文件路径。 /// public string Path = string.Empty; /// /// Target name. /// Target名字。 /// public string Name = string.Empty; /// /// Target scale in meter. Reference . /// Target图像的缩放比例,单位为米。参考 /// public float Scale = 0.1f; } /// /// Target data for target creation. Target scale and name are defined in the etd file. /// 创建target的target data。Target名字和缩放在etd文件中定义。 /// [Serializable] public class TargetDataFileSourceData { /// /// File path type. /// 文件路径类型。 /// public PathType PathType = PathType.StreamingAssets; /// /// File path. /// 文件路径。 /// public string Path = string.Empty; } #if UNITY_EDITOR /// /// data. Used for gizmo display. /// 数据,用于在编辑器中显示的gizmo。 /// public class GizmoStorage { public string Signature; public Texture2D Texture; public Material Material; public float Scale = 0.1f; public float ScaleX = 0.1f; public bool HorizontalFlip; } #endif } }