#define ENABLE_LOG /* * Copyright (c) 2014 - 2022 t_saki@serenegiant.com */ using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace Serenegiant.UVC { public class UVCDrawer : MonoBehaviour, IUVCDrawer { /** * IUVCSelectorがセットされていないとき * またはIUVCSelectorが解像度選択時にnullを * 返したときのデフォルトの解像度(幅) */ public int DefaultWidth = 1280; /** * IUVCSelectorがセットされていないとき * またはIUVCSelectorが解像度選択時にnullを * 返したときのデフォルトの解像度(高さ) */ public int DefaultHeight = 720; /** * 接続時及び描画時のフィルタ用 */ public UVCFilter[] UVCFilters; /** * GameObject保留UVC设备的视频目标材质 * 如果未设置,则使用与分配此脚本相同的GameObjec。 */ public List RenderTargets; [HideInInspector] public Action StartPreviewAction; [HideInInspector] public Action StopPreviewAction; //-------------------------------------------------------------------------------- private const string TAG = "UVCDrawer#"; /** * UVC機器からの映像の描画先Material * TargetGameObjectから取得する * 優先順位: * TargetGameObjectのSkybox * > TargetGameObjectのRenderer * > TargetGameObjectのRawImage * > TargetGameObjectのMaterial * いずれの方法でも取得できなければStartでUnityExceptionを投げる */ private UnityEngine.Object[] TargetMaterials; /** * オリジナルのテクスチャ * UVCカメラ映像受け取り用テクスチャをセットする前に * GetComponent().material.mainTextureに設定されていた値 */ private Texture[] SavedTextures; private Quaternion[] quaternions; //================================================================================ // Start is called before the first frame update void Start() { #if (!NDEBUG && DEBUG && ENABLE_LOG) Console.WriteLine($"{TAG}Start:"); #endif UpdateTarget(); } // // Update is called once per frame // void Update() // { // // } //================================================================================ /** * UVC機器が接続された * IOnUVCAttachHandlerの実装 * @param manager 呼び出し元のUVCManager * @param device 対象となるUVC機器の情報 * @return true: UVC機器を使用する, false: UVC機器を使用しない */ public bool OnUVCAttachEvent(UVCManager manager, UVCDevice device) { #if (!NDEBUG && DEBUG && ENABLE_LOG) Console.WriteLine($"{TAG}OnUVCAttachEvent:{device}"); #endif // XXX 今の実装では基本的に全てのUVC機器を受け入れる // ただしTHETA SとTHETA VとTHETA Z1は映像を取得できないインターフェースがあるのでオミットする // CanDrawと同様にUVC機器フィルターをインスペクタで設定できるようにする var result = !device.IsRicoh || device.IsTHETA; result &= UVCFilter.Match(device, UVCFilters); return result; } /** * UVC機器が取り外された * IOnUVCDetachEventHandlerの実装 * @param manager 呼び出し元のUVCManager * @param device 対象となるUVC機器の情報 */ public void OnUVCDetachEvent(UVCManager manager, UVCDevice device) { #if (!NDEBUG && DEBUG && ENABLE_LOG) Console.WriteLine($"{TAG}OnUVCDetachEvent:{device}"); #endif } // /** // * 解像度選択 // * IOnUVCSelectSizeHandlerの実装 // * @param manager 呼び出し元のUVCManager // * @param device 対象となるUVC機器の情報 // * @param formats 対応している解像度についての情報 // */ // public SupportedFormats.Size OnUVCSelectSize(UVCManager manager, UVCDevice device, SupportedFormats formats) // { //#if (!NDEBUG && DEBUG && ENABLE_LOG) // Console.WriteLine($"{TAG}OnUVCSelectSize:{device}"); //#endif // if (device.IsTHETA_V || device.IsTHETA_Z1) // { //#if (!NDEBUG && DEBUG && ENABLE_LOG) // Console.WriteLine($"{TAG}OnUVCSelectSize:THETA V/Z1"); //#endif // return FindSize(formats, 3840, 1920); // } // else if (device.IsTHETA_S) // { //#if (!NDEBUG && DEBUG && ENABLE_LOG) // Console.WriteLine($"{TAG}OnUVCSelectSize:THETA S"); //#endif // return FindSize(formats, 1920, 1080); // } // else // { //#if (!NDEBUG && DEBUG && ENABLE_LOG) // Console.WriteLine($"{TAG}OnUVCSelectSize:other UVC device,{device}"); //#endif // return formats.Find(DefaultWidth, DefaultHeight); // } // } /** * 获取IUVCdrawer是否可以绘制指定的UVC设备的视频 * 实现IUVCdrawer * @param manager 调用方UVCmanager * @param device 目标UVC设备信息 */ public bool CanDraw(UVCManager manager, UVCDevice device) { return UVCFilter.Match(device, UVCFilters); } /** * 已开始获取视频 * 实现IUVCdrawer * @param manager 调用方UVCManager * @param device 对象的UVC设备的信息 * @param tex 从UVC设备接收视频的纹理实例 */ public void OnUVCStartEvent(UVCManager manager, UVCDevice device, Texture tex) { #if (!NDEBUG && DEBUG && ENABLE_LOG) Console.WriteLine($"{TAG}OnUVCStartEvent:{device}"); #endif HandleOnStartPreview(tex); StartPreviewAction?.Invoke(tex); } /** * 视频获取已完成 * 实现IUVCdrawer * @param manager 调用方UVCManager * @param device 对象的UVC设备的信息 */ public void OnUVCStopEvent(UVCManager manager, UVCDevice device) { #if (!NDEBUG && DEBUG && ENABLE_LOG) Console.WriteLine($"{TAG}OnUVCStopEvent:{device}"); #endif HandleOnStopPreview(); StopPreviewAction?.Invoke(); } //================================================================================ /** * 更新目标 */ private void UpdateTarget() { bool found = false; if ((RenderTargets != null) && (RenderTargets.Count > 0)) { TargetMaterials = new UnityEngine.Object[RenderTargets.Count]; SavedTextures = new Texture[RenderTargets.Count]; quaternions = new Quaternion[RenderTargets.Count]; int i = 0; foreach (var target in RenderTargets) { if (target != null) { var material = TargetMaterials[i] = GetTargetMaterial(target); if (material != null) { found = true; } #if (!NDEBUG && DEBUG && ENABLE_LOG) Console.WriteLine($"{TAG}UpdateTarget:material={material}"); #endif } i++; } } if (!found) { //找不到一个目标时,该脚本 //尝试从AddComponent GameObject获取 //在XXX RenderTargets中设置gameObject? TargetMaterials = new UnityEngine.Object[1]; SavedTextures = new Texture[1]; quaternions = new Quaternion[1]; TargetMaterials[0] = GetTargetMaterial(gameObject); found = TargetMaterials[0] != null; } if (!found) { throw new UnityException("no target material found."); } } /** * 获取将图像绘制为纹理的材质 * 如果指定的GameObject具有Skybox/Render/RawImage/Material,则从中获取Material * 如果每个都分配了多个,则返回第一个找到的可用项 * 优先级:Skybox>Render>RawImage>Material * @param target * @return如果找不到,则返回null */ UnityEngine.Object GetTargetMaterial(GameObject target/*NonNull*/) { // Skyboxの取得を試みる var skyboxs = target.GetComponents(); if (skyboxs != null) { foreach (var skybox in skyboxs) { if (skybox.isActiveAndEnabled && (skybox.material != null)) { RenderSettings.skybox = skybox.material; return skybox.material; } } } // Skyboxが取得できなければRendererの取得を試みる var renderers = target.GetComponents(); if (renderers != null) { foreach (var renderer in renderers) { if (renderer.enabled && (renderer.material != null)) { return renderer.material; } } } // SkyboxもRendererも取得できなければRawImageの取得を試みる var rawImages = target.GetComponents(); if (rawImages != null) { foreach (var rawImage in rawImages) { if (rawImage.enabled && (rawImage.material != null)) { return rawImage; } } } // SkyboxもRendererもRawImageも取得できなければMaterialの取得を試みる var material = target.GetComponent(); if (material != null) { return material; } return null; } private void RestoreTexture() { for (int i = 0; i < TargetMaterials.Length; i++) { var target = TargetMaterials[i]; try { if (target is Material) { (target as Material).mainTexture = SavedTextures[i]; } else if (target is RawImage) { (target as RawImage).texture = SavedTextures[i]; } } catch { Console.WriteLine($"{TAG}RestoreTexture:Exception cought"); } SavedTextures[i] = null; quaternions[i] = Quaternion.identity; } } private void ClearTextures() { for (int i = 0; i < SavedTextures.Length; i++) { SavedTextures[i] = null; } } /** * 映像取得開始時の処理 * @param tex 映像を受け取るテクスチャ */ private void HandleOnStartPreview(Texture tex) { #if (!NDEBUG && DEBUG && ENABLE_LOG) Console.WriteLine($"{TAG}HandleOnStartPreview:({tex})"); #endif int i = 0; foreach (var target in TargetMaterials) { if (target is Material) { #if (!NDEBUG && DEBUG && ENABLE_LOG) Console.WriteLine($"{TAG}HandleOnStartPreview:assign Texture to Material({target})"); #endif SavedTextures[i++] = (target as Material).mainTexture; (target as Material).mainTexture = tex; } else if (target is RawImage) { #if (!NDEBUG && DEBUG && ENABLE_LOG) Console.WriteLine($"{TAG}HandleOnStartPreview:assign Texture to RawImage({target})"); #endif SavedTextures[i++] = (target as RawImage).texture; (target as RawImage).texture = tex; } } } /** * 映像取得が終了したときのUnity側の処理 */ private void HandleOnStopPreview() { #if (!NDEBUG && DEBUG && ENABLE_LOG) Console.WriteLine($"{TAG}HandleOnStopPreview:"); #endif // 描画先のテクスチャをもとに戻す RestoreTexture(); #if (!NDEBUG && DEBUG && ENABLE_LOG) Console.WriteLine($"{TAG}HandleOnStopPreview:finished"); #endif } } // class UVCDrawer } // namespace Serenegiant.UVC