Wes xx mediapipe integration
This commit is contained in:
8
Assets/MediaPipeUnity.meta
Normal file
8
Assets/MediaPipeUnity.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2eeb6ad0b5f376a4c89c3d60981e3954
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/MediaPipeUnity/Common.meta
Normal file
8
Assets/MediaPipeUnity/Common.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c7edf4cdcf72d7a4ebb045b80f81aa26
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/MediaPipeUnity/Common/Scripts.meta
Normal file
8
Assets/MediaPipeUnity/Common/Scripts.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d4cf8a63bc91e254baf15f576e0722c3
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
39
Assets/MediaPipeUnity/Common/Scripts/AssetLoader.cs
Normal file
39
Assets/MediaPipeUnity/Common/Scripts/AssetLoader.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public static class AssetLoader
|
||||||
|
{
|
||||||
|
private static ResourceManager _ResourceManager;
|
||||||
|
|
||||||
|
public static void Provide(ResourceManager manager)
|
||||||
|
{
|
||||||
|
_ResourceManager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerator PrepareAssetAsync(string name, string uniqueKey, bool overwrite = false)
|
||||||
|
{
|
||||||
|
if (_ResourceManager == null)
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
Logger.LogWarning("ResourceManager is not provided, so default LocalResourceManager will be used");
|
||||||
|
_ResourceManager = new LocalResourceManager();
|
||||||
|
#else
|
||||||
|
throw new System.InvalidOperationException("ResourceManager is not provided");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return _ResourceManager.PrepareAssetAsync(name, uniqueKey, overwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerator PrepareAssetAsync(string name, bool overwrite = false)
|
||||||
|
{
|
||||||
|
return PrepareAssetAsync(name, name, overwrite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/MediaPipeUnity/Common/Scripts/AssetLoader.cs.meta
Normal file
11
Assets/MediaPipeUnity/Common/Scripts/AssetLoader.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b8bd1b384b7c7414cb732e8fbabf95a8
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
160
Assets/MediaPipeUnity/Common/Scripts/Bootstrap.cs
Normal file
160
Assets/MediaPipeUnity/Common/Scripts/Bootstrap.cs
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using System.IO;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public class Bootstrap : MonoBehaviour
|
||||||
|
{
|
||||||
|
[System.Serializable]
|
||||||
|
public enum AssetLoaderType
|
||||||
|
{
|
||||||
|
StreamingAssets,
|
||||||
|
AssetBundle,
|
||||||
|
Local,
|
||||||
|
}
|
||||||
|
|
||||||
|
private const string _TAG = nameof(Bootstrap);
|
||||||
|
|
||||||
|
[SerializeField] private ImageSourceType _defaultImageSource;
|
||||||
|
[SerializeField] private InferenceMode _preferableInferenceMode;
|
||||||
|
[SerializeField] private AssetLoaderType _assetLoaderType;
|
||||||
|
[SerializeField] private bool _enableGlog = true;
|
||||||
|
|
||||||
|
public InferenceMode inferenceMode { get; private set; }
|
||||||
|
public bool isFinished { get; private set; }
|
||||||
|
private bool _isGlogInitialized;
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
var _ = StartCoroutine(Init());
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator Init()
|
||||||
|
{
|
||||||
|
Logger.SetLogger(new MemoizedLogger(100));
|
||||||
|
Logger.MinLogLevel = Logger.LogLevel.Debug;
|
||||||
|
|
||||||
|
Protobuf.SetLogHandler(Protobuf.DefaultLogHandler);
|
||||||
|
|
||||||
|
Logger.LogInfo(_TAG, "Setting global flags...");
|
||||||
|
GlobalConfigManager.SetFlags();
|
||||||
|
|
||||||
|
if (_enableGlog)
|
||||||
|
{
|
||||||
|
if (Glog.LogDir != null)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(Glog.LogDir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(Glog.LogDir);
|
||||||
|
}
|
||||||
|
Logger.LogVerbose(_TAG, $"Glog will output files under {Glog.LogDir}");
|
||||||
|
}
|
||||||
|
Glog.Initialize("MediaPipeUnityPlugin");
|
||||||
|
_isGlogInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.LogInfo(_TAG, "Initializing AssetLoader...");
|
||||||
|
switch (_assetLoaderType)
|
||||||
|
{
|
||||||
|
case AssetLoaderType.AssetBundle:
|
||||||
|
{
|
||||||
|
AssetLoader.Provide(new AssetBundleResourceManager("mediapipe"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AssetLoaderType.StreamingAssets:
|
||||||
|
{
|
||||||
|
AssetLoader.Provide(new StreamingAssetsResourceManager());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AssetLoaderType.Local:
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
AssetLoader.Provide(new LocalResourceManager());
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
Logger.LogError("LocalResourceManager is only supported on UnityEditor");
|
||||||
|
yield break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
Logger.LogError($"AssetLoaderType is unknown: {_assetLoaderType}");
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DecideInferenceMode();
|
||||||
|
if (inferenceMode == InferenceMode.GPU)
|
||||||
|
{
|
||||||
|
Logger.LogInfo(_TAG, "Initializing GPU resources...");
|
||||||
|
yield return GpuManager.Initialize();
|
||||||
|
|
||||||
|
if (!GpuManager.IsInitialized)
|
||||||
|
{
|
||||||
|
Logger.LogWarning("If your native library is built for CPU, change 'Preferable Inference Mode' to CPU from the Inspector Window for Bootstrap");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.LogInfo(_TAG, "Preparing ImageSource...");
|
||||||
|
ImageSourceProvider.ImageSource = GetImageSource(_defaultImageSource);
|
||||||
|
|
||||||
|
isFinished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageSource GetImageSource(ImageSourceType imageSourceType)
|
||||||
|
{
|
||||||
|
switch (imageSourceType)
|
||||||
|
{
|
||||||
|
case ImageSourceType.WebCamera:
|
||||||
|
{
|
||||||
|
return GetComponent<WebCamSource>();
|
||||||
|
}
|
||||||
|
case ImageSourceType.Image:
|
||||||
|
{
|
||||||
|
return GetComponent<StaticImageSource>();
|
||||||
|
}
|
||||||
|
case ImageSourceType.Video:
|
||||||
|
{
|
||||||
|
return GetComponent<VideoSource>();
|
||||||
|
}
|
||||||
|
case ImageSourceType.Unknown:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new System.ArgumentException($"Unsupported source type: {imageSourceType}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DecideInferenceMode()
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR_OSX || UNITY_EDITOR_WIN
|
||||||
|
if (_preferableInferenceMode == InferenceMode.GPU) {
|
||||||
|
Logger.LogWarning(_TAG, "Current platform does not support GPU inference mode, so falling back to CPU mode");
|
||||||
|
}
|
||||||
|
inferenceMode = InferenceMode.CPU;
|
||||||
|
#else
|
||||||
|
inferenceMode = _preferableInferenceMode;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnApplicationQuit()
|
||||||
|
{
|
||||||
|
GpuManager.Shutdown();
|
||||||
|
|
||||||
|
if (_isGlogInitialized)
|
||||||
|
{
|
||||||
|
Glog.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
Protobuf.ResetLogHandler();
|
||||||
|
Logger.SetLogger(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Assets/MediaPipeUnity/Common/Scripts/Bootstrap.cs.meta
Normal file
15
Assets/MediaPipeUnity/Common/Scripts/Bootstrap.cs.meta
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f4d846393f8d9f20fa64b924b0d95e68
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences:
|
||||||
|
- globalConfigManagerPrefab: {fileID: 4394522812020757894, guid: 488fbb6a3005b66c2b657204bce83fcf,
|
||||||
|
type: 3}
|
||||||
|
- gpuManagerPrefab: {fileID: 7458244645391269047, guid: a84904e562ecaf887b2dba62111bb901,
|
||||||
|
type: 3}
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
140
Assets/MediaPipeUnity/Common/Scripts/GlobalConfigManager.cs
Normal file
140
Assets/MediaPipeUnity/Common/Scripts/GlobalConfigManager.cs
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public static class GlobalConfigManager
|
||||||
|
{
|
||||||
|
private const string _TAG = nameof(GlobalConfigManager);
|
||||||
|
|
||||||
|
private static string CacheDirPath => Path.Combine(Application.persistentDataPath, "Cache");
|
||||||
|
|
||||||
|
private static string ConfigFilePath => Path.Combine(CacheDirPath, "globalConfig.env");
|
||||||
|
|
||||||
|
private const string _GlogLogtostderrKey = "GLOG_logtostderr";
|
||||||
|
private const string _GlogStderrthresholdKey = "GLOG_stderrthreshold";
|
||||||
|
private const string _GlogMinloglevelKey = "GLOG_minloglevel";
|
||||||
|
private const string _GlogVKey = "GLOG_v";
|
||||||
|
private const string _GlogLogDirKey = "GLOG_log_dir";
|
||||||
|
|
||||||
|
public static bool GlogLogtostderr
|
||||||
|
{
|
||||||
|
get => Config[_GlogLogtostderrKey] == "1";
|
||||||
|
set => Config[_GlogLogtostderrKey] = value ? "1" : "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GlogStderrthreshold
|
||||||
|
{
|
||||||
|
get => int.Parse(Config[_GlogStderrthresholdKey]);
|
||||||
|
set => Config[_GlogStderrthresholdKey] = value.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GlogMinloglevel
|
||||||
|
{
|
||||||
|
get => int.Parse(Config[_GlogMinloglevelKey]);
|
||||||
|
set => Config[_GlogMinloglevelKey] = value.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GlogV
|
||||||
|
{
|
||||||
|
get => int.Parse(Config[_GlogVKey]);
|
||||||
|
set => Config[_GlogVKey] = value.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GlogLogDir
|
||||||
|
{
|
||||||
|
get => Config[_GlogLogDirKey];
|
||||||
|
set => Config[_GlogLogDirKey] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, string> _Config;
|
||||||
|
private static Dictionary<string, string> Config
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_Config == null)
|
||||||
|
{
|
||||||
|
_Config = new Dictionary<string, string>() {
|
||||||
|
{ _GlogLogtostderrKey, "1" },
|
||||||
|
{ _GlogStderrthresholdKey, "2" },
|
||||||
|
{ _GlogMinloglevelKey, "0" },
|
||||||
|
{ _GlogLogDirKey, "" },
|
||||||
|
{ _GlogVKey, "0" },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!File.Exists(ConfigFilePath))
|
||||||
|
{
|
||||||
|
Logger.LogDebug(_TAG, $"Global config file does not exist: {ConfigFilePath}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogDebug(_TAG, $"Reading the config file ({ConfigFilePath})...");
|
||||||
|
foreach (var line in File.ReadLines(ConfigFilePath))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pair = ParseLine(line);
|
||||||
|
_Config[pair.Item1] = pair.Item2;
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogWarning($"{e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _Config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Commit()
|
||||||
|
{
|
||||||
|
string[] lines = {
|
||||||
|
$"{_GlogLogtostderrKey}={(GlogLogtostderr ? "1" : "0")}",
|
||||||
|
$"{_GlogStderrthresholdKey}={GlogStderrthreshold}",
|
||||||
|
$"{_GlogMinloglevelKey}={GlogMinloglevel}",
|
||||||
|
$"{_GlogLogDirKey}={GlogLogDir}",
|
||||||
|
$"{_GlogVKey}={GlogV}",
|
||||||
|
};
|
||||||
|
if (!Directory.Exists(CacheDirPath))
|
||||||
|
{
|
||||||
|
var _ = Directory.CreateDirectory(CacheDirPath);
|
||||||
|
}
|
||||||
|
File.WriteAllLines(ConfigFilePath, lines, Encoding.UTF8);
|
||||||
|
Logger.LogInfo(_TAG, "Global config file has been updated");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetFlags()
|
||||||
|
{
|
||||||
|
Glog.Logtostderr = GlogLogtostderr;
|
||||||
|
Glog.Stderrthreshold = GlogStderrthreshold;
|
||||||
|
Glog.Minloglevel = GlogMinloglevel;
|
||||||
|
Glog.V = GlogV;
|
||||||
|
Glog.LogDir = GlogLogDir == "" ? null : Path.Combine(Application.persistentDataPath, GlogLogDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (string, string) ParseLine(string line)
|
||||||
|
{
|
||||||
|
var i = line.IndexOf('=');
|
||||||
|
|
||||||
|
if (i < 0)
|
||||||
|
{
|
||||||
|
throw new System.FormatException("Each line in global config file must include '=', but not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
var key = line.Substring(0, i);
|
||||||
|
var value = line.Substring(i + 1);
|
||||||
|
|
||||||
|
return (key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9b93a8796afa16fd68ef2325d00d4d9a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
311
Assets/MediaPipeUnity/Common/Scripts/GraphRunner.cs
Normal file
311
Assets/MediaPipeUnity/Common/Scripts/GraphRunner.cs
Normal file
@@ -0,0 +1,311 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Rendering;
|
||||||
|
|
||||||
|
using Stopwatch = System.Diagnostics.Stopwatch;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public abstract class GraphRunner : MonoBehaviour
|
||||||
|
{
|
||||||
|
public enum ConfigType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
CPU,
|
||||||
|
GPU,
|
||||||
|
OpenGLES,
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable IDE1006
|
||||||
|
// TODO: make it static
|
||||||
|
protected string TAG => GetType().Name;
|
||||||
|
#pragma warning restore IDE1006
|
||||||
|
|
||||||
|
[SerializeField] private TextAsset _cpuConfig = null;
|
||||||
|
[SerializeField] private TextAsset _gpuConfig = null;
|
||||||
|
[SerializeField] private TextAsset _openGlEsConfig = null;
|
||||||
|
[SerializeField] private long _timeoutMicrosec = 0;
|
||||||
|
|
||||||
|
private static readonly GlobalInstanceTable<int, GraphRunner> _InstanceTable = new GlobalInstanceTable<int, GraphRunner>(5);
|
||||||
|
private static readonly Dictionary<IntPtr, int> _NameTable = new Dictionary<IntPtr, int>();
|
||||||
|
|
||||||
|
protected RunningMode runningMode { get; private set; } = RunningMode.Async;
|
||||||
|
private bool _isRunning = false;
|
||||||
|
|
||||||
|
public InferenceMode inferenceMode => configType == ConfigType.CPU ? InferenceMode.CPU : InferenceMode.GPU;
|
||||||
|
public virtual ConfigType configType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (GpuManager.IsInitialized)
|
||||||
|
{
|
||||||
|
#if UNITY_ANDROID
|
||||||
|
if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3 && _openGlEsConfig != null)
|
||||||
|
{
|
||||||
|
return ConfigType.OpenGLES;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (_gpuConfig != null)
|
||||||
|
{
|
||||||
|
return ConfigType.GPU;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _cpuConfig != null ? ConfigType.CPU : ConfigType.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public TextAsset textConfig
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (configType)
|
||||||
|
{
|
||||||
|
case ConfigType.CPU: return _cpuConfig;
|
||||||
|
case ConfigType.GPU: return _gpuConfig;
|
||||||
|
case ConfigType.OpenGLES: return _openGlEsConfig;
|
||||||
|
case ConfigType.None:
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long timeoutMicrosec
|
||||||
|
{
|
||||||
|
get => _timeoutMicrosec;
|
||||||
|
set => _timeoutMicrosec = (long)Mathf.Max(0, value);
|
||||||
|
}
|
||||||
|
public long timeoutMillisec
|
||||||
|
{
|
||||||
|
get => timeoutMicrosec / 1000;
|
||||||
|
set => timeoutMicrosec = value * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RotationAngle rotation { get; private set; } = 0;
|
||||||
|
|
||||||
|
private Stopwatch _stopwatch;
|
||||||
|
protected CalculatorGraph calculatorGraph { get; private set; }
|
||||||
|
protected Timestamp latestTimestamp;
|
||||||
|
|
||||||
|
protected virtual void Start()
|
||||||
|
{
|
||||||
|
_InstanceTable.Add(GetInstanceID(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnDestroy()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public WaitForResult WaitForInit(RunningMode runningMode)
|
||||||
|
{
|
||||||
|
return new WaitForResult(this, Initialize(runningMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IEnumerator Initialize(RunningMode runningMode)
|
||||||
|
{
|
||||||
|
this.runningMode = runningMode;
|
||||||
|
|
||||||
|
Logger.LogInfo(TAG, $"Config Type = {configType}");
|
||||||
|
Logger.LogInfo(TAG, $"Running Mode = {runningMode}");
|
||||||
|
|
||||||
|
InitializeCalculatorGraph().AssertOk();
|
||||||
|
_stopwatch = new Stopwatch();
|
||||||
|
_stopwatch.Start();
|
||||||
|
|
||||||
|
Logger.LogInfo(TAG, "Loading dependent assets...");
|
||||||
|
var assetRequests = RequestDependentAssets();
|
||||||
|
yield return new WaitWhile(() => assetRequests.Any((request) => request.keepWaiting));
|
||||||
|
|
||||||
|
var errors = assetRequests.Where((request) => request.isError).Select((request) => request.error).ToList();
|
||||||
|
if (errors.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var error in errors)
|
||||||
|
{
|
||||||
|
Logger.LogError(TAG, error);
|
||||||
|
}
|
||||||
|
throw new InternalException("Failed to prepare dependent assets");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void StartRun(ImageSource imageSource);
|
||||||
|
|
||||||
|
protected void StartRun(SidePacket sidePacket)
|
||||||
|
{
|
||||||
|
calculatorGraph.StartRun(sidePacket).AssertOk();
|
||||||
|
_isRunning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Stop()
|
||||||
|
{
|
||||||
|
if (calculatorGraph != null)
|
||||||
|
{
|
||||||
|
if (_isRunning)
|
||||||
|
{
|
||||||
|
using (var status = calculatorGraph.CloseAllPacketSources())
|
||||||
|
{
|
||||||
|
if (!status.Ok())
|
||||||
|
{
|
||||||
|
Logger.LogError(TAG, status.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var status = calculatorGraph.WaitUntilDone())
|
||||||
|
{
|
||||||
|
if (!status.Ok())
|
||||||
|
{
|
||||||
|
Logger.LogError(TAG, status.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isRunning = false;
|
||||||
|
var _ = _NameTable.Remove(calculatorGraph.mpPtr);
|
||||||
|
calculatorGraph.Dispose();
|
||||||
|
calculatorGraph = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_stopwatch != null && _stopwatch.IsRunning)
|
||||||
|
{
|
||||||
|
_stopwatch.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void AddPacketToInputStream<T>(string streamName, Packet<T> packet)
|
||||||
|
{
|
||||||
|
calculatorGraph.AddPacketToInputStream(streamName, packet).AssertOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void AddTextureFrameToInputStream(string streamName, TextureFrame textureFrame)
|
||||||
|
{
|
||||||
|
latestTimestamp = GetCurrentTimestamp();
|
||||||
|
|
||||||
|
if (configType == ConfigType.OpenGLES)
|
||||||
|
{
|
||||||
|
var gpuBuffer = textureFrame.BuildGpuBuffer(GpuManager.GlCalculatorHelper.GetGlContext());
|
||||||
|
AddPacketToInputStream(streamName, new GpuBufferPacket(gpuBuffer, latestTimestamp));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageFrame = textureFrame.BuildImageFrame();
|
||||||
|
textureFrame.Release();
|
||||||
|
|
||||||
|
AddPacketToInputStream(streamName, new ImageFramePacket(imageFrame, latestTimestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool TryGetNext<TPacket, TValue>(OutputStream<TPacket, TValue> stream, out TValue value, bool allowBlock, long currentTimestampMicrosec) where TPacket : Packet<TValue>, new()
|
||||||
|
{
|
||||||
|
var result = stream.TryGetNext(out value, allowBlock);
|
||||||
|
return result || allowBlock || stream.ResetTimestampIfTimedOut(currentTimestampMicrosec, timeoutMicrosec);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long GetCurrentTimestampMicrosec()
|
||||||
|
{
|
||||||
|
return _stopwatch == null || !_stopwatch.IsRunning ? -1 : _stopwatch.ElapsedTicks / (TimeSpan.TicksPerMillisecond / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Timestamp GetCurrentTimestamp()
|
||||||
|
{
|
||||||
|
var microsec = GetCurrentTimestampMicrosec();
|
||||||
|
return microsec < 0 ? Timestamp.Unset() : new Timestamp(microsec);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Status InitializeCalculatorGraph()
|
||||||
|
{
|
||||||
|
calculatorGraph = new CalculatorGraph();
|
||||||
|
_NameTable.Add(calculatorGraph.mpPtr, GetInstanceID());
|
||||||
|
|
||||||
|
// NOTE: There's a simpler way to initialize CalculatorGraph.
|
||||||
|
//
|
||||||
|
// calculatorGraph = new CalculatorGraph(config.text);
|
||||||
|
//
|
||||||
|
// However, if the config format is invalid, this code does not initialize CalculatorGraph and does not throw exceptions either.
|
||||||
|
// The problem is that if you call ObserveStreamOutput in this state, the program will crash.
|
||||||
|
// The following code is not very efficient, but it will return Non-OK status when an invalid configuration is given.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var baseConfig = textConfig == null ? null : CalculatorGraphConfig.Parser.ParseFromTextFormat(textConfig.text);
|
||||||
|
if (baseConfig == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Failed to get the text config. Check if the config is set to GraphRunner");
|
||||||
|
}
|
||||||
|
var status = ConfigureCalculatorGraph(baseConfig);
|
||||||
|
return !status.Ok() || inferenceMode == InferenceMode.CPU ? status : calculatorGraph.SetGpuResources(GpuManager.GpuResources);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return Status.FailedPrecondition(e.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configure and initialize the <see cref="CalculatorGraph" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is the main process in <see cref="InitializeCalculatorGraph" />.<br />
|
||||||
|
/// At least, <c>calculatorGraph.Initialize</c> must be called here.
|
||||||
|
/// In addition to that, <see cref="OutputStream" /> instances should be initialized.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="config">
|
||||||
|
/// A <see cref="CalculatorGraphConfig" /> instance corresponding to <see cref="textConfig" />.<br />
|
||||||
|
/// It can be dynamically modified here.
|
||||||
|
/// </param>
|
||||||
|
protected virtual Status ConfigureCalculatorGraph(CalculatorGraphConfig config)
|
||||||
|
{
|
||||||
|
return calculatorGraph.Initialize(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SetImageTransformationOptions(SidePacket sidePacket, ImageSource imageSource, bool expectedToBeMirrored = false)
|
||||||
|
{
|
||||||
|
// NOTE: The origin is left-bottom corner in Unity, and right-top corner in MediaPipe.
|
||||||
|
rotation = imageSource.rotation.Reverse();
|
||||||
|
var inputRotation = rotation;
|
||||||
|
var isInverted = CoordinateSystem.ImageCoordinate.IsInverted(rotation);
|
||||||
|
var shouldBeMirrored = imageSource.isHorizontallyFlipped ^ expectedToBeMirrored;
|
||||||
|
var inputHorizontallyFlipped = isInverted ^ shouldBeMirrored;
|
||||||
|
var inputVerticallyFlipped = !isInverted;
|
||||||
|
|
||||||
|
if ((inputHorizontallyFlipped && inputVerticallyFlipped) || rotation == RotationAngle.Rotation180)
|
||||||
|
{
|
||||||
|
inputRotation = inputRotation.Add(RotationAngle.Rotation180);
|
||||||
|
inputHorizontallyFlipped = !inputHorizontallyFlipped;
|
||||||
|
inputVerticallyFlipped = !inputVerticallyFlipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.LogDebug($"input_rotation = {inputRotation}, input_horizontally_flipped = {inputHorizontallyFlipped}, input_vertically_flipped = {inputVerticallyFlipped}");
|
||||||
|
|
||||||
|
sidePacket.Emplace("input_rotation", new IntPacket((int)inputRotation));
|
||||||
|
sidePacket.Emplace("input_horizontally_flipped", new BoolPacket(inputHorizontallyFlipped));
|
||||||
|
sidePacket.Emplace("input_vertically_flipped", new BoolPacket(inputVerticallyFlipped));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WaitForResult WaitForAsset(string assetName, string uniqueKey, long timeoutMillisec, bool overwrite = false)
|
||||||
|
{
|
||||||
|
return new WaitForResult(this, AssetLoader.PrepareAssetAsync(assetName, uniqueKey, overwrite), timeoutMillisec);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WaitForResult WaitForAsset(string assetName, long timeoutMillisec, bool overwrite = false)
|
||||||
|
{
|
||||||
|
return WaitForAsset(assetName, assetName, timeoutMillisec, overwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WaitForResult WaitForAsset(string assetName, string uniqueKey, bool overwrite = false)
|
||||||
|
{
|
||||||
|
return new WaitForResult(this, AssetLoader.PrepareAssetAsync(assetName, uniqueKey, overwrite));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WaitForResult WaitForAsset(string assetName, bool overwrite = false)
|
||||||
|
{
|
||||||
|
return WaitForAsset(assetName, assetName, overwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract IList<WaitForResult> RequestDependentAssets();
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/MediaPipeUnity/Common/Scripts/GraphRunner.cs.meta
Normal file
11
Assets/MediaPipeUnity/Common/Scripts/GraphRunner.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 00f8c92dc785a7523b94c869aaead45f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/MediaPipeUnity/Common/Scripts/ImageSource.meta
Normal file
8
Assets/MediaPipeUnity/Common/Scripts/ImageSource.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ab516f3bbf28a23489219f7a966fa0cc
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
159
Assets/MediaPipeUnity/Common/Scripts/ImageSource/ImageSource.cs
Normal file
159
Assets/MediaPipeUnity/Common/Scripts/ImageSource/ImageSource.cs
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Experimental.Rendering;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public abstract class ImageSource : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public struct ResolutionStruct
|
||||||
|
{
|
||||||
|
public int width;
|
||||||
|
public int height;
|
||||||
|
public double frameRate;
|
||||||
|
|
||||||
|
public ResolutionStruct(int width, int height, double frameRate)
|
||||||
|
{
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.frameRate = frameRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResolutionStruct(Resolution resolution)
|
||||||
|
{
|
||||||
|
width = resolution.width;
|
||||||
|
height = resolution.height;
|
||||||
|
frameRate = resolution.refreshRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resolution ToResolution()
|
||||||
|
{
|
||||||
|
return new Resolution() { width = width, height = height, refreshRate = (int)frameRate };
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var aspectRatio = $"{width}x{height}";
|
||||||
|
var frameRateStr = frameRate.ToString("#.##");
|
||||||
|
return frameRate > 0 ? $"{aspectRatio} ({frameRateStr}Hz)" : aspectRatio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResolutionStruct resolution { get; protected set; }
|
||||||
|
|
||||||
|
/// <remarks>
|
||||||
|
/// To call this method, the image source must be prepared.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>
|
||||||
|
/// <see cref="TextureFormat" /> that is compatible with the current texture.
|
||||||
|
/// </returns>
|
||||||
|
public TextureFormat textureFormat => isPrepared ? TextureFormatFor(GetCurrentTexture()) : throw new InvalidOperationException("ImageSource is not prepared");
|
||||||
|
public virtual int textureWidth => resolution.width;
|
||||||
|
public virtual int textureHeight => resolution.height;
|
||||||
|
/// <remarks>
|
||||||
|
/// If <see cref="type" /> does not support frame rate, it returns zero.
|
||||||
|
/// </remarks>
|
||||||
|
public virtual double frameRate => resolution.frameRate;
|
||||||
|
public float focalLengthPx { get; } = 2.0f; // TODO: calculate at runtime
|
||||||
|
public virtual bool isHorizontallyFlipped { get; set; } = false;
|
||||||
|
public virtual bool isVerticallyFlipped { get; } = false;
|
||||||
|
public virtual bool isFrontFacing { get; } = false;
|
||||||
|
public virtual RotationAngle rotation { get; } = RotationAngle.Rotation0;
|
||||||
|
|
||||||
|
public abstract string sourceName { get; }
|
||||||
|
public abstract string[] sourceCandidateNames { get; }
|
||||||
|
public abstract ResolutionStruct[] availableResolutions { get; }
|
||||||
|
|
||||||
|
/// <remarks>
|
||||||
|
/// Once <see cref="Play" /> finishes successfully, it will become true.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>
|
||||||
|
/// Returns if the image source is prepared.
|
||||||
|
/// </returns>
|
||||||
|
public abstract bool isPrepared { get; }
|
||||||
|
|
||||||
|
public abstract bool isPlaying { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Choose the source from <see cref="sourceCandidateNames" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// You need to call <see cref="Play" /> for the change to take effect.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="sourceId">The index of <see cref="sourceCandidateNames" /></param>
|
||||||
|
public abstract void SelectSource(int sourceId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Choose the resolution from <see cref="availableResolutions" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// You need to call <see cref="Play" /> for the change to take effect.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="resolutionId">The index of <see cref="availableResolutions" /></param>
|
||||||
|
public void SelectResolution(int resolutionId)
|
||||||
|
{
|
||||||
|
var resolutions = availableResolutions;
|
||||||
|
|
||||||
|
if (resolutionId < 0 || resolutionId >= resolutions.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Invalid resolution ID: {resolutionId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
resolution = resolutions[resolutionId];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prepare image source.
|
||||||
|
/// If <see cref="isPlaying" /> is true, it will reset the image source.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// When it finishes successfully, <see cref="isPrepared" /> will return true.
|
||||||
|
/// </remarks>
|
||||||
|
/// <exception cref="InvalidOperation" />
|
||||||
|
public abstract IEnumerator Play();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resume image source.
|
||||||
|
/// If <see cref="isPlaying" /> is true, it will do nothing.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="InvalidOperation">
|
||||||
|
/// The image source has not been played.
|
||||||
|
/// </exception>
|
||||||
|
public abstract IEnumerator Resume();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pause image source.
|
||||||
|
/// If <see cref="isPlaying" /> is false, it will do nothing.
|
||||||
|
/// </summary>
|
||||||
|
public abstract void Pause();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stop image source.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// When it finishes successfully, <see cref="isPrepared" /> will return false.
|
||||||
|
/// </remarks>
|
||||||
|
public abstract void Stop();
|
||||||
|
|
||||||
|
/// <remarks>
|
||||||
|
/// To call this method, the image source must be prepared.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>
|
||||||
|
/// <see cref="Texture" /> that contains the current image.
|
||||||
|
/// </returns>
|
||||||
|
public abstract Texture GetCurrentTexture();
|
||||||
|
|
||||||
|
protected static TextureFormat TextureFormatFor(Texture texture)
|
||||||
|
{
|
||||||
|
return GraphicsFormatUtility.GetTextureFormat(texture.graphicsFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 78116299de071af7094419302302ec05
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
public enum ImageSourceType
|
||||||
|
{
|
||||||
|
WebCamera = 0,
|
||||||
|
Image = 1,
|
||||||
|
Video = 2,
|
||||||
|
Unknown = 3,
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2e20c591a3836aae1abc65429b7adde1
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public class StaticImageSource : ImageSource
|
||||||
|
{
|
||||||
|
[SerializeField] private Texture[] _availableSources;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private ResolutionStruct[] _defaultAvailableResolutions = new ResolutionStruct[] {
|
||||||
|
new ResolutionStruct(512, 512, 0),
|
||||||
|
new ResolutionStruct(640, 480, 0),
|
||||||
|
new ResolutionStruct(1280, 720, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
private Texture2D _outputTexture;
|
||||||
|
private Texture _image;
|
||||||
|
private Texture image
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_image == null && _availableSources != null && _availableSources.Length > 0)
|
||||||
|
{
|
||||||
|
image = _availableSources[0];
|
||||||
|
}
|
||||||
|
return _image;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_image = value;
|
||||||
|
resolution = GetDefaultResolution();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double frameRate => 0;
|
||||||
|
|
||||||
|
public override string sourceName => image != null ? image.name : null;
|
||||||
|
|
||||||
|
public override string[] sourceCandidateNames => _availableSources?.Select(source => source.name).ToArray();
|
||||||
|
|
||||||
|
public override ResolutionStruct[] availableResolutions => _defaultAvailableResolutions;
|
||||||
|
|
||||||
|
public override bool isPrepared => _outputTexture != null;
|
||||||
|
|
||||||
|
private bool _isPlaying = false;
|
||||||
|
public override bool isPlaying => _isPlaying;
|
||||||
|
|
||||||
|
public override void SelectSource(int sourceId)
|
||||||
|
{
|
||||||
|
if (sourceId < 0 || sourceId >= _availableSources.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Invalid source ID: {sourceId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
image = _availableSources[sourceId];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerator Play()
|
||||||
|
{
|
||||||
|
if (image == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Image is not selected");
|
||||||
|
}
|
||||||
|
if (isPlaying)
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeOutputTexture(image);
|
||||||
|
_isPlaying = true;
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerator Resume()
|
||||||
|
{
|
||||||
|
if (!isPrepared)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Image is not prepared");
|
||||||
|
}
|
||||||
|
_isPlaying = true;
|
||||||
|
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Pause()
|
||||||
|
{
|
||||||
|
_isPlaying = false;
|
||||||
|
}
|
||||||
|
public override void Stop()
|
||||||
|
{
|
||||||
|
_isPlaying = false;
|
||||||
|
_outputTexture = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Texture GetCurrentTexture()
|
||||||
|
{
|
||||||
|
return _outputTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResolutionStruct GetDefaultResolution()
|
||||||
|
{
|
||||||
|
var resolutions = availableResolutions;
|
||||||
|
|
||||||
|
return (resolutions == null || resolutions.Length == 0) ? new ResolutionStruct() : resolutions[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeOutputTexture(Texture src)
|
||||||
|
{
|
||||||
|
_outputTexture = new Texture2D(textureWidth, textureHeight, TextureFormat.RGBA32, false);
|
||||||
|
|
||||||
|
Texture resizedTexture = new Texture2D(textureWidth, textureHeight, TextureFormat.RGBA32, false);
|
||||||
|
// TODO: assert ConvertTexture finishes successfully
|
||||||
|
var _ = Graphics.ConvertTexture(src, resizedTexture);
|
||||||
|
|
||||||
|
var currentRenderTexture = RenderTexture.active;
|
||||||
|
var tmpRenderTexture = new RenderTexture(resizedTexture.width, resizedTexture.height, 32);
|
||||||
|
Graphics.Blit(resizedTexture, tmpRenderTexture);
|
||||||
|
RenderTexture.active = tmpRenderTexture;
|
||||||
|
|
||||||
|
var rect = new UnityEngine.Rect(0, 0, _outputTexture.width, _outputTexture.height);
|
||||||
|
_outputTexture.ReadPixels(rect, 0, 0);
|
||||||
|
_outputTexture.Apply();
|
||||||
|
|
||||||
|
RenderTexture.active = currentRenderTexture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bd7955705ab46c72b9124bb116a2dca9
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
378
Assets/MediaPipeUnity/Common/Scripts/ImageSource/TextureFrame.cs
Normal file
378
Assets/MediaPipeUnity/Common/Scripts/ImageSource/TextureFrame.cs
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Unity.Collections;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using UnityEngine.Experimental.Rendering;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
#pragma warning disable IDE0065
|
||||||
|
using Color = UnityEngine.Color;
|
||||||
|
#pragma warning restore IDE0065
|
||||||
|
|
||||||
|
public class TextureFrame
|
||||||
|
{
|
||||||
|
public class ReleaseEvent : UnityEvent<TextureFrame> { }
|
||||||
|
|
||||||
|
private const string _TAG = nameof(TextureFrame);
|
||||||
|
|
||||||
|
private static readonly GlobalInstanceTable<Guid, TextureFrame> _InstanceTable = new GlobalInstanceTable<Guid, TextureFrame>(100);
|
||||||
|
/// <summary>
|
||||||
|
/// A dictionary to look up which native texture belongs to which <see cref="TextureFrame" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Not all the <see cref="TextureFrame" /> instances are registered.
|
||||||
|
/// Texture names are queried only when necessary, and the corresponding data will be saved then.
|
||||||
|
/// </remarks>
|
||||||
|
private static readonly Dictionary<uint, Guid> _NameTable = new Dictionary<uint, Guid>();
|
||||||
|
|
||||||
|
private readonly Texture2D _texture;
|
||||||
|
private IntPtr _nativeTexturePtr = IntPtr.Zero;
|
||||||
|
private GlSyncPoint _glSyncToken;
|
||||||
|
|
||||||
|
// Buffers that will be used to copy texture data on CPU.
|
||||||
|
// They won't be initialized until it's necessary.
|
||||||
|
private Texture2D _textureBuffer;
|
||||||
|
|
||||||
|
private Color32[] _pixelsBuffer; // for WebCamTexture
|
||||||
|
private Color32[] pixelsBuffer
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_pixelsBuffer == null)
|
||||||
|
{
|
||||||
|
_pixelsBuffer = new Color32[width * height];
|
||||||
|
}
|
||||||
|
return _pixelsBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Guid _instanceId;
|
||||||
|
// NOTE: width and height can be accessed from a thread other than Main Thread.
|
||||||
|
public readonly int width;
|
||||||
|
public readonly int height;
|
||||||
|
public readonly TextureFormat format;
|
||||||
|
|
||||||
|
private ImageFormat.Types.Format _format = ImageFormat.Types.Format.Unknown;
|
||||||
|
public ImageFormat.Types.Format imageFormat
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_format == ImageFormat.Types.Format.Unknown)
|
||||||
|
{
|
||||||
|
_format = format.ToImageFormat();
|
||||||
|
}
|
||||||
|
return _format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool isReadable => _texture.isReadable;
|
||||||
|
|
||||||
|
// TODO: determine at runtime
|
||||||
|
public GpuBufferFormat gpuBufferformat => GpuBufferFormat.kBGRA32;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The event that will be invoked when the TextureFrame is released.
|
||||||
|
/// </summary>
|
||||||
|
#pragma warning disable IDE1006 // UnityEvent is PascalCase
|
||||||
|
public readonly ReleaseEvent OnRelease;
|
||||||
|
#pragma warning restore IDE1006
|
||||||
|
|
||||||
|
private TextureFrame(Texture2D texture)
|
||||||
|
{
|
||||||
|
_texture = texture;
|
||||||
|
width = texture.width;
|
||||||
|
height = texture.height;
|
||||||
|
format = texture.format;
|
||||||
|
OnRelease = new ReleaseEvent();
|
||||||
|
_instanceId = Guid.NewGuid();
|
||||||
|
_InstanceTable.Add(_instanceId, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureFrame(int width, int height, TextureFormat format) : this(new Texture2D(width, height, format, false)) { }
|
||||||
|
public TextureFrame(int width, int height) : this(width, height, TextureFormat.RGBA32) { }
|
||||||
|
|
||||||
|
public void CopyTexture(Texture dst)
|
||||||
|
{
|
||||||
|
Graphics.CopyTexture(_texture, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTextureFrom(Texture src)
|
||||||
|
{
|
||||||
|
Graphics.CopyTexture(src, _texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ConvertTexture(Texture dst)
|
||||||
|
{
|
||||||
|
return Graphics.ConvertTexture(_texture, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ConvertTextureFrom(Texture src)
|
||||||
|
{
|
||||||
|
return Graphics.ConvertTexture(src, _texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copy texture data from <paramref name="src" />.
|
||||||
|
/// If <paramref name="src" /> format is different from <see cref="format" />, it converts the format.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// After calling it, pixel data won't be read from CPU safely.
|
||||||
|
/// </remarks>
|
||||||
|
public bool ReadTextureFromOnGPU(Texture src)
|
||||||
|
{
|
||||||
|
if (GetTextureFormat(src) != format)
|
||||||
|
{
|
||||||
|
return Graphics.ConvertTexture(src, _texture);
|
||||||
|
}
|
||||||
|
Graphics.CopyTexture(src, _texture);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copy texture data from <paramref name="src" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This operation is slow.
|
||||||
|
/// If CPU won't access the pixel data, use <see cref="ReadTextureFromOnGPU" /> instead.
|
||||||
|
/// </remarks>
|
||||||
|
public void ReadTextureFromOnCPU(Texture src)
|
||||||
|
{
|
||||||
|
var textureBuffer = LoadToTextureBuffer(src);
|
||||||
|
SetPixels32(textureBuffer.GetPixels32());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copy texture data from <paramref name="src" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// In most cases, it should be better to use <paramref name="src" /> directly.
|
||||||
|
/// </remarks>
|
||||||
|
public void ReadTextureFromOnCPU(Texture2D src)
|
||||||
|
{
|
||||||
|
SetPixels32(src.GetPixels32());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copy texture data from <paramref name="src" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="src">
|
||||||
|
/// The texture from which the pixels are read.
|
||||||
|
/// Its width and height must match that of the TextureFrame.
|
||||||
|
/// </param>
|
||||||
|
/// <remarks>
|
||||||
|
/// This operation is slow.
|
||||||
|
/// If CPU won't access the pixel data, use <see cref="ReadTextureFromOnGPU" /> instead.
|
||||||
|
/// </remarks>
|
||||||
|
public void ReadTextureFromOnCPU(WebCamTexture src)
|
||||||
|
{
|
||||||
|
SetPixels32(src.GetPixels32(pixelsBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color GetPixel(int x, int y)
|
||||||
|
{
|
||||||
|
return _texture.GetPixel(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color32[] GetPixels32()
|
||||||
|
{
|
||||||
|
return _texture.GetPixels32();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPixels32(Color32[] pixels)
|
||||||
|
{
|
||||||
|
_texture.SetPixels32(pixels);
|
||||||
|
_texture.Apply();
|
||||||
|
|
||||||
|
if (!RevokeNativeTexturePtr())
|
||||||
|
{
|
||||||
|
// If this line was executed, there must be a bug.
|
||||||
|
Logger.LogError("Failed to revoke the native texture.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NativeArray<T> GetRawTextureData<T>() where T : struct
|
||||||
|
{
|
||||||
|
return _texture.GetRawTextureData<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <returns>The texture's native pointer</returns>
|
||||||
|
public IntPtr GetNativeTexturePtr()
|
||||||
|
{
|
||||||
|
if (_nativeTexturePtr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
_nativeTexturePtr = _texture.GetNativeTexturePtr();
|
||||||
|
var name = (uint)_nativeTexturePtr;
|
||||||
|
|
||||||
|
lock (((ICollection)_NameTable).SyncRoot)
|
||||||
|
{
|
||||||
|
if (!AcquireName(name, _instanceId))
|
||||||
|
{
|
||||||
|
throw new InvalidProgramException($"Another instance (id={_instanceId}) is using the specified name ({name}) now");
|
||||||
|
}
|
||||||
|
_NameTable.Add(name, _instanceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _nativeTexturePtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetTextureName()
|
||||||
|
{
|
||||||
|
return (uint)GetNativeTexturePtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid GetInstanceID()
|
||||||
|
{
|
||||||
|
return _instanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageFrame BuildImageFrame()
|
||||||
|
{
|
||||||
|
return new ImageFrame(imageFormat, width, height, 4 * width, GetRawTextureData<byte>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public GpuBuffer BuildGpuBuffer(GlContext glContext)
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR_LINUX || UNITY_STANDALONE_LINUX || UNITY_ANDROID
|
||||||
|
var glTextureBuffer = new GlTextureBuffer(GetTextureName(), width, height, gpuBufferformat, OnReleaseTextureFrame, glContext);
|
||||||
|
return new GpuBuffer(glTextureBuffer);
|
||||||
|
#else
|
||||||
|
throw new NotSupportedException("This method is only supported on Linux or Android");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAllReleaseListeners()
|
||||||
|
{
|
||||||
|
OnRelease.RemoveAllListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: stop invoking OnRelease when it's already released
|
||||||
|
public void Release(GlSyncPoint token = null)
|
||||||
|
{
|
||||||
|
if (_glSyncToken != null)
|
||||||
|
{
|
||||||
|
_glSyncToken.Dispose();
|
||||||
|
}
|
||||||
|
_glSyncToken = token;
|
||||||
|
OnRelease.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Waits until the GPU has executed all commands up to the sync point.
|
||||||
|
/// This blocks the CPU, and ensures the commands are complete from the point of view of all threads and contexts.
|
||||||
|
/// </summary>
|
||||||
|
public void WaitUntilReleased()
|
||||||
|
{
|
||||||
|
if (_glSyncToken == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_glSyncToken.Wait();
|
||||||
|
_glSyncToken.Dispose();
|
||||||
|
_glSyncToken = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[AOT.MonoPInvokeCallback(typeof(GlTextureBuffer.DeletionCallback))]
|
||||||
|
public static void OnReleaseTextureFrame(uint textureName, IntPtr syncTokenPtr)
|
||||||
|
{
|
||||||
|
var isIdFound = _NameTable.TryGetValue(textureName, out var _instanceId);
|
||||||
|
|
||||||
|
if (!isIdFound)
|
||||||
|
{
|
||||||
|
Logger.LogError(_TAG, $"nameof (name={textureName}) is released, but the owner TextureFrame is not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var isTextureFrameFound = _InstanceTable.TryGetValue(_instanceId, out var textureFrame);
|
||||||
|
|
||||||
|
if (!isTextureFrameFound)
|
||||||
|
{
|
||||||
|
Logger.LogWarning(_TAG, $"nameof owner TextureFrame of the released texture (name={textureName}) is already garbage collected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _glSyncToken = syncTokenPtr == IntPtr.Zero ? null : new GlSyncPoint(syncTokenPtr);
|
||||||
|
textureFrame.Release(_glSyncToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove <paramref name="name" /> from <see cref="_NameTable" /> if it's stale.
|
||||||
|
/// If <paramref name="name" /> does not exist in <see cref="_NameTable" />, do nothing.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If the instance whose id is <paramref name="ownerId" /> owns <paramref name="name" /> now, it still removes <paramref name="name" />.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>Return if name is available</returns>
|
||||||
|
private static bool AcquireName(uint name, Guid ownerId)
|
||||||
|
{
|
||||||
|
if (_NameTable.TryGetValue(name, out var id))
|
||||||
|
{
|
||||||
|
if (ownerId != id && _InstanceTable.TryGetValue(id, out var _))
|
||||||
|
{
|
||||||
|
// if instance is found, the instance is using the name.
|
||||||
|
Logger.LogVerbose($"{id} is using {name} now");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var _ = _NameTable.Remove(name);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextureFormat GetTextureFormat(Texture texture)
|
||||||
|
{
|
||||||
|
return GraphicsFormatUtility.GetTextureFormat(texture.graphicsFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove the texture name from <see cref="_NameTable" /> and empty <see cref="_nativeTexturePtr" />.
|
||||||
|
/// This method needs to be called when an operation is performed that may change the internal texture.
|
||||||
|
/// </summary>
|
||||||
|
private bool RevokeNativeTexturePtr()
|
||||||
|
{
|
||||||
|
if (_nativeTexturePtr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentName = GetTextureName();
|
||||||
|
if (!_NameTable.Remove(currentName))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_nativeTexturePtr = IntPtr.Zero;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Texture2D LoadToTextureBuffer(Texture texture)
|
||||||
|
{
|
||||||
|
var textureFormat = GetTextureFormat(texture);
|
||||||
|
|
||||||
|
if (_textureBuffer == null || _textureBuffer.format != textureFormat)
|
||||||
|
{
|
||||||
|
_textureBuffer = new Texture2D(width, height, textureFormat, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmpRenderTexture = RenderTexture.GetTemporary(texture.width, texture.height, 32);
|
||||||
|
var currentRenderTexture = RenderTexture.active;
|
||||||
|
RenderTexture.active = tmpRenderTexture;
|
||||||
|
|
||||||
|
Graphics.Blit(texture, tmpRenderTexture);
|
||||||
|
|
||||||
|
var rect = new UnityEngine.Rect(0, 0, Mathf.Min(tmpRenderTexture.width, _textureBuffer.width), Mathf.Min(tmpRenderTexture.height, _textureBuffer.height));
|
||||||
|
_textureBuffer.ReadPixels(rect, 0, 0);
|
||||||
|
_textureBuffer.Apply();
|
||||||
|
RenderTexture.active = currentRenderTexture;
|
||||||
|
RenderTexture.ReleaseTemporary(tmpRenderTexture);
|
||||||
|
|
||||||
|
return _textureBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fa7e0da68d497cd578438e238b6a6e7c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public class TextureFramePool : MonoBehaviour
|
||||||
|
{
|
||||||
|
private const string _TAG = nameof(TextureFramePool);
|
||||||
|
|
||||||
|
[SerializeField] private int _poolSize = 10;
|
||||||
|
|
||||||
|
private readonly object _formatLock = new object();
|
||||||
|
private int _textureWidth = 0;
|
||||||
|
private int _textureHeight = 0;
|
||||||
|
private TextureFormat _format = TextureFormat.RGBA32;
|
||||||
|
|
||||||
|
private Queue<TextureFrame> _availableTextureFrames;
|
||||||
|
/// <remarks>
|
||||||
|
/// key: TextureFrame's instance ID
|
||||||
|
/// </remarks>
|
||||||
|
private Dictionary<Guid, TextureFrame> _textureFramesInUse;
|
||||||
|
|
||||||
|
/// <returns>
|
||||||
|
/// The total number of texture frames in the pool.
|
||||||
|
/// </returns>
|
||||||
|
public int frameCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var availableTextureFramesCount = _availableTextureFrames == null ? 0 : _availableTextureFrames.Count;
|
||||||
|
var textureFramesInUseCount = _textureFramesInUse == null ? 0 : _textureFramesInUse.Count;
|
||||||
|
|
||||||
|
return availableTextureFramesCount + textureFramesInUseCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
_availableTextureFrames = new Queue<TextureFrame>(_poolSize);
|
||||||
|
_textureFramesInUse = new Dictionary<Guid, TextureFrame>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
lock (((ICollection)_availableTextureFrames).SyncRoot)
|
||||||
|
{
|
||||||
|
_availableTextureFrames.Clear();
|
||||||
|
_availableTextureFrames = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (((ICollection)_textureFramesInUse).SyncRoot)
|
||||||
|
{
|
||||||
|
foreach (var textureFrame in _textureFramesInUse.Values)
|
||||||
|
{
|
||||||
|
textureFrame.OnRelease.RemoveListener(OnTextureFrameRelease);
|
||||||
|
}
|
||||||
|
_textureFramesInUse.Clear();
|
||||||
|
_textureFramesInUse = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResizeTexture(int textureWidth, int textureHeight, TextureFormat format)
|
||||||
|
{
|
||||||
|
lock (_formatLock)
|
||||||
|
{
|
||||||
|
_textureWidth = textureWidth;
|
||||||
|
_textureHeight = textureHeight;
|
||||||
|
_format = format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResizeTexture(int textureWidth, int textureHeight)
|
||||||
|
{
|
||||||
|
ResizeTexture(textureWidth, textureHeight, _format);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetTextureFrame(out TextureFrame outFrame)
|
||||||
|
{
|
||||||
|
TextureFrame nextFrame = null;
|
||||||
|
|
||||||
|
lock (((ICollection)_availableTextureFrames).SyncRoot)
|
||||||
|
{
|
||||||
|
if (_poolSize <= frameCount)
|
||||||
|
{
|
||||||
|
while (_availableTextureFrames.Count > 0)
|
||||||
|
{
|
||||||
|
var textureFrame = _availableTextureFrames.Dequeue();
|
||||||
|
|
||||||
|
if (!IsStale(textureFrame))
|
||||||
|
{
|
||||||
|
nextFrame = textureFrame;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nextFrame = CreateNewTextureFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextFrame == null)
|
||||||
|
{
|
||||||
|
outFrame = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (((ICollection)_textureFramesInUse).SyncRoot)
|
||||||
|
{
|
||||||
|
_textureFramesInUse.Add(nextFrame.GetInstanceID(), nextFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
nextFrame.WaitUntilReleased();
|
||||||
|
outFrame = nextFrame;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTextureFrameRelease(TextureFrame textureFrame)
|
||||||
|
{
|
||||||
|
lock (((ICollection)_textureFramesInUse).SyncRoot)
|
||||||
|
{
|
||||||
|
if (!_textureFramesInUse.Remove(textureFrame.GetInstanceID()))
|
||||||
|
{
|
||||||
|
// won't be run
|
||||||
|
Logger.LogWarning(_TAG, "The released texture does not belong to the pool");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frameCount > _poolSize || IsStale(textureFrame))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_availableTextureFrames.Enqueue(textureFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsStale(TextureFrame textureFrame)
|
||||||
|
{
|
||||||
|
lock (_formatLock)
|
||||||
|
{
|
||||||
|
return textureFrame.width != _textureWidth || textureFrame.height != _textureHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextureFrame CreateNewTextureFrame()
|
||||||
|
{
|
||||||
|
var textureFrame = new TextureFrame(_textureWidth, _textureHeight, _format);
|
||||||
|
textureFrame.OnRelease.AddListener(OnTextureFrameRelease);
|
||||||
|
|
||||||
|
return textureFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d5da564da19cb6b7d8e4f97f269edc5d
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
116
Assets/MediaPipeUnity/Common/Scripts/ImageSource/VideoSource.cs
Normal file
116
Assets/MediaPipeUnity/Common/Scripts/ImageSource/VideoSource.cs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Video;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public class VideoSource : ImageSource
|
||||||
|
{
|
||||||
|
[SerializeField] private VideoClip[] _availableSources;
|
||||||
|
|
||||||
|
private VideoClip _video;
|
||||||
|
private VideoClip video
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_video == null && _availableSources != null && _availableSources.Length > 0)
|
||||||
|
{
|
||||||
|
video = _availableSources[0];
|
||||||
|
}
|
||||||
|
return _video;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_video = value;
|
||||||
|
resolution = new ResolutionStruct((int)_video.width, (int)_video.height, _video.frameRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private VideoPlayer _videoPlayer;
|
||||||
|
|
||||||
|
public override string sourceName => video != null ? video.name : null;
|
||||||
|
|
||||||
|
public override string[] sourceCandidateNames => _availableSources?.Select(source => source.name).ToArray();
|
||||||
|
|
||||||
|
public override ResolutionStruct[] availableResolutions => video == null ? null : new ResolutionStruct[] { new ResolutionStruct((int)video.width, (int)video.height, video.frameRate) };
|
||||||
|
|
||||||
|
public override bool isPlaying => _videoPlayer != null && _videoPlayer.isPlaying;
|
||||||
|
public override bool isPrepared => _videoPlayer != null && _videoPlayer.isPrepared;
|
||||||
|
|
||||||
|
public override void SelectSource(int sourceId)
|
||||||
|
{
|
||||||
|
if (sourceId < 0 || sourceId >= _availableSources.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Invalid source ID: {sourceId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
video = _availableSources[sourceId];
|
||||||
|
if (_videoPlayer != null)
|
||||||
|
{
|
||||||
|
_videoPlayer.clip = video;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerator Play()
|
||||||
|
{
|
||||||
|
if (video == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Video is not selected");
|
||||||
|
}
|
||||||
|
_videoPlayer = gameObject.AddComponent<VideoPlayer>();
|
||||||
|
_videoPlayer.renderMode = VideoRenderMode.APIOnly;
|
||||||
|
_videoPlayer.isLooping = true;
|
||||||
|
_videoPlayer.clip = video;
|
||||||
|
_videoPlayer.Prepare();
|
||||||
|
|
||||||
|
yield return new WaitUntil(() => _videoPlayer.isPrepared);
|
||||||
|
_videoPlayer.Play();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerator Resume()
|
||||||
|
{
|
||||||
|
if (!isPrepared)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("VideoPlayer is not prepared");
|
||||||
|
}
|
||||||
|
if (!isPlaying)
|
||||||
|
{
|
||||||
|
_videoPlayer.Play();
|
||||||
|
}
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Pause()
|
||||||
|
{
|
||||||
|
if (!isPlaying)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_videoPlayer.Pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Stop()
|
||||||
|
{
|
||||||
|
if (_videoPlayer == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_videoPlayer.Stop();
|
||||||
|
Destroy(gameObject.GetComponent<VideoPlayer>());
|
||||||
|
_videoPlayer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Texture GetCurrentTexture()
|
||||||
|
{
|
||||||
|
return _videoPlayer != null ? _videoPlayer.texture : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 04085488e5fac35599866a2a6fceeda3
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
299
Assets/MediaPipeUnity/Common/Scripts/ImageSource/WebCamSource.cs
Normal file
299
Assets/MediaPipeUnity/Common/Scripts/ImageSource/WebCamSource.cs
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
#if UNITY_ANDROID
|
||||||
|
using UnityEngine.Android;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public class WebCamSource : ImageSource
|
||||||
|
{
|
||||||
|
[Tooltip("For the default resolution, the one whose width is closest to this value will be chosen")]
|
||||||
|
[SerializeField] private int _preferableDefaultWidth = 1280;
|
||||||
|
|
||||||
|
private const string _TAG = nameof(WebCamSource);
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private ResolutionStruct[] _defaultAvailableResolutions = new ResolutionStruct[] {
|
||||||
|
new ResolutionStruct(176, 144, 30),
|
||||||
|
new ResolutionStruct(320, 240, 30),
|
||||||
|
new ResolutionStruct(424, 240, 30),
|
||||||
|
new ResolutionStruct(640, 360, 30),
|
||||||
|
new ResolutionStruct(640, 480, 30),
|
||||||
|
new ResolutionStruct(848, 480, 30),
|
||||||
|
new ResolutionStruct(960, 540, 30),
|
||||||
|
new ResolutionStruct(1280, 720, 30),
|
||||||
|
new ResolutionStruct(1600, 896, 30),
|
||||||
|
new ResolutionStruct(1920, 1080, 30),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly object _PermissionLock = new object();
|
||||||
|
private static bool _IsPermitted = false;
|
||||||
|
|
||||||
|
private WebCamTexture _webCamTexture;
|
||||||
|
private WebCamTexture webCamTexture
|
||||||
|
{
|
||||||
|
get => _webCamTexture;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_webCamTexture != null)
|
||||||
|
{
|
||||||
|
_webCamTexture.Stop();
|
||||||
|
}
|
||||||
|
_webCamTexture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int textureWidth => !isPrepared ? 0 : webCamTexture.width;
|
||||||
|
public override int textureHeight => !isPrepared ? 0 : webCamTexture.height;
|
||||||
|
|
||||||
|
public override bool isVerticallyFlipped => isPrepared && webCamTexture.videoVerticallyMirrored;
|
||||||
|
public override bool isFrontFacing => isPrepared && (webCamDevice is WebCamDevice valueOfWebCamDevice) && valueOfWebCamDevice.isFrontFacing;
|
||||||
|
public override RotationAngle rotation => !isPrepared ? RotationAngle.Rotation0 : (RotationAngle)webCamTexture.videoRotationAngle;
|
||||||
|
|
||||||
|
private WebCamDevice? _webCamDevice;
|
||||||
|
private WebCamDevice? webCamDevice
|
||||||
|
{
|
||||||
|
get => _webCamDevice;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_webCamDevice is WebCamDevice valueOfWebCamDevice)
|
||||||
|
{
|
||||||
|
if (value is WebCamDevice valueOfValue && valueOfValue.name == valueOfWebCamDevice.name)
|
||||||
|
{
|
||||||
|
// not changed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value == null)
|
||||||
|
{
|
||||||
|
// not changed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_webCamDevice = value;
|
||||||
|
resolution = GetDefaultResolution();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override string sourceName => (webCamDevice is WebCamDevice valueOfWebCamDevice) ? valueOfWebCamDevice.name : null;
|
||||||
|
|
||||||
|
private WebCamDevice[] _availableSources;
|
||||||
|
private WebCamDevice[] availableSources
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_availableSources == null)
|
||||||
|
{
|
||||||
|
_availableSources = WebCamTexture.devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _availableSources;
|
||||||
|
}
|
||||||
|
set => _availableSources = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string[] sourceCandidateNames => availableSources?.Select(device => device.name).ToArray();
|
||||||
|
|
||||||
|
#pragma warning disable IDE0025
|
||||||
|
public override ResolutionStruct[] availableResolutions
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR
|
||||||
|
if (webCamDevice is WebCamDevice valueOfWebCamDevice) {
|
||||||
|
return valueOfWebCamDevice.availableResolutions.Select(resolution => new ResolutionStruct(resolution)).ToArray();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return webCamDevice == null ? null : _defaultAvailableResolutions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma warning restore IDE0025
|
||||||
|
|
||||||
|
public override bool isPrepared => webCamTexture != null;
|
||||||
|
public override bool isPlaying => webCamTexture != null && webCamTexture.isPlaying;
|
||||||
|
private bool _isInitialized;
|
||||||
|
|
||||||
|
private IEnumerator Start()
|
||||||
|
{
|
||||||
|
yield return GetPermission();
|
||||||
|
|
||||||
|
if (!_IsPermitted)
|
||||||
|
{
|
||||||
|
_isInitialized = true;
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
availableSources = WebCamTexture.devices;
|
||||||
|
|
||||||
|
if (availableSources != null && availableSources.Length > 0)
|
||||||
|
{
|
||||||
|
webCamDevice = availableSources[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
_isInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator GetPermission()
|
||||||
|
{
|
||||||
|
lock (_PermissionLock)
|
||||||
|
{
|
||||||
|
if (_IsPermitted)
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_ANDROID
|
||||||
|
if (!Permission.HasUserAuthorizedPermission(Permission.Camera))
|
||||||
|
{
|
||||||
|
Permission.RequestUserPermission(Permission.Camera);
|
||||||
|
yield return new WaitForSeconds(0.1f);
|
||||||
|
}
|
||||||
|
#elif UNITY_IOS
|
||||||
|
if (!Application.HasUserAuthorization(UserAuthorization.WebCam)) {
|
||||||
|
yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if UNITY_ANDROID
|
||||||
|
if (!Permission.HasUserAuthorizedPermission(Permission.Camera))
|
||||||
|
{
|
||||||
|
Logger.LogWarning(_TAG, "Not permitted to use Camera");
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
#elif UNITY_IOS
|
||||||
|
if (!Application.HasUserAuthorization(UserAuthorization.WebCam)) {
|
||||||
|
Logger.LogWarning(_TAG, "Not permitted to use WebCam");
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
_IsPermitted = true;
|
||||||
|
|
||||||
|
yield return new WaitForEndOfFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SelectSource(int sourceId)
|
||||||
|
{
|
||||||
|
if (sourceId < 0 || sourceId >= availableSources.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Invalid source ID: {sourceId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
webCamDevice = availableSources[sourceId];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerator Play()
|
||||||
|
{
|
||||||
|
yield return new WaitUntil(() => _isInitialized);
|
||||||
|
if (!_IsPermitted)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Not permitted to access cameras");
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeWebCamTexture();
|
||||||
|
webCamTexture.Play();
|
||||||
|
yield return WaitForWebCamTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerator Resume()
|
||||||
|
{
|
||||||
|
if (!isPrepared)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("WebCamTexture is not prepared yet");
|
||||||
|
}
|
||||||
|
if (!webCamTexture.isPlaying)
|
||||||
|
{
|
||||||
|
webCamTexture.Play();
|
||||||
|
}
|
||||||
|
yield return WaitForWebCamTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Pause()
|
||||||
|
{
|
||||||
|
if (isPlaying)
|
||||||
|
{
|
||||||
|
webCamTexture.Pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Stop()
|
||||||
|
{
|
||||||
|
if (webCamTexture != null)
|
||||||
|
{
|
||||||
|
webCamTexture.Stop();
|
||||||
|
}
|
||||||
|
webCamTexture = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Texture GetCurrentTexture()
|
||||||
|
{
|
||||||
|
return webCamTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResolutionStruct GetDefaultResolution()
|
||||||
|
{
|
||||||
|
var resolutions = availableResolutions;
|
||||||
|
return resolutions == null || resolutions.Length == 0 ? new ResolutionStruct() : resolutions.OrderBy(resolution => resolution, new ResolutionStructComparer(_preferableDefaultWidth)).First();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeWebCamTexture()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
if (webCamDevice is WebCamDevice valueOfWebCamDevice)
|
||||||
|
{
|
||||||
|
webCamTexture = new WebCamTexture(valueOfWebCamDevice.name, resolution.width, resolution.height, (int)resolution.frameRate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new InvalidOperationException("Cannot initialize WebCamTexture because WebCamDevice is not selected");
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator WaitForWebCamTexture()
|
||||||
|
{
|
||||||
|
const int timeoutFrame = 2000;
|
||||||
|
var count = 0;
|
||||||
|
Logger.LogVerbose("Waiting for WebCamTexture to start");
|
||||||
|
yield return new WaitUntil(() => count++ > timeoutFrame || webCamTexture.width > 16);
|
||||||
|
|
||||||
|
if (webCamTexture.width <= 16)
|
||||||
|
{
|
||||||
|
throw new TimeoutException("Failed to start WebCam");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ResolutionStructComparer : IComparer<ResolutionStruct>
|
||||||
|
{
|
||||||
|
private readonly int _preferableDefaultWidth;
|
||||||
|
|
||||||
|
public ResolutionStructComparer(int preferableDefaultWidth)
|
||||||
|
{
|
||||||
|
_preferableDefaultWidth = preferableDefaultWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Compare(ResolutionStruct a, ResolutionStruct b)
|
||||||
|
{
|
||||||
|
var aDiff = Mathf.Abs(a.width - _preferableDefaultWidth);
|
||||||
|
var bDiff = Mathf.Abs(b.width - _preferableDefaultWidth);
|
||||||
|
if (aDiff != bDiff)
|
||||||
|
{
|
||||||
|
return aDiff - bDiff;
|
||||||
|
}
|
||||||
|
if (a.height != b.height)
|
||||||
|
{
|
||||||
|
// prefer smaller height
|
||||||
|
return a.height - b.height;
|
||||||
|
}
|
||||||
|
// prefer smaller frame rate
|
||||||
|
return (int)(a.frameRate - b.frameRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 498146e99d4934673bd948c8be11227e
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
45
Assets/MediaPipeUnity/Common/Scripts/ImageSourceProvider.cs
Normal file
45
Assets/MediaPipeUnity/Common/Scripts/ImageSourceProvider.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public static class ImageSourceProvider
|
||||||
|
{
|
||||||
|
private static ImageSource _ImageSource;
|
||||||
|
public static ImageSource ImageSource
|
||||||
|
{
|
||||||
|
get => _ImageSource;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != null && !value.enabled)
|
||||||
|
{
|
||||||
|
value.enabled = true;
|
||||||
|
}
|
||||||
|
_ImageSource = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ImageSourceType CurrentSourceType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_ImageSource is WebCamSource)
|
||||||
|
{
|
||||||
|
return ImageSourceType.WebCamera;
|
||||||
|
}
|
||||||
|
if (_ImageSource is StaticImageSource)
|
||||||
|
{
|
||||||
|
return ImageSourceType.Image;
|
||||||
|
}
|
||||||
|
if (_ImageSource is VideoSource)
|
||||||
|
{
|
||||||
|
return ImageSourceType.Video;
|
||||||
|
}
|
||||||
|
return ImageSourceType.Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 703949cb153f043aca7381a8f9b21a86
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
131
Assets/MediaPipeUnity/Common/Scripts/ImageSourceSolution.cs
Normal file
131
Assets/MediaPipeUnity/Common/Scripts/ImageSourceSolution.cs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public abstract class ImageSourceSolution<T> : Solution where T : GraphRunner
|
||||||
|
{
|
||||||
|
[SerializeField] protected Screen screen;
|
||||||
|
[SerializeField] protected T graphRunner;
|
||||||
|
[SerializeField] protected TextureFramePool textureFramePool;
|
||||||
|
|
||||||
|
private Coroutine _coroutine;
|
||||||
|
|
||||||
|
public RunningMode runningMode;
|
||||||
|
|
||||||
|
public long timeoutMillisec
|
||||||
|
{
|
||||||
|
get => graphRunner.timeoutMillisec;
|
||||||
|
set => graphRunner.timeoutMillisec = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Play()
|
||||||
|
{
|
||||||
|
if (_coroutine != null)
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
base.Play();
|
||||||
|
_coroutine = StartCoroutine(Run());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Pause()
|
||||||
|
{
|
||||||
|
base.Pause();
|
||||||
|
ImageSourceProvider.ImageSource.Pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Resume()
|
||||||
|
{
|
||||||
|
base.Resume();
|
||||||
|
var _ = StartCoroutine(ImageSourceProvider.ImageSource.Resume());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Stop()
|
||||||
|
{
|
||||||
|
base.Stop();
|
||||||
|
StopCoroutine(_coroutine);
|
||||||
|
ImageSourceProvider.ImageSource.Stop();
|
||||||
|
graphRunner.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator Run()
|
||||||
|
{
|
||||||
|
var graphInitRequest = graphRunner.WaitForInit(runningMode);
|
||||||
|
var imageSource = ImageSourceProvider.ImageSource;
|
||||||
|
|
||||||
|
yield return imageSource.Play();
|
||||||
|
|
||||||
|
if (!imageSource.isPrepared)
|
||||||
|
{
|
||||||
|
Logger.LogError(TAG, "Failed to start ImageSource, exiting...");
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use RGBA32 as the input format.
|
||||||
|
// TODO: When using GpuBuffer, MediaPipe assumes that the input format is BGRA, so the following code must be fixed.
|
||||||
|
textureFramePool.ResizeTexture(imageSource.textureWidth, imageSource.textureHeight, TextureFormat.RGBA32);
|
||||||
|
SetupScreen(imageSource);
|
||||||
|
|
||||||
|
yield return graphInitRequest;
|
||||||
|
if (graphInitRequest.isError)
|
||||||
|
{
|
||||||
|
Logger.LogError(TAG, graphInitRequest.error);
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnStartRun();
|
||||||
|
graphRunner.StartRun(imageSource);
|
||||||
|
|
||||||
|
var waitWhilePausing = new WaitWhile(() => isPaused);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (isPaused)
|
||||||
|
{
|
||||||
|
yield return waitWhilePausing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!textureFramePool.TryGetTextureFrame(out var textureFrame))
|
||||||
|
{
|
||||||
|
yield return new WaitForEndOfFrame();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy current image to TextureFrame
|
||||||
|
ReadFromImageSource(imageSource, textureFrame);
|
||||||
|
AddTextureFrameToInputStream(textureFrame);
|
||||||
|
yield return new WaitForEndOfFrame();
|
||||||
|
|
||||||
|
if (runningMode.IsSynchronous())
|
||||||
|
{
|
||||||
|
RenderCurrentFrame(textureFrame);
|
||||||
|
yield return WaitForNextValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void SetupScreen(ImageSource imageSource)
|
||||||
|
{
|
||||||
|
// NOTE: The screen will be resized later, keeping the aspect ratio.
|
||||||
|
screen.Initialize(imageSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void RenderCurrentFrame(TextureFrame textureFrame)
|
||||||
|
{
|
||||||
|
screen.ReadSync(textureFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void OnStartRun();
|
||||||
|
|
||||||
|
protected abstract void AddTextureFrameToInputStream(TextureFrame textureFrame);
|
||||||
|
|
||||||
|
protected abstract IEnumerator WaitForNextValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a7573abd3c3f9972e964d5c526c34e0a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
15
Assets/MediaPipeUnity/Common/Scripts/InferenceMode.cs
Normal file
15
Assets/MediaPipeUnity/Common/Scripts/InferenceMode.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
[System.Serializable]
|
||||||
|
public enum InferenceMode
|
||||||
|
{
|
||||||
|
GPU,
|
||||||
|
CPU,
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/MediaPipeUnity/Common/Scripts/InferenceMode.cs.meta
Normal file
11
Assets/MediaPipeUnity/Common/Scripts/InferenceMode.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d95cf1e3a8fe6741295a3b42972dec58
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
264
Assets/MediaPipeUnity/Common/Scripts/MemoizedLogger.cs
Normal file
264
Assets/MediaPipeUnity/Common/Scripts/MemoizedLogger.cs
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
using LogLevel = Mediapipe.Unity.Logger.LogLevel;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public class MemoizedLogger : IExtendedLogger
|
||||||
|
{
|
||||||
|
public readonly struct LogStruct
|
||||||
|
{
|
||||||
|
public readonly LogLevel logLevel;
|
||||||
|
public readonly string tag;
|
||||||
|
public readonly object message;
|
||||||
|
public readonly DateTime utcTime;
|
||||||
|
|
||||||
|
public LogStruct(LogLevel logLevel, string tag, object message)
|
||||||
|
{
|
||||||
|
this.logLevel = logLevel;
|
||||||
|
this.tag = tag;
|
||||||
|
this.message = message;
|
||||||
|
utcTime = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogStruct(LogType logType, string tag, object message) : this(GetLogLevelFromLogType(logType), tag, message) { }
|
||||||
|
|
||||||
|
private static LogLevel GetLogLevelFromLogType(LogType logType)
|
||||||
|
{
|
||||||
|
switch (logType)
|
||||||
|
{
|
||||||
|
case LogType.Error:
|
||||||
|
case LogType.Exception:
|
||||||
|
{
|
||||||
|
return LogLevel.Error;
|
||||||
|
}
|
||||||
|
case LogType.Warning:
|
||||||
|
{
|
||||||
|
return LogLevel.Warn;
|
||||||
|
}
|
||||||
|
case LogType.Assert:
|
||||||
|
case LogType.Log:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return LogLevel.Info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemoizedLogger(int historySize = 0)
|
||||||
|
{
|
||||||
|
this.historySize = historySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _historySize;
|
||||||
|
public int historySize
|
||||||
|
{
|
||||||
|
get => _historySize;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_historySize = value;
|
||||||
|
|
||||||
|
while (_historySize < histories.Count)
|
||||||
|
{
|
||||||
|
var _ = histories.Dequeue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Queue<LogStruct> _histories;
|
||||||
|
public Queue<LogStruct> histories
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_histories == null)
|
||||||
|
{
|
||||||
|
_histories = new Queue<LogStruct>(_historySize);
|
||||||
|
}
|
||||||
|
return _histories;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void LogOutputEventHandler(LogStruct logStruct);
|
||||||
|
public event LogOutputEventHandler OnLogOutput;
|
||||||
|
|
||||||
|
private readonly ILogger _logger = Debug.unityLogger;
|
||||||
|
|
||||||
|
public LogType filterLogType
|
||||||
|
{
|
||||||
|
get => _logger.filterLogType;
|
||||||
|
set => _logger.filterLogType = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool logEnabled
|
||||||
|
{
|
||||||
|
get => _logger.logEnabled;
|
||||||
|
set => _logger.logEnabled = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ILogHandler logHandler
|
||||||
|
{
|
||||||
|
get => _logger.logHandler;
|
||||||
|
set => _logger.logHandler = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsLogTypeAllowed(LogType logType)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(object message)
|
||||||
|
{
|
||||||
|
_logger.Log(message);
|
||||||
|
RecordInfoLog(null, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(string tag, object message)
|
||||||
|
{
|
||||||
|
_logger.Log(tag, message);
|
||||||
|
RecordInfoLog(tag, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(string tag, object message, UnityEngine.Object context)
|
||||||
|
{
|
||||||
|
_logger.Log(tag, message, context);
|
||||||
|
RecordInfoLog(tag, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(LogType logType, object message)
|
||||||
|
{
|
||||||
|
_logger.Log(logType, message);
|
||||||
|
RecordLog(logType, null, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(LogType logType, object message, UnityEngine.Object context)
|
||||||
|
{
|
||||||
|
_logger.Log(logType, message, context);
|
||||||
|
RecordLog(logType, null, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(LogType logType, string tag, object message)
|
||||||
|
{
|
||||||
|
_logger.Log(logType, tag, message);
|
||||||
|
RecordLog(logType, tag, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(LogType logType, string tag, object message, UnityEngine.Object context)
|
||||||
|
{
|
||||||
|
_logger.Log(logType, tag, message, context);
|
||||||
|
RecordLog(logType, tag, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(LogLevel logLevel, string tag, object message, UnityEngine.Object context)
|
||||||
|
{
|
||||||
|
_logger.Log(logLevel.GetLogType(), tag, message, context);
|
||||||
|
RecordLog(new LogStruct(logLevel, tag, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(LogLevel logLevel, string tag, object message)
|
||||||
|
{
|
||||||
|
_logger.Log(logLevel.GetLogType(), tag, message);
|
||||||
|
RecordLog(new LogStruct(logLevel, tag, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(LogLevel logLevel, object message, UnityEngine.Object context)
|
||||||
|
{
|
||||||
|
_logger.Log(logLevel.GetLogType(), message, context);
|
||||||
|
RecordLog(new LogStruct(logLevel, null, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(LogLevel logLevel, object message)
|
||||||
|
{
|
||||||
|
_logger.Log(logLevel.GetLogType(), message);
|
||||||
|
RecordLog(new LogStruct(logLevel, null, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogWarning(string tag, object message)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(tag, message);
|
||||||
|
RecordWarnLog(tag, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogWarning(string tag, object message, UnityEngine.Object context)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(tag, message, context);
|
||||||
|
RecordWarnLog(tag, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogError(string tag, object message)
|
||||||
|
{
|
||||||
|
_logger.LogError(tag, message);
|
||||||
|
RecordErrorLog(tag, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogError(string tag, object message, UnityEngine.Object context)
|
||||||
|
{
|
||||||
|
_logger.LogError(tag, message, context);
|
||||||
|
RecordErrorLog(tag, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogFormat(LogType logType, string format, params object[] args)
|
||||||
|
{
|
||||||
|
_logger.LogFormat(logType, format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogFormat(LogType logType, UnityEngine.Object context, string format, params object[] args)
|
||||||
|
{
|
||||||
|
_logger.LogFormat(logType, context, format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogException(Exception exception)
|
||||||
|
{
|
||||||
|
_logger.LogException(exception);
|
||||||
|
RecordErrorLog(null, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogException(Exception exception, UnityEngine.Object context)
|
||||||
|
{
|
||||||
|
_logger.LogException(exception, context);
|
||||||
|
RecordErrorLog(null, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RecordLog(LogStruct log)
|
||||||
|
{
|
||||||
|
lock (((ICollection)histories).SyncRoot)
|
||||||
|
{
|
||||||
|
while (histories.Count > 0 && _historySize <= histories.Count)
|
||||||
|
{
|
||||||
|
var _ = histories.Dequeue();
|
||||||
|
}
|
||||||
|
histories.Enqueue(log);
|
||||||
|
OnLogOutput?.Invoke(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RecordLog(LogType logType, string tag, object message)
|
||||||
|
{
|
||||||
|
RecordLog(new LogStruct(logType, tag, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RecordInfoLog(string tag, object message)
|
||||||
|
{
|
||||||
|
RecordLog(new LogStruct(LogLevel.Info, tag, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RecordWarnLog(string tag, object message)
|
||||||
|
{
|
||||||
|
RecordLog(new LogStruct(LogLevel.Warn, tag, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RecordErrorLog(string tag, object message)
|
||||||
|
{
|
||||||
|
RecordLog(new LogStruct(LogLevel.Error, tag, message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/MediaPipeUnity/Common/Scripts/MemoizedLogger.cs.meta
Normal file
11
Assets/MediaPipeUnity/Common/Scripts/MemoizedLogger.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 00164446b902a4f99ae323de716782fe
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
24
Assets/MediaPipeUnity/Common/Scripts/RunningMode.cs
Normal file
24
Assets/MediaPipeUnity/Common/Scripts/RunningMode.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
[System.Serializable]
|
||||||
|
public enum RunningMode
|
||||||
|
{
|
||||||
|
Async,
|
||||||
|
NonBlockingSync,
|
||||||
|
Sync,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RunningModeExtension
|
||||||
|
{
|
||||||
|
public static bool IsSynchronous(this RunningMode runningMode)
|
||||||
|
{
|
||||||
|
return runningMode == RunningMode.Sync || runningMode == RunningMode.NonBlockingSync;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/MediaPipeUnity/Common/Scripts/RunningMode.cs.meta
Normal file
11
Assets/MediaPipeUnity/Common/Scripts/RunningMode.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e82590f067b6f1b96ac9dadddcd9ab26
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
98
Assets/MediaPipeUnity/Common/Scripts/Screen.cs
Normal file
98
Assets/MediaPipeUnity/Common/Scripts/Screen.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public class Screen : MonoBehaviour
|
||||||
|
{
|
||||||
|
[SerializeField] private RawImage _screen;
|
||||||
|
|
||||||
|
private ImageSource _imageSource;
|
||||||
|
|
||||||
|
public Texture texture
|
||||||
|
{
|
||||||
|
private get => _screen.texture;
|
||||||
|
set => _screen.texture = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnityEngine.Rect uvRect
|
||||||
|
{
|
||||||
|
set => _screen.uvRect = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize(ImageSource imageSource)
|
||||||
|
{
|
||||||
|
_imageSource = imageSource;
|
||||||
|
|
||||||
|
Resize(_imageSource.textureWidth, _imageSource.textureHeight);
|
||||||
|
Rotate(_imageSource.rotation.Reverse());
|
||||||
|
ResetUvRect(RunningMode.Async);
|
||||||
|
texture = imageSource.GetCurrentTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resize(int width, int height)
|
||||||
|
{
|
||||||
|
_screen.rectTransform.sizeDelta = new Vector2(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Rotate(RotationAngle rotationAngle)
|
||||||
|
{
|
||||||
|
_screen.rectTransform.localEulerAngles = rotationAngle.GetEulerAngles();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReadSync(TextureFrame textureFrame)
|
||||||
|
{
|
||||||
|
if (!(texture is Texture2D))
|
||||||
|
{
|
||||||
|
texture = new Texture2D(_imageSource.textureWidth, _imageSource.textureHeight, TextureFormat.RGBA32, false);
|
||||||
|
ResetUvRect(RunningMode.Sync);
|
||||||
|
}
|
||||||
|
textureFrame.CopyTexture(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetUvRect(RunningMode runningMode)
|
||||||
|
{
|
||||||
|
var rect = new UnityEngine.Rect(0, 0, 1, 1);
|
||||||
|
|
||||||
|
if (_imageSource.isVerticallyFlipped && runningMode == RunningMode.Async)
|
||||||
|
{
|
||||||
|
// In Async mode, we don't need to flip the screen vertically since the image will be copied on CPU.
|
||||||
|
rect = FlipVertically(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_imageSource.isFrontFacing)
|
||||||
|
{
|
||||||
|
// Flip the image (not the screen) horizontally.
|
||||||
|
// It should be taken into account that the image will be rotated later.
|
||||||
|
var rotation = _imageSource.rotation;
|
||||||
|
|
||||||
|
if (rotation == RotationAngle.Rotation0 || rotation == RotationAngle.Rotation180)
|
||||||
|
{
|
||||||
|
rect = FlipHorizontally(rect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rect = FlipVertically(rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uvRect = rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UnityEngine.Rect FlipHorizontally(UnityEngine.Rect rect)
|
||||||
|
{
|
||||||
|
return new UnityEngine.Rect(1 - rect.x, rect.y, -rect.width, rect.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UnityEngine.Rect FlipVertically(UnityEngine.Rect rect)
|
||||||
|
{
|
||||||
|
return new UnityEngine.Rect(rect.x, 1 - rect.y, rect.width, -rect.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/MediaPipeUnity/Common/Scripts/Screen.cs.meta
Normal file
11
Assets/MediaPipeUnity/Common/Scripts/Screen.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 827c4431af677e057aa6f14170d0785c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
117
Assets/MediaPipeUnity/Common/Scripts/Solution.cs
Normal file
117
Assets/MediaPipeUnity/Common/Scripts/Solution.cs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public abstract class Solution : MonoBehaviour
|
||||||
|
{
|
||||||
|
#pragma warning disable IDE1006
|
||||||
|
// TODO: make it static
|
||||||
|
protected virtual string TAG => GetType().Name;
|
||||||
|
#pragma warning restore IDE1006
|
||||||
|
|
||||||
|
public Bootstrap bootstrap;
|
||||||
|
protected bool isPaused;
|
||||||
|
|
||||||
|
protected virtual IEnumerator Start()
|
||||||
|
{
|
||||||
|
bootstrap = FindBootstrap();
|
||||||
|
yield return new WaitUntil(() => bootstrap.isFinished);
|
||||||
|
|
||||||
|
Play();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start the main program from the beginning.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Play()
|
||||||
|
{
|
||||||
|
isPaused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pause the main program.
|
||||||
|
/// <summary>
|
||||||
|
public virtual void Pause()
|
||||||
|
{
|
||||||
|
isPaused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resume the main program.
|
||||||
|
/// If the main program has not begun, it'll do nothing.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Resume()
|
||||||
|
{
|
||||||
|
isPaused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stops the main program.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Stop()
|
||||||
|
{
|
||||||
|
isPaused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void SetupAnnotationController<T>(AnnotationController<T> annotationController, ImageSource imageSource, bool expectedToBeMirrored = false) where T : HierarchicalAnnotation
|
||||||
|
{
|
||||||
|
annotationController.isMirrored = expectedToBeMirrored ^ imageSource.isHorizontallyFlipped ^ imageSource.isFrontFacing;
|
||||||
|
annotationController.rotationAngle = imageSource.rotation.Reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void ReadFromImageSource(ImageSource imageSource, TextureFrame textureFrame)
|
||||||
|
{
|
||||||
|
var sourceTexture = imageSource.GetCurrentTexture();
|
||||||
|
|
||||||
|
// For some reason, when the image is coiped on GPU, latency tends to be high.
|
||||||
|
// So even when OpenGL ES is available, use CPU to copy images.
|
||||||
|
var textureType = sourceTexture.GetType();
|
||||||
|
|
||||||
|
if (textureType == typeof(WebCamTexture))
|
||||||
|
{
|
||||||
|
textureFrame.ReadTextureFromOnCPU((WebCamTexture)sourceTexture);
|
||||||
|
}
|
||||||
|
else if (textureType == typeof(Texture2D))
|
||||||
|
{
|
||||||
|
textureFrame.ReadTextureFromOnCPU((Texture2D)sourceTexture);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
textureFrame.ReadTextureFromOnCPU(sourceTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Bootstrap FindBootstrap()
|
||||||
|
{
|
||||||
|
var bootstrapObj = GameObject.Find("Bootstrap");
|
||||||
|
|
||||||
|
if (bootstrapObj != null)
|
||||||
|
{
|
||||||
|
return bootstrapObj.GetComponent<Bootstrap>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.LogWarning(TAG, "Global Bootstrap instance is not found (maybe running a sample scene directly), "
|
||||||
|
+ "so activating a fallback Bootstrap instance attached to each Solution object");
|
||||||
|
|
||||||
|
var bootstrap = GetComponent<Bootstrap>();
|
||||||
|
bootstrap.enabled = true;
|
||||||
|
|
||||||
|
// hide menu button when trying a single scene.
|
||||||
|
DisableMenuButton();
|
||||||
|
return bootstrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisableMenuButton()
|
||||||
|
{
|
||||||
|
var menuButton = GameObject.Find("MenuButton");
|
||||||
|
menuButton.SetActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/MediaPipeUnity/Common/Scripts/Solution.cs.meta
Normal file
11
Assets/MediaPipeUnity/Common/Scripts/Solution.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 589adc9f9488f9d8eaee5a408719b452
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
36
Assets/MediaPipeUnity/Common/Scripts/StartSceneController.cs
Normal file
36
Assets/MediaPipeUnity/Common/Scripts/StartSceneController.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public class StartSceneController : MonoBehaviour
|
||||||
|
{
|
||||||
|
private const string _TAG = nameof(Bootstrap);
|
||||||
|
|
||||||
|
[SerializeField] private Image _screen;
|
||||||
|
[SerializeField] private GameObject _consolePrefab;
|
||||||
|
|
||||||
|
private IEnumerator Start()
|
||||||
|
{
|
||||||
|
var _ = Instantiate(_consolePrefab, _screen.transform);
|
||||||
|
|
||||||
|
var bootstrap = GetComponent<Bootstrap>();
|
||||||
|
|
||||||
|
yield return new WaitUntil(() => bootstrap.isFinished);
|
||||||
|
|
||||||
|
DontDestroyOnLoad(gameObject);
|
||||||
|
|
||||||
|
Logger.LogInfo(_TAG, "Loading the first scene...");
|
||||||
|
var sceneLoadReq = SceneManager.LoadSceneAsync(1);
|
||||||
|
yield return new WaitUntil(() => sceneLoadReq.isDone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2ca6b5afaa693af02957f0d68cf058d9
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
87
Assets/MediaPipeUnity/Common/Scripts/WaitForResult.cs
Normal file
87
Assets/MediaPipeUnity/Common/Scripts/WaitForResult.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
using Stopwatch = System.Diagnostics.Stopwatch;
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity
|
||||||
|
{
|
||||||
|
public class WaitForResult : CustomYieldInstruction
|
||||||
|
{
|
||||||
|
public object result { get; private set; }
|
||||||
|
|
||||||
|
protected object tmpResult;
|
||||||
|
protected bool isDone = false;
|
||||||
|
|
||||||
|
private readonly MonoBehaviour _runner;
|
||||||
|
private readonly IEnumerator _inner;
|
||||||
|
private readonly Coroutine _coroutine;
|
||||||
|
|
||||||
|
public bool isError { get; private set; } = false;
|
||||||
|
public Exception error { get; private set; }
|
||||||
|
public override bool keepWaiting => !isDone && !isError;
|
||||||
|
|
||||||
|
public WaitForResult(MonoBehaviour runner, IEnumerator inner, long timeoutMillisec = long.MaxValue)
|
||||||
|
{
|
||||||
|
_runner = runner;
|
||||||
|
_inner = inner;
|
||||||
|
_coroutine = runner.StartCoroutine(Run(timeoutMillisec));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator Run(long timeoutMillisec)
|
||||||
|
{
|
||||||
|
var stopwatch = new Stopwatch();
|
||||||
|
stopwatch.Start();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (stopwatch.ElapsedMilliseconds > timeoutMillisec)
|
||||||
|
{
|
||||||
|
_runner.StopCoroutine(_coroutine);
|
||||||
|
throw new TimeoutException($"{stopwatch.ElapsedMilliseconds}ms has passed");
|
||||||
|
}
|
||||||
|
if (!_inner.MoveNext())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tmpResult = _inner.Current;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
isError = true;
|
||||||
|
error = e;
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
yield return tmpResult;
|
||||||
|
}
|
||||||
|
Done(tmpResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Done(object result)
|
||||||
|
{
|
||||||
|
this.result = result;
|
||||||
|
isDone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class WaitForResult<T> : WaitForResult
|
||||||
|
{
|
||||||
|
public new T result { get; private set; }
|
||||||
|
|
||||||
|
public WaitForResult(MonoBehaviour runner, IEnumerator inner, long timeoutMillisec = long.MaxValue) : base(runner, inner, timeoutMillisec) { }
|
||||||
|
|
||||||
|
protected override void Done(object result)
|
||||||
|
{
|
||||||
|
this.result = (T)result;
|
||||||
|
isDone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/MediaPipeUnity/Common/Scripts/WaitForResult.cs.meta
Normal file
11
Assets/MediaPipeUnity/Common/Scripts/WaitForResult.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 374b5ec183b8225d0ac8b0664812f5f1
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
730
Assets/MediaPipeUnity/WeSign_extractor.unity
Normal file
730
Assets/MediaPipeUnity/WeSign_extractor.unity
Normal file
@@ -0,0 +1,730 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!29 &1
|
||||||
|
OcclusionCullingSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_OcclusionBakeSettings:
|
||||||
|
smallestOccluder: 5
|
||||||
|
smallestHole: 0.25
|
||||||
|
backfaceThreshold: 100
|
||||||
|
m_SceneGUID: 00000000000000000000000000000000
|
||||||
|
m_OcclusionCullingData: {fileID: 0}
|
||||||
|
--- !u!104 &2
|
||||||
|
RenderSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 9
|
||||||
|
m_Fog: 0
|
||||||
|
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||||
|
m_FogMode: 3
|
||||||
|
m_FogDensity: 0.01
|
||||||
|
m_LinearFogStart: 0
|
||||||
|
m_LinearFogEnd: 300
|
||||||
|
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||||
|
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||||
|
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||||
|
m_AmbientIntensity: 1
|
||||||
|
m_AmbientMode: 0
|
||||||
|
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||||
|
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_HaloStrength: 0.5
|
||||||
|
m_FlareStrength: 1
|
||||||
|
m_FlareFadeSpeed: 3
|
||||||
|
m_HaloTexture: {fileID: 0}
|
||||||
|
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
m_DefaultReflectionMode: 0
|
||||||
|
m_DefaultReflectionResolution: 128
|
||||||
|
m_ReflectionBounces: 1
|
||||||
|
m_ReflectionIntensity: 1
|
||||||
|
m_CustomReflection: {fileID: 0}
|
||||||
|
m_Sun: {fileID: 0}
|
||||||
|
m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
|
||||||
|
m_UseRadianceAmbientProbe: 0
|
||||||
|
--- !u!157 &3
|
||||||
|
LightmapSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 12
|
||||||
|
m_GIWorkflowMode: 1
|
||||||
|
m_GISettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_BounceScale: 1
|
||||||
|
m_IndirectOutputScale: 1
|
||||||
|
m_AlbedoBoost: 1
|
||||||
|
m_EnvironmentLightingMode: 0
|
||||||
|
m_EnableBakedLightmaps: 1
|
||||||
|
m_EnableRealtimeLightmaps: 0
|
||||||
|
m_LightmapEditorSettings:
|
||||||
|
serializedVersion: 12
|
||||||
|
m_Resolution: 2
|
||||||
|
m_BakeResolution: 40
|
||||||
|
m_AtlasSize: 1024
|
||||||
|
m_AO: 0
|
||||||
|
m_AOMaxDistance: 1
|
||||||
|
m_CompAOExponent: 1
|
||||||
|
m_CompAOExponentDirect: 0
|
||||||
|
m_ExtractAmbientOcclusion: 0
|
||||||
|
m_Padding: 2
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_LightmapsBakeMode: 1
|
||||||
|
m_TextureCompression: 1
|
||||||
|
m_FinalGather: 0
|
||||||
|
m_FinalGatherFiltering: 1
|
||||||
|
m_FinalGatherRayCount: 256
|
||||||
|
m_ReflectionCompression: 2
|
||||||
|
m_MixedBakeMode: 2
|
||||||
|
m_BakeBackend: 1
|
||||||
|
m_PVRSampling: 1
|
||||||
|
m_PVRDirectSampleCount: 32
|
||||||
|
m_PVRSampleCount: 512
|
||||||
|
m_PVRBounces: 2
|
||||||
|
m_PVREnvironmentSampleCount: 256
|
||||||
|
m_PVREnvironmentReferencePointCount: 2048
|
||||||
|
m_PVRFilteringMode: 1
|
||||||
|
m_PVRDenoiserTypeDirect: 1
|
||||||
|
m_PVRDenoiserTypeIndirect: 1
|
||||||
|
m_PVRDenoiserTypeAO: 1
|
||||||
|
m_PVRFilterTypeDirect: 0
|
||||||
|
m_PVRFilterTypeIndirect: 0
|
||||||
|
m_PVRFilterTypeAO: 0
|
||||||
|
m_PVREnvironmentMIS: 1
|
||||||
|
m_PVRCulling: 1
|
||||||
|
m_PVRFilteringGaussRadiusDirect: 1
|
||||||
|
m_PVRFilteringGaussRadiusIndirect: 5
|
||||||
|
m_PVRFilteringGaussRadiusAO: 2
|
||||||
|
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||||
|
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||||
|
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||||
|
m_ExportTrainingData: 0
|
||||||
|
m_TrainingDataDestination: TrainingData
|
||||||
|
m_LightProbeSampleCountMultiplier: 4
|
||||||
|
m_LightingDataAsset: {fileID: 0}
|
||||||
|
m_LightingSettings: {fileID: 0}
|
||||||
|
--- !u!196 &4
|
||||||
|
NavMeshSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_BuildSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
agentTypeID: 0
|
||||||
|
agentRadius: 0.5
|
||||||
|
agentHeight: 2
|
||||||
|
agentSlope: 45
|
||||||
|
agentClimb: 0.4
|
||||||
|
ledgeDropHeight: 0
|
||||||
|
maxJumpAcrossDistance: 0
|
||||||
|
minRegionArea: 2
|
||||||
|
manualCellSize: 0
|
||||||
|
cellSize: 0.16666667
|
||||||
|
manualTileSize: 0
|
||||||
|
tileSize: 256
|
||||||
|
accuratePlacement: 0
|
||||||
|
maxJobWorkers: 0
|
||||||
|
preserveTilesOutsideBounds: 0
|
||||||
|
debug:
|
||||||
|
m_Flags: 0
|
||||||
|
m_NavMeshData: {fileID: 0}
|
||||||
|
--- !u!1 &560904344
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 560904345}
|
||||||
|
- component: {fileID: 560904348}
|
||||||
|
- component: {fileID: 560904347}
|
||||||
|
- component: {fileID: 560904346}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Screen
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &560904345
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 560904344}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 1475592761}
|
||||||
|
m_Father: {fileID: 884590458}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 100, y: 100}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!114 &560904346
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 560904344}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 827c4431af677e057aa6f14170d0785c, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
_screen: {fileID: 0}
|
||||||
|
--- !u!114 &560904347
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 560904344}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_UVRect:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: 1
|
||||||
|
--- !u!222 &560904348
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 560904344}
|
||||||
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!1 &858349201
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 858349204}
|
||||||
|
- component: {fileID: 858349203}
|
||||||
|
- component: {fileID: 858349202}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: EventSystem
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &858349202
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 858349201}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_SendPointerHoverToParent: 1
|
||||||
|
m_HorizontalAxis: Horizontal
|
||||||
|
m_VerticalAxis: Vertical
|
||||||
|
m_SubmitButton: Submit
|
||||||
|
m_CancelButton: Cancel
|
||||||
|
m_InputActionsPerSecond: 10
|
||||||
|
m_RepeatDelay: 0.5
|
||||||
|
m_ForceModuleActive: 0
|
||||||
|
--- !u!114 &858349203
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 858349201}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_FirstSelected: {fileID: 0}
|
||||||
|
m_sendNavigationEvents: 1
|
||||||
|
m_DragThreshold: 10
|
||||||
|
--- !u!4 &858349204
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 858349201}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 4
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &869147449
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 869147450}
|
||||||
|
- component: {fileID: 869147451}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: OfficialSolution
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &869147450
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 869147449}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 2
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &869147451
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 869147449}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 043ccd99cf82b3cc9bf2e00956ce2b93, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
_configAsset: {fileID: 4900000, guid: 6288c43cdca97374782dac1ea87aa029, type: 3}
|
||||||
|
_screen: {fileID: 560904347}
|
||||||
|
_width: 640
|
||||||
|
_height: 480
|
||||||
|
_fps: 30
|
||||||
|
_poseLandmarkListAnnotationController: {fileID: 1475592763}
|
||||||
|
--- !u!1 &884590454
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 884590458}
|
||||||
|
- component: {fileID: 884590457}
|
||||||
|
- component: {fileID: 884590456}
|
||||||
|
- component: {fileID: 884590455}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Canvas
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &884590455
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 884590454}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_IgnoreReversedGraphics: 1
|
||||||
|
m_BlockingObjects: 0
|
||||||
|
m_BlockingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
--- !u!114 &884590456
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 884590454}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_UiScaleMode: 0
|
||||||
|
m_ReferencePixelsPerUnit: 100
|
||||||
|
m_ScaleFactor: 1
|
||||||
|
m_ReferenceResolution: {x: 800, y: 600}
|
||||||
|
m_ScreenMatchMode: 0
|
||||||
|
m_MatchWidthOrHeight: 0
|
||||||
|
m_PhysicalUnit: 3
|
||||||
|
m_FallbackScreenDPI: 96
|
||||||
|
m_DefaultSpriteDPI: 96
|
||||||
|
m_DynamicPixelsPerUnit: 1
|
||||||
|
m_PresetInfoIsWorld: 0
|
||||||
|
--- !u!223 &884590457
|
||||||
|
Canvas:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 884590454}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_RenderMode: 1
|
||||||
|
m_Camera: {fileID: 1522608648}
|
||||||
|
m_PlaneDistance: 100
|
||||||
|
m_PixelPerfect: 0
|
||||||
|
m_ReceivesEvents: 1
|
||||||
|
m_OverrideSorting: 0
|
||||||
|
m_OverridePixelPerfect: 0
|
||||||
|
m_SortingBucketNormalizedSize: 0
|
||||||
|
m_AdditionalShaderChannelsFlag: 0
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_TargetDisplay: 0
|
||||||
|
--- !u!224 &884590458
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 884590454}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 560904345}
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 3
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 0, y: 0}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
|
m_Pivot: {x: 0, y: 0}
|
||||||
|
--- !u!1001 &937709944
|
||||||
|
PrefabInstance:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Modification:
|
||||||
|
m_TransformParent: {fileID: 1475592761}
|
||||||
|
m_Modifications:
|
||||||
|
- target: {fileID: 1915238444563462410, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
propertyPath: m_RootOrder
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 1915238444563462410, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
propertyPath: m_LocalPosition.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 1915238444563462410, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
propertyPath: m_LocalPosition.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 1915238444563462410, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
propertyPath: m_LocalPosition.z
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 1915238444563462410, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.w
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 1915238444563462410, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 1915238444563462410, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 1915238444563462410, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.z
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 1915238444563462410, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 1915238444563462410, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 1915238444563462410, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.z
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 1915238444563462411, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
propertyPath: m_Name
|
||||||
|
value: PoseLandmarkList Annotation
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
m_RemovedComponents: []
|
||||||
|
m_SourcePrefab: {fileID: 100100000, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
--- !u!4 &937709945 stripped
|
||||||
|
Transform:
|
||||||
|
m_CorrespondingSourceObject: {fileID: 1915238444563462410, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
m_PrefabInstance: {fileID: 937709944}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
--- !u!1 &1475592760
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1475592761}
|
||||||
|
- component: {fileID: 1475592763}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: AnnotationLayer
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &1475592761
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1475592760}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 937709945}
|
||||||
|
m_Father: {fileID: 560904345}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &1475592763
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1475592760}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 70c2b36b394190968977c6493e60e0af, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
annotation: {fileID: 2100643019}
|
||||||
|
_visualizeZ: 0
|
||||||
|
--- !u!1 &1522608646
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1522608649}
|
||||||
|
- component: {fileID: 1522608648}
|
||||||
|
- component: {fileID: 1522608647}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Main Camera
|
||||||
|
m_TagString: MainCamera
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!81 &1522608647
|
||||||
|
AudioListener:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1522608646}
|
||||||
|
m_Enabled: 1
|
||||||
|
--- !u!20 &1522608648
|
||||||
|
Camera:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1522608646}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ClearFlags: 1
|
||||||
|
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||||
|
m_projectionMatrixMode: 1
|
||||||
|
m_GateFitMode: 2
|
||||||
|
m_FOVAxisMode: 0
|
||||||
|
m_SensorSize: {x: 36, y: 24}
|
||||||
|
m_LensShift: {x: 0, y: 0}
|
||||||
|
m_FocalLength: 50
|
||||||
|
m_NormalizedViewPortRect:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: 1
|
||||||
|
near clip plane: 0.3
|
||||||
|
far clip plane: 1000
|
||||||
|
field of view: 60
|
||||||
|
orthographic: 0
|
||||||
|
orthographic size: 5
|
||||||
|
m_Depth: -1
|
||||||
|
m_CullingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_RenderingPath: -1
|
||||||
|
m_TargetTexture: {fileID: 0}
|
||||||
|
m_TargetDisplay: 0
|
||||||
|
m_TargetEye: 3
|
||||||
|
m_HDR: 1
|
||||||
|
m_AllowMSAA: 1
|
||||||
|
m_AllowDynamicResolution: 0
|
||||||
|
m_ForceIntoRT: 0
|
||||||
|
m_OcclusionCulling: 1
|
||||||
|
m_StereoConvergence: 10
|
||||||
|
m_StereoSeparation: 0.022
|
||||||
|
--- !u!4 &1522608649
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1522608646}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 1, z: -10}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &1802405420
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1802405422}
|
||||||
|
- component: {fileID: 1802405421}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Directional Light
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!108 &1802405421
|
||||||
|
Light:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1802405420}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 10
|
||||||
|
m_Type: 1
|
||||||
|
m_Shape: 0
|
||||||
|
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
|
||||||
|
m_Intensity: 1
|
||||||
|
m_Range: 10
|
||||||
|
m_SpotAngle: 30
|
||||||
|
m_InnerSpotAngle: 21.80208
|
||||||
|
m_CookieSize: 10
|
||||||
|
m_Shadows:
|
||||||
|
m_Type: 2
|
||||||
|
m_Resolution: -1
|
||||||
|
m_CustomResolution: -1
|
||||||
|
m_Strength: 1
|
||||||
|
m_Bias: 0.05
|
||||||
|
m_NormalBias: 0.4
|
||||||
|
m_NearPlane: 0.2
|
||||||
|
m_CullingMatrixOverride:
|
||||||
|
e00: 1
|
||||||
|
e01: 0
|
||||||
|
e02: 0
|
||||||
|
e03: 0
|
||||||
|
e10: 0
|
||||||
|
e11: 1
|
||||||
|
e12: 0
|
||||||
|
e13: 0
|
||||||
|
e20: 0
|
||||||
|
e21: 0
|
||||||
|
e22: 1
|
||||||
|
e23: 0
|
||||||
|
e30: 0
|
||||||
|
e31: 0
|
||||||
|
e32: 0
|
||||||
|
e33: 1
|
||||||
|
m_UseCullingMatrixOverride: 0
|
||||||
|
m_Cookie: {fileID: 0}
|
||||||
|
m_DrawHalo: 0
|
||||||
|
m_Flare: {fileID: 0}
|
||||||
|
m_RenderMode: 0
|
||||||
|
m_CullingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_Lightmapping: 4
|
||||||
|
m_LightShadowCasterMode: 0
|
||||||
|
m_AreaSize: {x: 1, y: 1}
|
||||||
|
m_BounceIntensity: 1
|
||||||
|
m_ColorTemperature: 6570
|
||||||
|
m_UseColorTemperature: 0
|
||||||
|
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_UseBoundingSphereOverride: 0
|
||||||
|
m_UseViewFrustumForShadowCasterCull: 1
|
||||||
|
m_ShadowRadius: 0
|
||||||
|
m_ShadowAngle: 0
|
||||||
|
--- !u!4 &1802405422
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1802405420}
|
||||||
|
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
|
||||||
|
m_LocalPosition: {x: 0, y: 3, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 1
|
||||||
|
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
||||||
|
--- !u!114 &2100643019 stripped
|
||||||
|
MonoBehaviour:
|
||||||
|
m_CorrespondingSourceObject: {fileID: 1915238444563462421, guid: 4418f6a92856c5b51b58a36e3be7ed5c, type: 3}
|
||||||
|
m_PrefabInstance: {fileID: 937709944}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 39bac9dd52c31ae7aa01a7383bc44853, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
7
Assets/MediaPipeUnity/WeSign_extractor.unity.meta
Normal file
7
Assets/MediaPipeUnity/WeSign_extractor.unity.meta
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 14d8a9174a4263d83bdc4e90eb9a2ef7
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
94
Assets/MediaPipeUnity/WeSign_extractor_cpu.txt
Normal file
94
Assets/MediaPipeUnity/WeSign_extractor_cpu.txt
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# Copyright 2019 The MediaPipe Authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
# Copied from mediapipe/graphs/holistic_tracking/holistic_tracking_gpu.pbtxt
|
||||||
|
#
|
||||||
|
# CHANGES:
|
||||||
|
# - Add ImageTransformationCalculator and rotate the input
|
||||||
|
# - Remove AnnotationOverlayCalculator
|
||||||
|
|
||||||
|
# Tracks and renders pose + hands + face landmarks.
|
||||||
|
|
||||||
|
# CPU image. (ImageFrame)
|
||||||
|
input_stream: "input_video"
|
||||||
|
|
||||||
|
output_stream: "pose_landmarks"
|
||||||
|
output_stream: "pose_world_landmarks"
|
||||||
|
output_stream: "segmentation_mask"
|
||||||
|
output_stream: "pose_roi"
|
||||||
|
output_stream: "pose_detection"
|
||||||
|
output_stream: "face_landmarks"
|
||||||
|
output_stream: "left_hand_landmarks"
|
||||||
|
output_stream: "right_hand_landmarks"
|
||||||
|
|
||||||
|
# Throttles the images flowing downstream for flow control. It passes through
|
||||||
|
# the very first incoming image unaltered, and waits for downstream nodes
|
||||||
|
# (calculators and subgraphs) in the graph to finish their tasks before it
|
||||||
|
# passes through another image. All images that come in while waiting are
|
||||||
|
# dropped, limiting the number of in-flight images in most part of the graph to
|
||||||
|
# 1. This prevents the downstream nodes from queuing up incoming images and data
|
||||||
|
# excessively, which leads to increased latency and memory usage, unwanted in
|
||||||
|
# real-time mobile applications. It also eliminates unnecessarily computation,
|
||||||
|
# e.g., the output produced by a node may get dropped downstream if the
|
||||||
|
# subsequent nodes are still busy processing previous inputs.
|
||||||
|
node {
|
||||||
|
calculator: "FlowLimiterCalculator"
|
||||||
|
input_stream: "input_video"
|
||||||
|
input_stream: "FINISHED:pose_landmarks"
|
||||||
|
input_stream_info: {
|
||||||
|
tag_index: "FINISHED"
|
||||||
|
back_edge: true
|
||||||
|
}
|
||||||
|
output_stream: "throttled_input_video"
|
||||||
|
node_options: {
|
||||||
|
[type.googleapis.com/mediapipe.FlowLimiterCalculatorOptions] {
|
||||||
|
max_in_flight: 1
|
||||||
|
max_in_queue: 1
|
||||||
|
# Timeout is disabled (set to 0) as first frame processing can take more
|
||||||
|
# than 1 second.
|
||||||
|
in_flight_timeout: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node: {
|
||||||
|
calculator: "ImageTransformationCalculator"
|
||||||
|
input_stream: "IMAGE:throttled_input_video"
|
||||||
|
output_stream: "IMAGE:transformed_input_video"
|
||||||
|
node_options: {
|
||||||
|
[type.googleapis.com/mediapipe.ImageTransformationCalculatorOptions] {
|
||||||
|
flip_vertically: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
node {
|
||||||
|
calculator: "HolisticLandmarkCpu"
|
||||||
|
input_stream: "IMAGE:transformed_input_video"
|
||||||
|
output_stream: "POSE_LANDMARKS:pose_landmarks"
|
||||||
|
output_stream: "WORLD_LANDMARKS:pose_world_landmarks"
|
||||||
|
output_stream: "SEGMENTATION_MASK:segmentation_mask_rotated"
|
||||||
|
output_stream: "POSE_ROI:pose_roi"
|
||||||
|
output_stream: "POSE_DETECTION:pose_detection"
|
||||||
|
output_stream: "FACE_LANDMARKS:face_landmarks"
|
||||||
|
output_stream: "LEFT_HAND_LANDMARKS:left_hand_landmarks"
|
||||||
|
output_stream: "RIGHT_HAND_LANDMARKS:right_hand_landmarks"
|
||||||
|
}
|
||||||
|
|
||||||
|
node: {
|
||||||
|
calculator: "ImageTransformationCalculator"
|
||||||
|
input_stream: "IMAGE:segmentation_mask_rotated"
|
||||||
|
output_stream: "IMAGE:segmentation_mask"
|
||||||
|
}
|
||||||
7
Assets/MediaPipeUnity/WeSign_extractor_cpu.txt.meta
Normal file
7
Assets/MediaPipeUnity/WeSign_extractor_cpu.txt.meta
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6288c43cdca97374782dac1ea87aa029
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
101
Assets/MediaPipeUnity/WeSign_extractor_gpu.txt
Normal file
101
Assets/MediaPipeUnity/WeSign_extractor_gpu.txt
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
# Copyright 2019 The MediaPipe Authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
# Copied from mediapipe/graphs/holistic_tracking/holistic_tracking_gpu.pbtxt
|
||||||
|
#
|
||||||
|
# CHANGES:
|
||||||
|
# - `input_video` is ImageFrame (ImageFrameToGpuBufferCalculator converts it into GpuBuffer)
|
||||||
|
# - Add ImageTransformationCalculator and rotate the input
|
||||||
|
# - Remove AnnotationOverlayCalculator
|
||||||
|
|
||||||
|
# Tracks and renders pose + hands + face landmarks.
|
||||||
|
|
||||||
|
# ImageFrame
|
||||||
|
input_stream: "input_video"
|
||||||
|
|
||||||
|
output_stream: "pose_landmarks"
|
||||||
|
output_stream: "pose_world_landmarks"
|
||||||
|
output_stream: "segmentation_mask"
|
||||||
|
output_stream: "pose_roi"
|
||||||
|
output_stream: "pose_detection"
|
||||||
|
output_stream: "face_landmarks"
|
||||||
|
output_stream: "left_hand_landmarks"
|
||||||
|
output_stream: "right_hand_landmarks"
|
||||||
|
|
||||||
|
# Throttles the images flowing downstream for flow control. It passes through
|
||||||
|
# the very first incoming image unaltered, and waits for downstream nodes
|
||||||
|
# (calculators and subgraphs) in the graph to finish their tasks before it
|
||||||
|
# passes through another image. All images that come in while waiting are
|
||||||
|
# dropped, limiting the number of in-flight images in most part of the graph to
|
||||||
|
# 1. This prevents the downstream nodes from queuing up incoming images and data
|
||||||
|
# excessively, which leads to increased latency and memory usage, unwanted in
|
||||||
|
# real-time mobile applications. It also eliminates unnecessarily computation,
|
||||||
|
# e.g., the output produced by a node may get dropped downstream if the
|
||||||
|
# subsequent nodes are still busy processing previous inputs.
|
||||||
|
node {
|
||||||
|
calculator: "FlowLimiterCalculator"
|
||||||
|
input_stream: "input_video"
|
||||||
|
input_stream: "FINISHED:pose_landmarks"
|
||||||
|
input_stream_info: {
|
||||||
|
tag_index: "FINISHED"
|
||||||
|
back_edge: true
|
||||||
|
}
|
||||||
|
output_stream: "throttled_input_video"
|
||||||
|
node_options: {
|
||||||
|
[type.googleapis.com/mediapipe.FlowLimiterCalculatorOptions] {
|
||||||
|
max_in_flight: 1
|
||||||
|
max_in_queue: 1
|
||||||
|
# Timeout is disabled (set to 0) as first frame processing can take more
|
||||||
|
# than 1 second.
|
||||||
|
in_flight_timeout: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node: {
|
||||||
|
calculator: "ImageFrameToGpuBufferCalculator"
|
||||||
|
input_stream: "throttled_input_video"
|
||||||
|
output_stream: "throttled_input_video_gpu"
|
||||||
|
}
|
||||||
|
|
||||||
|
node: {
|
||||||
|
calculator: "ImageTransformationCalculator"
|
||||||
|
input_stream: "IMAGE_GPU:throttled_input_video_gpu"
|
||||||
|
output_stream: "IMAGE_GPU:transformed_input_video"
|
||||||
|
}
|
||||||
|
|
||||||
|
node {
|
||||||
|
calculator: "HolisticLandmarkGpu"
|
||||||
|
input_stream: "IMAGE:transformed_input_video"
|
||||||
|
output_stream: "POSE_LANDMARKS:pose_landmarks"
|
||||||
|
output_stream: "WORLD_LANDMARKS:pose_world_landmarks"
|
||||||
|
output_stream: "SEGMENTATION_MASK:segmentation_mask_gpu"
|
||||||
|
output_stream: "POSE_ROI:pose_roi"
|
||||||
|
output_stream: "POSE_DETECTION:pose_detection"
|
||||||
|
output_stream: "FACE_LANDMARKS:face_landmarks"
|
||||||
|
output_stream: "LEFT_HAND_LANDMARKS:left_hand_landmarks"
|
||||||
|
output_stream: "RIGHT_HAND_LANDMARKS:right_hand_landmarks"
|
||||||
|
}
|
||||||
|
|
||||||
|
node: {
|
||||||
|
calculator: "ImageTransformationCalculator"
|
||||||
|
input_stream: "IMAGE_GPU:segmentation_mask_gpu"
|
||||||
|
output_stream: "IMAGE_GPU:segmentation_mask_unrotated_gpu"
|
||||||
|
}
|
||||||
|
|
||||||
|
node: {
|
||||||
|
calculator: "GpuBufferToImageFrameCalculator"
|
||||||
|
input_stream: "segmentation_mask_unrotated_gpu"
|
||||||
|
output_stream: "segmentation_mask"
|
||||||
|
}
|
||||||
7
Assets/MediaPipeUnity/WeSign_extractor_gpu.txt.meta
Normal file
7
Assets/MediaPipeUnity/WeSign_extractor_gpu.txt.meta
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4ecf0a6acdaa4fe499c1339d2d4aeddb
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
202
Assets/MediaPipeUnity/Wesign_extractor.cs
Normal file
202
Assets/MediaPipeUnity/Wesign_extractor.cs
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
// Copyright (c) 2021 homuler
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
// ATTENTION!: This code is for a tutorial.
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Unity.VisualScripting;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using Mediapipe.Unity.CoordinateSystem;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Mediapipe.Unity.Tutorial
|
||||||
|
{
|
||||||
|
public class Wesign_extractor : MonoBehaviour
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Config file to set up the graph
|
||||||
|
/// </summary>
|
||||||
|
[SerializeField] private TextAsset _configAsset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The screen object on which the video is displayed
|
||||||
|
/// </summary>
|
||||||
|
[SerializeField] private RawImage _screen;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// width of the screen
|
||||||
|
/// </summary>
|
||||||
|
[SerializeField] private int _width;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// height of the screen
|
||||||
|
/// </summary>
|
||||||
|
[SerializeField] private int _height;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// fps of the screen
|
||||||
|
/// </summary>
|
||||||
|
[SerializeField] private int _fps;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Landmark annotation controller to show the landmarks on the screen
|
||||||
|
/// </summary>
|
||||||
|
[SerializeField] private PoseLandmarkListAnnotationController _poseLandmarkListAnnotationController;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MediaPipe graph
|
||||||
|
/// </summary>
|
||||||
|
private CalculatorGraph _graph;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resource manager for graph resources
|
||||||
|
/// </summary>
|
||||||
|
private ResourceManager _resourceManager;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Webcam texture
|
||||||
|
/// </summary>
|
||||||
|
private WebCamTexture _webCamTexture;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Input texture
|
||||||
|
/// </summary>
|
||||||
|
private Texture2D _inputTexture;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Screen pixel data
|
||||||
|
/// </summary>
|
||||||
|
private Color32[] _pixelData;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stopwatch to give a timestamp to video frames
|
||||||
|
/// </summary>
|
||||||
|
private Stopwatch _stopwatch;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Google Mediapipe setup & run
|
||||||
|
/// </summary>
|
||||||
|
/// <returns> IEnumerator </returns>
|
||||||
|
/// <exception cref="System.Exception"></exception>
|
||||||
|
private IEnumerator Start()
|
||||||
|
{
|
||||||
|
// Webcam setup
|
||||||
|
if (WebCamTexture.devices.Length == 0)
|
||||||
|
{
|
||||||
|
throw new System.Exception("Web Camera devices are not found");
|
||||||
|
}
|
||||||
|
var webCamDevice = WebCamTexture.devices[0];
|
||||||
|
_webCamTexture = new WebCamTexture(webCamDevice.name, _width, _height, _fps);
|
||||||
|
_webCamTexture.Play();
|
||||||
|
|
||||||
|
yield return new WaitUntil(() => _webCamTexture.width > 16);
|
||||||
|
|
||||||
|
_screen.rectTransform.sizeDelta = new Vector2(_width, _height);
|
||||||
|
_screen.texture = _webCamTexture;
|
||||||
|
|
||||||
|
// TODO this method is kinda meh you should use ImageFrame
|
||||||
|
_inputTexture = new Texture2D(_width, _height, TextureFormat.RGBA32, false);
|
||||||
|
_pixelData = new Color32[_width * _height];
|
||||||
|
|
||||||
|
_resourceManager = new LocalResourceManager();
|
||||||
|
yield return _resourceManager.PrepareAssetAsync("pose_detection.bytes");
|
||||||
|
yield return _resourceManager.PrepareAssetAsync("pose_landmark_full.bytes");
|
||||||
|
yield return _resourceManager.PrepareAssetAsync("face_landmark.bytes");
|
||||||
|
yield return _resourceManager.PrepareAssetAsync("hand_landmark_full.bytes");
|
||||||
|
yield return _resourceManager.PrepareAssetAsync("face_detection_short_range.bytes");
|
||||||
|
yield return _resourceManager.PrepareAssetAsync("hand_recrop.bytes");
|
||||||
|
yield return _resourceManager.PrepareAssetAsync("handedness.txt");
|
||||||
|
|
||||||
|
_stopwatch = new Stopwatch();
|
||||||
|
|
||||||
|
// Setting up the graph
|
||||||
|
_graph = new CalculatorGraph(_configAsset.text);
|
||||||
|
var posestream = new OutputStream<NormalizedLandmarkListPacket, NormalizedLandmarkList>(_graph, "pose_landmarks");
|
||||||
|
var leftstream = new OutputStream<NormalizedLandmarkListPacket, NormalizedLandmarkList>(_graph, "left_hand_landmarks");
|
||||||
|
var rightstream = new OutputStream<NormalizedLandmarkListPacket, NormalizedLandmarkList>(_graph, "right_hand_landmarks");
|
||||||
|
posestream.StartPolling().AssertOk();
|
||||||
|
leftstream.StartPolling().AssertOk();
|
||||||
|
rightstream.StartPolling().AssertOk();
|
||||||
|
_graph.StartRun().AssertOk();
|
||||||
|
_stopwatch.Start();
|
||||||
|
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
_inputTexture.SetPixels32(_webCamTexture.GetPixels32(_pixelData));
|
||||||
|
var imageFrame = new ImageFrame(ImageFormat.Types.Format.Srgba, _width, _height, _width * 4, _inputTexture.GetRawTextureData<byte>());
|
||||||
|
var currentTimestamp = _stopwatch.ElapsedTicks / (System.TimeSpan.TicksPerMillisecond / 1000);
|
||||||
|
_graph.AddPacketToInputStream("input_video", new ImageFramePacket(imageFrame, new Timestamp(currentTimestamp))).AssertOk();
|
||||||
|
|
||||||
|
yield return new WaitForEndOfFrame();
|
||||||
|
|
||||||
|
//posestream.TryGetNext(out var poseLandmarks);
|
||||||
|
if (posestream.TryGetNext(out var poseLandmarks))
|
||||||
|
{
|
||||||
|
if (poseLandmarks != null)
|
||||||
|
{
|
||||||
|
// Draw the poseLandmarks on the screen
|
||||||
|
_poseLandmarkListAnnotationController.DrawNow(poseLandmarks);
|
||||||
|
var x = poseLandmarks.Landmark[0];
|
||||||
|
UnityEngine.Debug.Log($"Pose Coordinates: {x}");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (leftstream.TryGetNext(out var leftLandmarks))
|
||||||
|
{
|
||||||
|
if (leftLandmarks != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
var x = leftLandmarks.Landmark[0];
|
||||||
|
UnityEngine.Debug.Log($"Pose left Coordinates: {x}");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rightstream.TryGetNext(out var rightLandmarks))
|
||||||
|
{
|
||||||
|
if (rightLandmarks != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
var x = rightLandmarks.Landmark[0];
|
||||||
|
UnityEngine.Debug.Log($"Pose right Coordinates: {x}");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Propper destruction on the Mediapipegraph
|
||||||
|
/// </summary>
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
if (_webCamTexture != null)
|
||||||
|
{
|
||||||
|
_webCamTexture.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_graph != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_graph.CloseInputStream("input_video").AssertOk();
|
||||||
|
_graph.WaitUntilDone().AssertOk();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
|
||||||
|
_graph.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/MediaPipeUnity/Wesign_extractor.cs.meta
Normal file
11
Assets/MediaPipeUnity/Wesign_extractor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 043ccd99cf82b3cc9bf2e00956ce2b93
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
21
Packages/com.github.homuler.mediapipe/LICENSE.md
Normal file
21
Packages/com.github.homuler.mediapipe/LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 homuler
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
7
Packages/com.github.homuler.mediapipe/LICENSE.md.meta
Normal file
7
Packages/com.github.homuler.mediapipe/LICENSE.md.meta
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e728b176561fa96ed8fde03486bbb142
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a0d7e8178b74a234b982e1c9e95b06e7
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 997abefdb7c9a1a469fea28ffa80e73a
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: Line
|
||||||
|
m_Shader: {fileID: 207, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_ShaderKeywords:
|
||||||
|
m_LightmapFlags: 4
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses: []
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BumpMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailAlbedoMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailMask:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailNormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _EmissionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MainTex:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MetallicGlossMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _OcclusionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _ParallaxMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Floats:
|
||||||
|
- _BumpScale: 1
|
||||||
|
- _Cutoff: 0.5
|
||||||
|
- _DetailNormalMapScale: 1
|
||||||
|
- _DstBlend: 0
|
||||||
|
- _GlossMapScale: 1
|
||||||
|
- _Glossiness: 0.5
|
||||||
|
- _GlossyReflections: 1
|
||||||
|
- _InvFade: 1
|
||||||
|
- _Metallic: 0
|
||||||
|
- _Mode: 0
|
||||||
|
- _OcclusionStrength: 1
|
||||||
|
- _Parallax: 0.02
|
||||||
|
- _SmoothnessTextureChannel: 0
|
||||||
|
- _SpecularHighlights: 1
|
||||||
|
- _SrcBlend: 1
|
||||||
|
- _UVSec: 0
|
||||||
|
- _ZWrite: 1
|
||||||
|
m_Colors:
|
||||||
|
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
|
- _TintColor: {r: 1, g: 0, b: 0, a: 0.5}
|
||||||
|
m_BuildTextureStacks: []
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 207b29ccc237efe2f841a58fbf9e5478
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: SolidConvergence
|
||||||
|
m_Shader: {fileID: 4800000, guid: 349b4f383ce8440988c29923e4684694, type: 3}
|
||||||
|
m_ShaderKeywords:
|
||||||
|
m_LightmapFlags: 4
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses: []
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BumpMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailAlbedoMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailMask:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailNormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _EmissionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MainTex:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MetallicGlossMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _OcclusionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _ParallaxMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Floats:
|
||||||
|
- _BumpScale: 1
|
||||||
|
- _Cutoff: 0.5
|
||||||
|
- _DetailNormalMapScale: 1
|
||||||
|
- _DstBlend: 0
|
||||||
|
- _GlossMapScale: 1
|
||||||
|
- _Glossiness: 0.5
|
||||||
|
- _GlossyReflections: 1
|
||||||
|
- _Metallic: 0
|
||||||
|
- _Mode: 0
|
||||||
|
- _OcclusionStrength: 1
|
||||||
|
- _Parallax: 0.02
|
||||||
|
- _SmoothnessTextureChannel: 0
|
||||||
|
- _SpecularHighlights: 1
|
||||||
|
- _SrcBlend: 1
|
||||||
|
- _UVSec: 0
|
||||||
|
- _ZWrite: 1
|
||||||
|
m_Colors:
|
||||||
|
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
|
m_BuildTextureStacks: []
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0ea6416eaf3d1674291ec58a548378d8
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: SolidMaterial
|
||||||
|
m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_ShaderKeywords:
|
||||||
|
m_LightmapFlags: 4
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses: []
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BumpMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailAlbedoMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailMask:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailNormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _EmissionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MainTex:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MetallicGlossMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _OcclusionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _ParallaxMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Floats:
|
||||||
|
- _BumpScale: 1
|
||||||
|
- _Cutoff: 0.5
|
||||||
|
- _DetailNormalMapScale: 1
|
||||||
|
- _DstBlend: 0
|
||||||
|
- _GlossMapScale: 1
|
||||||
|
- _Glossiness: 0.5
|
||||||
|
- _GlossyReflections: 1
|
||||||
|
- _Metallic: 0
|
||||||
|
- _Mode: 0
|
||||||
|
- _OcclusionStrength: 1
|
||||||
|
- _Parallax: 0.02
|
||||||
|
- _SmoothnessTextureChannel: 0
|
||||||
|
- _SpecularHighlights: 1
|
||||||
|
- _SrcBlend: 1
|
||||||
|
- _UVSec: 0
|
||||||
|
- _ZWrite: 1
|
||||||
|
m_Colors:
|
||||||
|
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
|
m_BuildTextureStacks: []
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b4cdc6c3db064fca08a172ce83ee9d12
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f57990152e91970499d1fd5e93c57d89
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5e77bccec954d4a4a8aa3c1a6bb94d15
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 88d74f24916764d31a81ea6cbfa4ba68
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b9f725766db3aa9629b417fd51e31530
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a193c7ca3dc050c6d8b728e7e129f6a5
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1cf05e630aa9cd6f38522c83264115ee
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0a4c697151131b35db0748e319aed581
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d2c612bb3b8652c34a610554ef621c35
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fa86133ea84e644f09b246134dd08cb6
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: abf39997153d3bc48b9af20bb8d2c75a
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Left
|
||||||
|
Right
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ca5d56c926737c2929c102575e703f4a
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 71b173c4b3503de4a8c9875972d880a4
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 25f7f8d6c78414aa6b47573191f3cb13
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 393afd72cbd0d7781ab071f3d6fb38fe
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 53a5a9537d1a5ea59a5ee2dd6f154af2
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5cde808ca06049fbcbdbf351c0579181
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f05d0f79da53b48858ba17062530313b
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 290ea52a92f4d637289ebae96906985b
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
???
|
||||||
|
Bicycle
|
||||||
|
Boot
|
||||||
|
Laptop
|
||||||
|
Person
|
||||||
|
Chair
|
||||||
|
Cattle
|
||||||
|
Desk
|
||||||
|
Cat
|
||||||
|
Computer mouse
|
||||||
|
Computer monitor
|
||||||
|
Box
|
||||||
|
Mug
|
||||||
|
Coffee cup
|
||||||
|
Stationary bicycle
|
||||||
|
Table
|
||||||
|
Bottle
|
||||||
|
High heels
|
||||||
|
Vehicle
|
||||||
|
Footwear
|
||||||
|
Dog
|
||||||
|
Book
|
||||||
|
Camera
|
||||||
|
Car
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5c852a0cff35fa9d1b6598816e80af6e
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user