ã¯ããã«
åå調æ»è¨äºãæ¸ãã¾ããã
ä»åã¯ç¶ãã§ã調æ»ãå ã«å®éã« WebGL ã®ãµãã¼ããè¡ãã¾ããï¼ãã¤ã¯ãµãã¼ãã®ã¿ã¾ãå¾æ¥ï¼ãå®è£ ããªããæ°ã¥ãããã¨ããåé¡ã«å¯¾ãã¦ã©ã®ããã«å¯¾å¿ããããªã©ã«ã¤ãã¦ã¾ã¨ãã¾ããã®ã§ãç´¹ä»ãã¾ãã
ãã¦ã³ãã¼ã
å®é¨ã¨åé¡è§£æ±º
åå㯠WebGL ã§ã¯è§£æã®å
¥å£ã¨ãªã£ã¦ãããªã¼ãã£ãªãããã¡ãåå¾ã§ãã OnAudioFilterRead()
ãåä½ããªããã¨ããã代æ¿æ段ã¨ã㦠Web Audio API ãããããã¡ãããã£ã¦ããæ¹å¼ã¨ AudioClip.GetData()
ã«ãã£ã¦åã£ã¦ããæ¹å¼ã®ã¡ãªããã»ãã¡ãªãããæ¯è¼ãã¾ãããååã®è¨äºã®çµè«ã¨ãã¦ã¯ãæ±ç¨æ§ã¨ã³ã¼ãå¤æ´æ§ã®å°ãªããã AudioClip.GetData()
ãé¸æãããã¨ã«ãããã¨ãããã®ã§ããã
ããã§ã¯ã¾ãã¯ã·ã³ãã«ã«ã³ã¼ããæ¸ãã¦è©¦ãã¦ã¿ã¾ããAudioClip.GetData()
ãåä½ããã®ã§ããã¨ã¯ AudioSource
ããç¾å¨ã®åçä½ç½®ãåã£ã¦ããå½¢ã«ãã¾ãããªã¼ãã£ãªãããã¡ã®åå¾é¨åã¯ã¡ã¤ã³ã¹ã¬ããã§ã®å®è¡ã«ãªã£ã¦ãã¾ãã¾ãããAPI èªä½ã¯åä½ãã¾ãã
#if UNITY_WEBGL && !UNITY_EDITOR float[] _audioBuffer = null; #endif ... void Update() { ... #if UNITY_WEBGL && !UNITY_EDITOR UpdateWebGL(); #endif ... } ... #if UNITY_WEBGL && !UNITY_EDITOR void UpdateWebGL() { if (!_audioSource) return; var clip = _audioSource.clip; if (!clip || clip.loadState != AudioDataLoadState.Loaded) return; int ch = clip.channels; int fps = 60; int n = AudioSettings.outputSampleRate / fps * ch; if (_audioBuffer == null || _audioBuffer.Length != n) { _audioBuffer = new float[n]; } int offset = _audioSource.timeSamples; offset = math.min(clip.samples - n - 1, offset); clip.GetData(_audioBuffer, offset); OnDataReceived(_audioBuffer, ch); } #endif ... public void OnDataReceived(float[] input, int channels) { // 解æ ... } ... void OnAudioFilterRead(float[] input, int channels) { ... OnDataReceived(input, channels); } ...
æ¬å½ã¯ååã® timeSamples
ãè¦ãã¦ãããããããã®å·®åãåå¾ããã¹ãã§ããããããªãã¨ååä¸ããé³å£°ãããã¡ã¨ãºã¬ãèµ·ãã¦ãã¾ãã¾ãããã ä¸æ¹ããã ã¨ããã©ã¼ãã³ã¹ã®ãã¬ã§ãããã¡ï¼_audioBuffer
ï¼ã®æ°ãå¯å¤ã«ãªã£ã¦ãã¾ããé »ç¹ã« new float[]
ããå¿
è¦ããããããããã©ã¼ãã³ã¹è¦³ç¹ããæã¾ããããã¾ããããã®ãããããã¡ã®å¤§ãããä¸å®ã«ãªããã仮㮠FPS ãè¨å®ããææ°ã®åçé¨åããä¸å®ã®éãã¤ãããã¡ãåã£ã¦ããå½¢ã¨ãã¾ããããã ããã ã¨ã¶ã¤åãã®ãããã¡ã解æã®ãªã³ã°ãããã¡ã«çªã£è¾¼ãã§ããå½¢ã«ãªã£ã¦ãã¾ãããã®é¢ä¿ã§ãããã¡ã®æ¥ç¶é¨ã¯ä¸é£ç¶ã«ãªã£ã¦ããã®ã§ãããåºæ¬çã«ã¯æ¯é³ã®è§£æãªã®ã§ããããã®ãã£ã³ã¯ç¨åº¦ã®é·ããããã°ååãªã®ã§ããã§ãå®éã¯å¤§ããªåé¡ãªãåä½ããã¨æããã¾ãã
Load Type ã«ããå¶é
ããããªãããã®ã¾ã¾ã§ã¯ãã«ããã¦ãåä½ãã¾ãããåå ãè¦ã¦ããã¾ãããã
GetData()
ã® リファレンス ã«ããã¨ãç¾å¨ã®å¶éã¨ãã¦ã¯ãAudioClip ã® Load Type ã Compressed In Memory ã«ãªã£ã¦ããå ´åãAudioClip.GetData()
ã使ç¨ã§ãã¾ããï¼åæ§ã«ã¹ããªã¼ãã³ã°ã®è¨å®ã®éã使ç¨ã§ãã¾ããï¼ãå§ç¸®ãããé³å£°ã«å¯¾ã㦠GetData()
ããã¨æ¬¡ã®ããã«ã¨ã©ã¼ã¨ãªãã¾ãã
確ãã«çãããã¡ã®ç¹å®ä½ç½®ã«ã¢ã¯ã»ã¹ãããããã§ããããå§ç¸®æ¸ã¿ã®ãã®ããã¯ãã®ã¾ã¾ã§ã¯æã£ã¦ãããªãããã§ããã代ããã« Decompressed On Load ãããã¨ããã®åã®éããã¼ãæã«å§ç¸®è§£é¤ãã¦ãããããããããã¡ãåå¾ãããã¨ãã§ããããã«ãªãã¾ãã
ãã®è¨å®ããããã¨ã§å£ãã¯ãã¦ãããããã«ãªãã¾ããããããªãã次ã®åé¡ãåºã¦ãã¾ãã
é³ã®åæãºã¬åé¡
Chrome ãªã©ã® Web ãã©ã¦ã¶ã§ã¯ãã¦ã¼ã¶ã®å ¥åãªãã«åæã«ã¡ãã£ã¢ãåçãããã¨ã«å¯¾ãã¦å¶éãè¨ãã¦ãã¾ããä¾ãã° Chrome ã§ã¯ Autoplay Policy ã¨ããååã§ç´¹ä»ããã¦ãã¾ãã
ãã㯠Web ã®è¦æ ¼ã§ã¯ãªãããã§ãããããã許ãã¨åæã«ããã¯ã°ã©ã¦ã³ãã§é³ããããªããã³ãã³é³´ã£ã¦ãã¾ãã¾ãããåæã«è¨ç®ãªã½ã¼ã¹ãæ¶è²»ããã¦ãã¾ãã®ã§ãã¨ã³ãã¦ã¼ã¶è¦ç¹ã ã¨ãããããä»æ§ã§ãããã éçºè å´ã¯å°ãé¢åã§ã次ã®ãããªæé ã§åçæ¸ã¿ãªã¼ãã£ãªãåéããå¿ è¦ãããã¾ãã
// AudioContext ãçæãã window.onload = function() { var context = new AudioContext(); ... } // ãªã«ãããã®ã¦ã¼ã¶ã¤ã³ã¿ã©ã¯ã·ã§ã³ï¼ããã§ã¯ click ã¤ãã³ãï¼ã // çºçããã AudioContext ã resume ãã document.querySelector('button').addEventListener('click', function() { context.resume().then(() => { console.log('ãã³ãã³'); }); });
ãã¦ããã®ã¬ã¸ã¥ã¼ã å¦çã«ããåã«é³ãåéãã¦é³´ããã ããªãåé¡ãªãã®ã§ãããåçãã¦ããé³å£°ã¨ä½ãããåæãããã¨ãªãã¨ããºã¬ãèµ·ãã¦ãã¾ãããã§ããã©ããã GetData()
ã§ã¯é常éãæåããåçããã¦ããã¨èªèãããããã¡ãéã£ã¦ããã®ã§ãããå®éã®åçããã¦ããé³å£°ã¯ã¬ã¸ã¥ã¼ã ããã¿ã¤ãã³ã°ï¼ã¦ã¼ã¶æä½ã®ã¿ã¤ãã³ã°ï¼ã§é ããåçéå§ããããã¨ãã£ãç¶æ
ã«ãªãããã§ããUnity å´ã®å®è£
ã§ããã®ããããã¾ãå¦çãã¦ã»ããã¨ããã§ãã...ãåºæ¥ã¦ããªããã¨ã«å¯¾ããæ·±ãçç±ã¯èª¿ã¹ã¾ããããããã¾ããã§ããï¼å
é¨çã«ã¯é³å£°çºé³ãããã¦ããå½¢ã«ããªãã¨ã確ãã«å°ãå±é¢ã¯åºã¦ããããªã®ã§ãã©ã£ã¡ãåããåé¡ãªã®ããããã¾ããï¼ãä¸å¿ãUnity ã§ã® Autoplay Policy ã«å¯¾ããå®è£
ãè¦ã¦ã¿ãã¨æ¬¡ã®ããã«ã¦ã¼ã¶å
¥åãè¦ã¦ã³ã³ããã¹ãã resume()
ãã¦ãã¾ããã
mousedown
ã¯ä¸»ã« PC åããtouchstart
ã¯ã¿ããå¯è½ãªããã¤ã¹ï¼ã¹ãããªã©ï¼åãã®ããã§ããåºæ¬çã«ã¯ãã¢ããªå¶ä½è
åãã®ãã¹ããã©ã¯ãã£ã¹ã¨ãã¦ã¯ãä½ãããã®ã¹ã¿ã¼ãç»é¢ãè¨ããã¯ãªãã¯ãã¿ãããä¿ãã¦ããã²ã¼ã ãã¢ããªãéå§ãã¦ãããããã®å¾ã«é³ãé³´ããå§ãããã¨ããæãã®ããã§ãããã ãã©ã¤ãã©ãªå¶ä½è
ã¨ãã¦ã¯è²ã
ãªã¦ã¼ã¹ã±ã¼ã¹ãæ¾ãããã«ãã¦ã¼ã¶æä½åããé³´ã£ã¦ããé³ã対å¿ãããã§ãã
対çæ¤è¨
ãã¦ãåæãºã¬ãç´ãæ¹æ³ã¯ãªããã¨èª¿ã¹ã¦ããã¨ããå°ã主æ¨ã¯éãã¾ãã Unity ã® WebGL ã§ã®ç¥è¦ã®é¢ç½ãè¨äºãããã¾ããã
è¨äºã«ãã㨠AudioSource.timeSamples
ã¯ã©ããã代å
¥ãå¹ããããªã®ã§ã次ã®è¬ã³ã¼ããæ¸ãã¦ã¿ã¾ãã
void UpdateWebGL() { ... _audioSource.timeSamples = _audioSource.timeSamples ... }
ãªãã¨ããããã¨åçä½ç½®ããããã¡ã®åå¾å ´æã¨ä¸è´ãã¦ãã¿ã¤ãã³ã°ãåããªããã·ã³ã¯ã«ãªãã¾ãï¼ããããã£ã® get / set ã¯ä¸èº«ã¯é¢æ°ãªã®ã§ãWebGL ã®å ´åã¯å
é¨ã®å®è£
ãé対称ã«ãªã£ã¦ãããã§ããï¼ããã ãä¸ã®ã³ã¼ãã§ã¯æ¯ãã¬ã¼ã Update()
ã¿ã¤ãã³ã°ã§ä½ç½®èª¿æ´ããã¦ãã¾ã£ã¦ããé¢ä¿ã§ããªã¼ãã£ãªã¹ã¬ããã¨ã¡ã¤ã³ã¹ã¬ããã«ããæ´æ°ã¿ã¤ãã³ã°ã®èª¤å·®ï¼ãªã¼ãã£ãªæ´æ°ã®ã¹ã¬ããã®å¨æ㯠Unity ã®ã¡ã¤ã³ã¹ã¬ããã®æ´æ°å¨æã¨ç°ãªãï¼ã§ãé³ãã¬ãã¬ããã¾ãã
ã©ããã«ããã¯ããããã³ã¼ã«ããã¯ãªã©ã§ AudioContext ã®ã¬ã¸ã¥ã¼ã ã¿ã¤ãã³ã°ã«ãã®å¦çãå®è¡ãã¦ãããã°è¯ããã¨æãã¾ããããUnity ãåãåºãã³ã¼ãä¸ã® _JS_Sound_Init
ãè¦ãã¦ã¿ã¦ããã¾ãè¯ãä»çµã¿ã¯ç¡ãããã§ãããã¡ããåãåºãå¾ã® .js ãæ¸ãæãã¦ãããã°è²ã
ã§ãã¾ãããæ¯åº¦ãã«ãå¾ã«æ¸ãæããã®ã¯ã©ã¤ãã©ãªä½¿ç¨è
å´ã®æéããããã¾ããé¿ãããã¨ããã§ãã
C# ã ãã§ãªãã¹ãå®çµãããã£ãã§ããããã㯠jslib ãã©ã°ã¤ã³ãæ¸ãã¦ã¦ã¼ã¶ã¤ãã³ãã«ããã¯ãã¦ä¸è¨ã³ã¼ããå®è¡ã§ããããã«ãã¦ã¿ã¾ãã
å®è£ ã®æµã
è¨è¨
æ¹éã¨ãã¦ã¯ JavaScript ä¸ã§ window.addEventListner
ããã³ã¼ã«ããã¯ããåçæ¸ã¿ã®è¤æ°ã® uLipSync ã¤ã³ã¹ã¿ã³ã¹ãåãåããããã«ãããã§ããå°ãå³ã«ããã¨æµããè¤éã§ãã次ã®ãããªè¨è¨ããã¦ã¿ã¾ããã
- static ãªã¯ã©ã¹ãä½æï¼ããã§ã¯
WebGL
ï¼ãããã®ä¸ã§RuntimeInitializeOnLoadMethod
ã¢ããªãã¥ã¼ããå©ç¨ãã¦èµ·åæã«åã¯ã©ã¹å ã®ã³ã¼ã«ããã¯ãï¼ããã§ã¯OnAuidoContextInitiallyResumed
ã jslib å´ã«ç»é² - åæã«
window.addEventListener
ã§ç¨®ã ã®ã¤ãã³ããå¼ã°ããããã®ã³ã¼ã«ããã¯ãå¼ã°ããããç»é² uLipSync
ã³ã³ãã¼ãã³ãã®Awake
ã§WebGL
ã¯ã©ã¹ã«èªèº«ãç»é²- ã¦ã¼ã¶ã¼ã¤ãã³ããçºç«ããã㨠jslib å´ããç»é²ãã¦ããã C# å´ã®
OnAuidoContextInitiallyResumed
ãçºç« - ç»é²ãã¦ããã
uLipSync
ã³ã³ãã¼ãã³ãã«éç¥
ãã®æµãã§ãã
å®è£
ã§ã¯å ·ä½çãªã³ã¼ããè¦ãã¦ã¿ã¾ãããã
WebGL.cs
ã¾ã㯠C# å´ããã§ãã
public class uLipSync : MonoBehaviour { ... void Awake() { ... #if UNITY_WEBGL && !UNITY_EDITOR InitializeWebGL(); #endif } ... #if UNITY_WEBGL && !UNITY_EDITOR public void InitializeWebGL() { WebGL.Register(this); } public void OnAuidoContextInitiallyResumed() { _audioSource.timeSamples = _audioSource.timeSamples; ... } ... #endif ... } public static class WebGL { static List<uLipSync> instances = new List<uLipSync>(); static bool isAudioContextResumed = false; public static void Register(uLipSync instance) { if (isAudioContextResumed) return; instances.Add(instance); } [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void Init() { OnLoad(OnAuidoContextInitiallyResumed); } [DllImport("__Internal")] public static extern void OnLoad(System.Action callback); [AOT.MonoPInvokeCallback(typeof(System.Action))] public static void OnAuidoContextInitiallyResumed() { foreach (var instance in instances) { instance.OnAuidoContextInitiallyResumed(); } instances.Clear(); isAudioContextResumed = true; } }
DllImport
ã§å®£è¨ãã¦ãã OnLoad
ãå¾ã§è¦ã jslib å´ã®é¢æ°ã«ãªãã¾ãï¼WebGL ã§ã¯ DllImport("__Internal")
ãã¤ãããã¨ã§å¼ã³åºããå¯è½ï¼ãMonoPInvokeCallback
ã¢ããªãã¥ã¼ããã¤ãã OnAuidoContextInitiallyResumed
ããã® OnLoad
ã«æ¸¡ãã¦åæåãã¦ãã¾ããå¾ã§ããã jslib å´ããå¼ã¶ã¤ã¡ã¼ã¸ã§ãï¼jslib å´ããå¼ã¶é¢æ°ã«ã¯ãã®ã¢ããªãã¥ã¼ããä»ä¸ããå¿
è¦ãããã¾ãï¼ãuLipSync
ã³ã³ãã¼ãã³ããã㯠Register
ãå¼ã°ãã¦å uLipSync
ã¤ã³ã¹ã¿ã³ã¹ããªã¹ãã«ç»é²ãããå¾ã§ jslib å´ãã OnAuidoContextInitiallyResumed
ãã³ã¼ã«ãããæã«ãã¹ã¦ã®ã¤ã³ã¹ã¿ã³ã¹ã«éç¥ãé£ã¶ãã¨ããã¤ã¡ã¼ã¸ã§ãã
uLipSync.jslib
次㯠jslib å´ã§ãã
const uLipSyncPlugin = { $uLipSync: { unityCsharpCallback: null, resumeEventNames: ['keydown', 'mousedown', 'touchstart'], userEventCallback: function() { Module.dynCall_v(uLipSync.unityCsharpCallback); for (const ev of uLipSync.resumeEventNames) { window.removeEventListener(ev, uLipSync.userEventCallback); } } }, OnLoad: function(callback) { if (WEBAudio.audioContext.state !== 'suspended') return; uLipSync.unityCsharpCallback = callback; for (const ev of uLipSync.resumeEventNames) { window.addEventListener(ev, uLipSync.userEventCallback); } }, }; autoAddDeps(uLipSyncPlugin, '$uLipSync'); mergeInto(LibraryManager.library, uLipSyncPlugin);
jslib å´ã¯ã¡ãã£ã¨çãããã¾ããâ¦ãã¨ã¦ã詳ãã解説ã gtk2k ããã«ãã£ã¦æ¸ããã¦ããã®ã§ãä¸èªãã ããã
ç´°ããã¨ãããè¦ã¦ããã¾ããautoAddDeps
ãè¡ã㨠JavaScript å´ã« $ ãå¤ãããªãã¸ã§ã¯ããï¼Unity ã®ã¹ã³ã¼ãå
ã«ï¼çæããã¾ããä¸æ¹ã§é常éã mergeInto
ããã¨ã¢ã³ãã¼ã¹ã³ã¢ä»ãã®é¢æ°ã¨ãã¦å±éããã¾ãï¼ãã®åã®éã merge into ã¨ãã¦å«ã¾ããã¤ã¡ã¼ã¸ï¼ããªã®ã§ä¸æçã«å¤æ°ãä¿åãããã¨ã㯠autoAddDeps
ãã¦ãã¾ããå
·ä½çã«ã¯ä»¥ä¸ã®ãããªã³ã¼ãã¸ã¨å±éããã¾ãã
OnLoad
ãå¼ã°ããã¿ã¤ãã³ã°ã§ã¯ã³ã³ããã¹ãã suspended
ã®ã¨ãã ãå¦çãã¾ãï¼Autoplay Policy ãåããUnity å´ããã¯åçãã¦ããããã«è¦ãããã©é³å£°ã¯åçããã¦ããªãç¶æ
ï¼ãä¸ããããã³ã¼ã«ããã¯ãä¿åããã¤ãã³ããªã¹ããç»é²ãã¦ããã¾ãããã㦠userEventCallback
ãã¦ã¼ã¶æä½ã«ãã£ã¦å¼ã°ããã¨ããModule.dynCall_v
ã§ãã®ã³ã¼ã«ããã¯ãå¼ã³åºããã¤ãã³ããªã¹ãã解é¤ãã¾ãã
ãã® Module.dynCall_v
ã§ããããã¥ã¡ã³ãããã¾ãããã¾ããâ¦ã以ä¸ã®ãµã¤ãã®è§£èª¬ãã¨ã¦ãããããããã£ãã§ãã
Unity å ¬å¼ã§ã¯è£½åã®ä¸ã¤ã§ãã Untiy Forma ã®ããã¥ã¡ã³ãã«è¨è¼ãããã¾ãã
Module.dynCall_v(...)
ã®ä»£ããã« dynCall('v', ...)
ã§ãåä½ãã¾ãããdynCallLegacy
ã«æ¥ç¶ããã¦ãã¾ã£ã¦ããã®ã§ãæå
ã®ã³ã¼ãã§ã¯ Module
ã使ç¨ããæ¹åã§ã²ã¨ã¾ãæ¸ãã¦ãããã¨ã«ãã¾ãã
çµæ
ãã¦ããã㧠uLipSync
ã® OnAuidoContextInitiallyResumed
ãã¦ã¼ã¶æä½æã«ãã£ã¦å¼ã°ããAudioSource
ã® timeSamples
ã« timeSamples
ã代å
¥ãããã¨ããè¬ã³ã¼ããçµã¦åæãåããããã«ãªãã¾ããããã㧠WebGL ã§ã®ãµãã¼ããåºæ¥ãå½¢ã«ãªãã¾ãã
ã¿ã¤ãã³ã°èª¿æ´
ããã§ãã¡ãã£ã¨ã¿ã¤ãã³ã°ããºã¬ã¦ããï¼é ãã¦ããï¼ããã«è¦ãã¾ãããä»åã¯ä»»æã®å ´æã®ãããã¡ãåã£ã¦ããå½¢ã«ãªã£ã¦ããã®ã§ããã®åã£ã¦ããä½ç½®ã«ãªãã»ãããããããã¨ãå¯è½ã§ãããã«ããè¯ãæãã«å£ãåãããã«èª¿æ´ã§ãã¾ãï¼éã«ãªã¢ã«ã¿ã¤ã ã®ãããã¡ãã¼ã¹ã ã¨å èªã¿ãåºæ¥ã¾ããããªã®ã§ãã®æ¹å¼ã®å¯ä¸ã®å©ç¹ã ã¨æãã¾ãï¼ã
[Range(-0.2f, 0.2f)] pulbic float audioSyncOffsetTime = 0.1f; ... void UpdateWebGL() { ... int offset = _audioSource.timeSamples; offset += (int)(audioSyncOffsetTime * AudioSettings.outputSampleRate * ch); ... clip.GetData(_audioBuffer, offset); OnDataReceived(_audioBuffer, ch); }
ããã©ã¼ãã³ã¹
æå¾ã«ç¾ç¶ã®ããã©ã¼ãã³ã¹ãè¦ã¦ããã¾ããããChrome ã®ãããã¡ã¤ã©ã§è¦ã¦ã¿ã¾ãã
uLipSync ã§ã¯åå¾ãããããã¡ã¯ JobSystem ã«ãã£ã¦çæãããã¸ã§ããã¯ã¼ã«ã¹ã¬ãã 1 ã¤ã使ãè£ã§è¨ç®ãè¡ããã次ãã¬ã¼ã ã§è§£æçµæãååããã¾ãããã WebGL ã§ã¯ããã©ã«ãã§ã¯ä¸å³ã®ããã«ã¡ã¤ã³ã¹ã¬ããä¸ã§ã¸ã§ããå®è¡ããã¾ãã
Unity ä¸ã§ã¯ã¾ã WebGL ã¯ã¡ã¤ã³ã¹ã¬ããã®ã¿ã®å®è¡ãªã®ã§ãç¾ç¶ã®ã³ã¼ãã®ã¾ã¾ã§ã¯ããã©ã¼ãã³ã¹æ¹åã¯ãã°ããå¾ ã¤ãã¨ã«ãªãããããã¾ãããJobSystem è¨ç®é¨åãåãåºããJavaScript å´ã® Web Worker ä¸ã§å®è¡ã§ãããã jslib ã使ã£ã¦ã¤ãªããã¨ãã§ããã°ããã©ã¼ãã³ã¹æ¹åã®ä½å°ã¯ããããããã¾ãããããã¯ä»å¾ã®èª²é¡ã¨ãããã¨æãã¾ãã
ä¸è¨ç»åãè¦ã¦ããã ãã¨ãããããã«ãç§ã® MacBook Pro (2021 / M1) ã 㨠4 ms ãããã£ã¦ãã¾ã£ã¦ãã¾ãããããç´°ããè¦ã¦ããã¨ããã¦ã³ãµã³ãã«ã®ããã®åå¦çã¨ãã¦è¡ã£ã¦ãããã¼ãã¹ãã£ã«ã¿å¦çã«æéãããã£ã¦ãã¾ãã
è¤æ°ãã£ã©ã®ä¼è©±ãªã©ã®ã¦ã¼ã¹ã±ã¼ã¹ã§ã¯ãå¯è½ãªéã¯äºåãã¤ã¯ãç©æ¥µçã«å©ç¨ãã¦ãã£ãã»ããè¯ãããã§ãã
ãããã«
次åã¯ãã¤ã¯ã®ãµãã¼ããè¡ãããã¨æãã¾ãããã¤ã¯å´ã¯ä»åã®ããã« Unity å´ã®åãæ±ããå¤ããã ãã§ã¯å®ç¾ã§ãããJavaScript å´ã§ getUserMedia() ãã¦åå¾ãããããã¡ã Unity å´ã¸æ¸¡ãå¿ è¦ãããã®ã§ãæ¢åã®ä»çµã¿ã¨ã®äºææ§ãä¿ã¤ããã«å°ããããäºå®ã§ãã