public void MessageDaisyChain(ref uOSC.Message message, int callCount) { //Startされていない場合無視 if (externalReceiverManager == null || enabled == false || gameObject.activeInHierarchy == false) { return; } if (shutdown) { return; } StatusMessage = "OK"; //異常を検出して動作停止 try { ProcessMessage(ref message); } catch (Exception e) { StatusMessage = "Error: Exception"; Debug.LogError(" --- Communication Error ---"); Debug.LogError(e.ToString()); shutdown = true; return; } if (!externalReceiverManager.SendNextReceivers(message, callCount)) { StatusMessage = "Infinite loop detected!"; shutdown = true; } }
private void ProcessMessage(ref uOSC.Message message) { //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない if (message.address == null || message.values == null) { StatusMessage = "Bad message."; return; } //カメラ姿勢FOV同期 v2.1 if (message.address == "/VMC/Ext/Cam" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) && (message.values[8] is float) ) { cameraPos.x = (float)message.values[1]; cameraPos.y = (float)message.values[2]; cameraPos.z = (float)message.values[3]; cameraRot.x = (float)message.values[4]; cameraRot.y = (float)message.values[5]; cameraRot.z = (float)message.values[6]; cameraRot.w = (float)message.values[7]; fov = (float)message.values[8]; //受信と更新のタイミングは切り離した } }
void OnDataReceived(uOSC.Message message) { if (message.address != "/uNvPipe/Data") { return; } var buf = (byte[])message.values[0]; var pinnedBuf = GCHandle.Alloc(buf, GCHandleType.Pinned); var ptr = pinnedBuf.AddrOfPinnedObject(); decoder.Decode(ptr, buf.Length); pinnedBuf.Free(); }
//デイジーチェーン処理 public void MessageDaisyChain(ref uOSC.Message message, int callCount) { //Startされていない場合無視 if (externalReceiverManager == null || enabled == false || gameObject.activeInHierarchy == false) { return; } //エラー・無限ループ時は処理をしない if (shutdown) { return; } //パケットリミッターが有効な場合、一定以上のパケットフレーム/フレーム数を観測した場合、次のフレームまでパケットを捨てる if (PacktLimiter && (LastPacketframeCounterInFrame > PACKET_LIMIT_MAX)) { DropPackets++; return; } //メッセージを処理 if (!Freeze) { //異常を検出して動作停止 try { ProcessMessage(ref message); } catch (Exception e) { StatusMessage = "Error: Exception"; Debug.LogError(" --- Communication Error ---"); Debug.LogError(e.ToString()); shutdown = true; return; } } //次のデイジーチェーンへ伝える if (!externalReceiverManager.SendNextReceivers(message, callCount)) { //無限ループ対策 StatusMessage = "Infinite loop detected!"; //以降の処理を全部停止 shutdown = true; } }
private void ProcessMessage(ref uOSC.Message message) { //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない if (message.address == null || message.values == null) { StatusMessage = "Bad message."; return; } //ライト同期 v2.4 if (message.address == "/VMC/Ext/Light" && (message.values[0] is string) && //name (message.values[1] is float) && //pos.x (message.values[2] is float) && //poy.y (message.values[3] is float) && //pos.z (message.values[4] is float) && //q.x (message.values[5] is float) && //q.y (message.values[6] is float) && //q.z (message.values[7] is float) && //q.w (message.values[8] is float) && //r (message.values[9] is float) && //g (message.values[10] is float) && //b (message.values[11] is float) //a ) { if (VMCControlledLight != null && VMCControlledLight.transform != null) { pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; col.r = (float)message.values[8]; col.g = (float)message.values[9]; col.b = (float)message.values[10]; col.a = (float)message.values[11]; VMCControlledLight.transform.localPosition = pos; VMCControlledLight.transform.localRotation = rot; VMCControlledLight.color = col; } } }
//IExternalReceiverのリストを使って配信する public bool SendNextReceivers(uOSC.Message message, int callCount) { if (callCount > 100) { //無限ループ対策 Debug.LogError("[ExternalReceiver] Too many call(maybe infinite loop)."); return(false); } foreach (var r in receivers) { //インターフェースがあるか if (r != null) { //Chain数を+1して次へ r.MessageDaisyChain(ref message, callCount + 1); } } return(true); }
public void MessageDaisyChain(ref uOSC.Message message, int callCount) { //Startされていない場合無視 if (externalReceiverManager == null || enabled == false || gameObject.activeInHierarchy == false) { return; } if (shutdown) { return; } StatusMessage = "OK"; ProcessMessage(ref message); if (!externalReceiverManager.SendNextReceivers(message, callCount)) { StatusMessage = "Infinite loop detected!"; shutdown = true; } }
private void ProcessMessage(ref uOSC.Message message) { //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない if (message.address == null || message.values == null) { StatusMessage = "Bad message."; return; } //V2.4 背景色情報 if (message.address == "/VMC/Ext/Setting/Color" && (message.values[0] is float) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float)) { backgroundColor = new Color((float)message.values[0], (float)message.values[1], (float)message.values[2], (float)message.values[3]); BackgroundSphereRenderer.materials[0].SetColor(Shader.PropertyToID("_Color"), backgroundColor); } //V2.4 ウィンドウ情報 else if (message.address == "/VMC/Ext/Setting/Win" && (message.values[0] is int) && (message.values[1] is int) && (message.values[2] is int) && (message.values[3] is int)) { IsTopMost = (int)message.values[0] != 0; IsTransparent = (int)message.values[1] != 0; WindowClickThrough = (int)message.values[2] != 0; HideBorder = (int)message.values[3] != 0; windowManager.SetWindowAlwaysTopMost(IsTopMost); windowManager.SetWindowBackgroundTransparent(IsTransparent, backgroundColor); windowManager.SetThroughMouseClick(WindowClickThrough); windowManager.SetWindowBorder(HideBorder); } }
//メッセージ処理本体 private void ProcessMessage(ref uOSC.Message message) { //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない if (message.address == null || message.values == null) { StatusMessage = "Bad message."; return; } //ルート位置がない場合 if (RootPositionTransform == null && Model != null) { //モデル姿勢をルート姿勢にする RootPositionTransform = Model.transform; } //ルート回転がない場合 if (RootRotationTransform == null && Model != null) { //モデル姿勢をルート姿勢にする RootRotationTransform = Model.transform; } //モーションデータ送信可否 if (message.address == "/VMC/Ext/OK" && (message.values[0] is int)) { Available = (int)message.values[0]; if (Available == 0) { StatusMessage = "Waiting for [Load VRM]"; } //V2.5 キャリブレーション状態(長さ3以上) if (message.values.Length >= 3) { if ((message.values[1] is int) && (message.values[2] is int)) { int calibrationState = (int)message.values[1]; int calibrationMode = (int)message.values[2]; //キャリブレーション出来ていないときは隠す if (HideInUncalibrated && Model != null) { Model.SetActive(calibrationState == 3); } //スケール同期をキャリブレーションと連動させる if (SyncCalibrationModeWithScaleOffsetSynchronize) { RootScaleOffsetSynchronize = !(calibrationMode == 0); //通常モードならオフ、MR系ならオン } } } return; } //データ送信時刻 else if (message.address == "/VMC/Ext/T" && (message.values[0] is float)) { time = (float)message.values[0]; PacketCounterInFrame++; //フレーム中のパケットフレーム数を測定 return; } //VRM自動読み込み else if (message.address == "/VMC/Ext/VRM" && (message.values[0] is string) && (message.values[1] is string) ) { string path = (string)message.values[0]; string title = (string)message.values[1]; //前回読み込んだパスと違う場合かつ、読み込みが許可されている場合 if (path != loadedVRMPath && enableAutoLoadVRM == true) { loadedVRMPath = path; loadedVRMName = title; LoadVRM(path); } return; } //オプション文字列 else if (message.address == "/VMC/Ext/Opt" && (message.values[0] is string)) { OptionString = (string)message.values[0]; return; } //モデルがないか、モデル姿勢、ルート姿勢が取得できないなら以降何もしない if (Model == null || Model.transform == null || RootPositionTransform == null || RootRotationTransform == null) { return; } //Root姿勢 if (message.address == "/VMC/Ext/Root/Pos" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { StatusMessage = "OK"; pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; //位置同期 if (RootPositionSynchronize) { RootPositionTransform.localPosition = pos; } //回転同期 if (RootRotationSynchronize) { RootRotationTransform.localRotation = rot; } //スケール同期とオフセット補正(v2.1拡張プロトコルの場合のみ) if (RootScaleOffsetSynchronize && message.values.Length > RootPacketLengthOfScaleAndOffset && (message.values[8] is float) && (message.values[9] is float) && (message.values[10] is float) && (message.values[11] is float) && (message.values[12] is float) && (message.values[13] is float) ) { scale.x = 1.0f / (float)message.values[8]; scale.y = 1.0f / (float)message.values[9]; scale.z = 1.0f / (float)message.values[10]; offset.x = (float)message.values[11]; offset.y = (float)message.values[12]; offset.z = (float)message.values[13]; Model.transform.localScale = scale; RootPositionTransform.localPosition = Vector3.Scale(RootPositionTransform.localPosition, scale); //位置同期が有効な場合のみオフセットを反映する if (RootPositionSynchronize) { offset = Vector3.Scale(offset, scale); RootPositionTransform.localPosition -= offset; } } else { Model.transform.localScale = Vector3.one; } } //ボーン姿勢 else if (message.address == "/VMC/Ext/Bone/Pos" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { string boneName = (string)message.values[0]; pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; //Humanoidボーンに該当するボーンがあるか調べる HumanBodyBones bone; if (HumanBodyBonesTryParse(ref boneName, out bone)) { //あれば位置と回転をキャッシュする if (HumanBodyBonesPositionTable.ContainsKey(bone)) { HumanBodyBonesPositionTable[bone] = pos; } else { HumanBodyBonesPositionTable.Add(bone, pos); } if (HumanBodyBonesRotationTable.ContainsKey(bone)) { HumanBodyBonesRotationTable[bone] = rot; } else { HumanBodyBonesRotationTable.Add(bone, rot); } } //受信と更新のタイミングは切り離した } //ブレンドシェープ同期 else if (message.address == "/VMC/Ext/Blend/Val" && (message.values[0] is string) && (message.values[1] is float) ) { //一旦変数に格納する string key = (string)message.values[0]; float value = (float)message.values[1]; //BlendShapeフィルタが有効なら if (BlendShapeFilterEnable) { //フィルタテーブルに存在するか確認する if (blendShapeFilterDictionaly.ContainsKey(key)) { //存在する場合はフィルタ更新して値として反映する blendShapeFilterDictionaly[key] = (blendShapeFilterDictionaly[key] * BlendShapeFilter) + value * (1.0f - BlendShapeFilter); value = blendShapeFilterDictionaly[key]; } else { //存在しない場合はフィルタに登録する。値はそのまま blendShapeFilterDictionaly.Add(key, value); } } if (BlendShapeSynchronize && blendShapeProxy != null) { //v0.56 BlendShape仕様変更対応 //辞書からKeyに変換し、Key値辞書に値を入れる //通信で受信したキーを小文字に変換して非ケース化 string lowerKey = key.ToLower(); //キーに該当するBSKeyが存在するかチェックする BlendShapeKey bskey; if (StringToBlendShapeKeyDictionary.TryGetValue(lowerKey, out bskey)) { //キーに対して値を登録する BlendShapeToValueDictionary[bskey] = value; //Debug.Log("[lowerKey]->"+ lowerKey+" [bskey]->"+bskey.ToString()+" [value]->"+value); } else { //そんなキーは無い //Debug.LogError("[lowerKey]->" + lowerKey + " is not found"); } } } //ブレンドシェープ適用 else if (message.address == "/VMC/Ext/Blend/Apply") { if (BlendShapeSynchronize && blendShapeProxy != null) { blendShapeProxy.SetValues(BlendShapeToValueDictionary); } } }
//データ受信イベント private void OnDataReceived(uOSC.Message message) { //チェーン数0としてデイジーチェーンを発生させる MessageDaisyChain(ref message, 0); }
//メッセージ処理本体 private void ProcessMessage(ref uOSC.Message message) { //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない if (message.address == null || message.values == null) { StatusMessage = "Bad message."; return; } //ルート位置がない場合 if (RootPositionTransform == null && Model != null) { //モデル姿勢をルート姿勢にする RootPositionTransform = Model.transform; } //ルート回転がない場合 if (RootRotationTransform == null && Model != null) { //モデル姿勢をルート姿勢にする RootRotationTransform = Model.transform; } //モーションデータ送信可否 if (message.address == "/VMC/Ext/OK" && (message.values[0] is int)) { Available = (int)message.values[0]; if (Available == 0) { StatusMessage = "Waiting for [Load VRM]"; } //V2.5 キャリブレーション状態(長さ3以上) if (message.values.Length >= 3) { if ((message.values[1] is int) && (message.values[2] is int)) { int calibrationState = (int)message.values[1]; int calibrationMode = (int)message.values[2]; //キャリブレーション出来ていないときは隠す if (HideInUncalibrated && Model != null) { Model.SetActive(calibrationState == 3); } //スケール同期をキャリブレーションと連動させる if (SyncCalibrationModeWithScaleOffsetSynchronize) { RootScaleOffsetSynchronize = !(calibrationMode == 0); //通常モードならオフ、MR系ならオン } } } return; } //データ送信時刻 else if (message.address == "/VMC/Ext/T" && (message.values[0] is float)) { time = (float)message.values[0]; PacketCounterInFrame++; //フレーム中のパケットフレーム数を測定 return; } //VRM自動読み込み else if (message.address == "/VMC/Ext/VRM" && (message.values[0] is string) && (message.values[1] is string) ) { string path = (string)message.values[0]; string title = (string)message.values[1]; //前回読み込んだパスと違う場合かつ、読み込みが許可されている場合 if (path != loadedVRMPath && enableAutoLoadVRM == true) { loadedVRMPath = path; loadedVRMName = title; LoadVRM(path); } return; } //オプション文字列 else if (message.address == "/VMC/Ext/Opt" && (message.values[0] is string)) { OptionString = (string)message.values[0]; return; } //モデルがないか、モデル姿勢、ルート姿勢が取得できないなら以降何もしない if (Model == null || Model.transform == null || RootPositionTransform == null || RootRotationTransform == null) { return; } //Root姿勢 if (message.address == "/VMC/Ext/Root/Pos" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { StatusMessage = "OK"; pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; //位置同期 if (RootPositionSynchronize) { RootPositionTransform.localPosition = pos; } //回転同期 if (RootRotationSynchronize) { RootRotationTransform.localRotation = rot; } //スケール同期とオフセット補正(v2.1拡張プロトコルの場合のみ) if (RootScaleOffsetSynchronize && message.values.Length > RootPacketLengthOfScaleAndOffset && (message.values[8] is float) && (message.values[9] is float) && (message.values[10] is float) && (message.values[11] is float) && (message.values[12] is float) && (message.values[13] is float) ) { scale.x = 1.0f / (float)message.values[8]; scale.y = 1.0f / (float)message.values[9]; scale.z = 1.0f / (float)message.values[10]; offset.x = (float)message.values[11]; offset.y = (float)message.values[12]; offset.z = (float)message.values[13]; Model.transform.localScale = scale; RootPositionTransform.localPosition = Vector3.Scale(RootPositionTransform.localPosition, scale); //位置同期が有効な場合のみオフセットを反映する if (RootPositionSynchronize) { offset = Vector3.Scale(offset, scale); RootPositionTransform.localPosition -= offset; } } else { Model.transform.localScale = Vector3.one; } } //ボーン姿勢 else if (message.address == "/VMC/Ext/Bone/Pos" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { string boneName = (string)message.values[0]; pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; //Humanoidボーンに該当するボーンがあるか調べる HumanBodyBones bone; if (HumanBodyBonesTryParse(ref boneName, out bone)) { //あれば位置と回転をキャッシュする if (HumanBodyBonesPositionTable.ContainsKey(bone)) { HumanBodyBonesPositionTable[bone] = pos; } else { HumanBodyBonesPositionTable.Add(bone, pos); } if (HumanBodyBonesRotationTable.ContainsKey(bone)) { HumanBodyBonesRotationTable[bone] = rot; } else { HumanBodyBonesRotationTable.Add(bone, rot); } } //受信と更新のタイミングは切り離した } //ブレンドシェープ同期 else if (message.address == "/VMC/Ext/Blend/Val" && (message.values[0] is string) && (message.values[1] is float) ) { if (BlendShapeSynchronize && blendShapeProxy != null) { //v0.55ブレンドシェープ仕様変更対応 //ワークアラウンドが有効か if (VRMVersion.MAJOR >= 0 && VRMVersion.MINOR > 53 && BlendShapeCaseWorkAround) { //まず、小文字変換テーブルを作成する string RawKey = (string)message.values[0]; string CaseSensitiveKey = ""; string NoCaseSensitiveKey = ""; //小文字変換テーブルに存在しなければ if (!blendShapeProxyCaseBuffer.TryGetValue(RawKey, out NoCaseSensitiveKey)) { //小文字変換テーブルに登録する blendShapeProxyCaseBuffer[RawKey] = RawKey.ToLower(); NoCaseSensitiveKey = RawKey.ToLower(); //Debug.Log("Register to CaseBuffer:" + RawKey + " -> " + NoCaseSensitiveKey); } //小文字変換された結果で、まずプリセットに存在するか確認する string presetName = ""; BlendShapePreset preset = BlendShapePreset.Unknown; //プリセット変換テーブルで見つかるか if (BlendShapePresetCaseConverter.TryGetValue(NoCaseSensitiveKey, out presetName)) { //ENUMテーブルで見つかるか if (BlendShapePresetTryParse(ref presetName, out preset)) { //見つかった blendShapeProxy.AccumulateValue(preset, (float)message.values[1]); //Debug.Log("Key Found: " + NoCaseSensitiveKey + "->" + preset.ToString()); } else { //見つからない preset = BlendShapePreset.Unknown; } } else { //見つからない preset = BlendShapePreset.Unknown; } //プリセットに該当するものがなかった場合 if (preset == BlendShapePreset.Unknown) { //小文字変換された結果を使って、ケースセンシティブな文字列に変換する if (blendShapeProxyCaseConverter.TryGetValue(NoCaseSensitiveKey, out CaseSensitiveKey)) { //独自キーとしてUniVRMにわたす blendShapeProxy.AccumulateValue(CaseSensitiveKey, (float)message.values[1]); //Debug.Log("Key Convert: " + NoCaseSensitiveKey + "->" + CaseSensitiveKey); } else { //Debug.Log("Key not found"); } } } else { //通常通り適用する blendShapeProxy.AccumulateValue((string)message.values[0], (float)message.values[1]); } } } //ブレンドシェープ適用 else if (message.address == "/VMC/Ext/Blend/Apply") { if (BlendShapeSynchronize && blendShapeProxy != null) { blendShapeProxy.Apply(); } } }
SteamVR_Utils.RigidTransform SetTransform(ref Vector3 pos, ref Quaternion rot, ref uOSC.Message message) { pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; return(new SteamVR_Utils.RigidTransform(pos, rot)); }
void OnDataReceived(uOSC.Message message) { //有効なとき以外処理しない if (this.isActiveAndEnabled) { //生存チェックのためのパケットカウンタ packets++; if (packets > int.MaxValue / 2) { packets = 0; } //仮想コントローラー V2.3 if (message.address == "/VMC/Ext/Con/Pos" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { string serial = (string)message.values[0]; var rigidTransform = SetTransform(ref pos, ref rot, ref message); lock (LockObject) { if (virtualController.ContainsKey(serial)) { virtualController[serial] = rigidTransform; } else { virtualController.Add(serial, rigidTransform); virtualControllerFiltered.Add(serial, rigidTransform); } } } //仮想トラッカー V2.3 else if ((message.address == "/VMC/Ext/Hmd/Pos" || message.address == "/VMC/Ext/Tra/Pos") && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { string serial = (string)message.values[0]; var rigidTransform = SetTransform(ref pos, ref rot, ref message); lock (LockObject) { if (virtualTracker.ContainsKey(serial)) { virtualTracker[serial] = rigidTransform; } else { virtualTracker.Add(serial, rigidTransform); virtualTrackerFiltered.Add(serial, rigidTransform); } } } //フレーム設定 V2.3 else if (message.address == "/VMC/Ext/Set/Period" && (message.values[0] is int) && (message.values[1] is int) && (message.values[2] is int) && (message.values[3] is int) && (message.values[4] is int) && (message.values[5] is int) ) { externalSender.periodStatus = (int)message.values[0]; externalSender.periodRoot = (int)message.values[1]; externalSender.periodBone = (int)message.values[2]; externalSender.periodBlendShape = (int)message.values[3]; externalSender.periodCamera = (int)message.values[4]; externalSender.periodDevices = (int)message.values[5]; } //Virtual MIDI CC V2.3 else if (message.address == "/VMC/Ext/Midi/CC/Val" && (message.values[0] is int) && (message.values[1] is float) ) { MIDICCWrapper.KnobUpdated(0, (int)message.values[0], (float)message.values[1]); } //Camera Control V2.3 else if (message.address == "/VMC/Ext/Cam" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) && (message.values[8] is float) ) { pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; float fov = (float)message.values[8]; //FreeCameraじゃなかったらFreeCameraにする if (Settings.Current.CameraType != UnityMemoryMappedFile.CameraTypes.Free) { CameraManager.Current.ChangeCamera(UnityMemoryMappedFile.CameraTypes.Free); } //カメラ制御を切る CameraManager.Current.FreeCamera.GetComponent <CameraMouseControl>().enabled = false; //座標とFOVを適用 CameraManager.Current.FreeCamera.transform.localPosition = pos; CameraManager.Current.FreeCamera.transform.localRotation = rot; CameraManager.Current.ControlCamera.fieldOfView = fov; } //ブレンドシェープ同期 else if (message.address == "/VMC/Ext/Blend/Val" && (message.values[0] is string) && (message.values[1] is float) ) { blendShapeBuffer[(string)message.values[0]] = (float)message.values[1]; } //ブレンドシェープ適用 else if (message.address == "/VMC/Ext/Blend/Apply") { if (DisableBlendShapeReception == true) { blendShapeBuffer.Clear(); } faceController.MixPresets(nameof(ExternalReceiverForVMC), blendShapeBuffer.Keys.ToArray(), blendShapeBuffer.Values.ToArray()); blendShapeBuffer.Clear(); }//外部アイトラ V2.3 else if (message.address == "/VMC/Ext/Set/Eye" && (message.values[0] is int) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) ) { bool enable = ((int)message.values[0]) != 0; pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; if (enable) { //ターゲットが存在しなければ作る if (lookTargetOSC == null) { lookTargetOSC = new GameObject(); lookTargetOSC.name = "lookTargetOSC"; } //位置を書き込む if (lookTargetOSC.transform != null) { lookTargetOSC.transform.parent = headTransform; lookTargetOSC.transform.localPosition = pos; } //視線に書き込む if (vrmLookAtHead != null && setFaceApplyAction == false) { faceController.BeforeApply += beforeFaceApply; setFaceApplyAction = true; } } else { //視線を止める if (vrmLookAtHead != null && setFaceApplyAction == true) { faceController.BeforeApply -= beforeFaceApply; setFaceApplyAction = false; } } } //情報要求 V2.4 else if (message.address == "/VMC/Ext/Set/Req") { if (externalSender.isActiveAndEnabled && externalSender.uClient != null) { externalSender.SendPerLowRate(); //即時送信 } } //情報表示 V2.4 else if (message.address == "/VMC/Ext/Set/Res" && (message.values[0] is string)) { statusString = (string)message.values[0]; } //キャリブレーション準備 V2.5 else if (message.address == "/VMC/Ext/Set/Calib/Ready") { if (File.Exists(Settings.Current.VRMPath)) { window.ImportVRM(Settings.Current.VRMPath, true, true, true); } } //キャリブレーション実行 V2.5 else if (message.address == "/VMC/Ext/Set/Calib/Exec" && (message.values[0] is int)) { PipeCommands.CalibrateType calibrateType = PipeCommands.CalibrateType.Default; switch ((int)message.values[0]) { case 0: calibrateType = PipeCommands.CalibrateType.Default; break; case 1: calibrateType = PipeCommands.CalibrateType.FixedHand; break; case 2: calibrateType = PipeCommands.CalibrateType.FixedHandWithGround; break; default: return; //無視 } StartCoroutine(window.Calibrate(calibrateType)); Invoke("EndCalibrate", 2f); } //設定読み込み V2.5 else if (message.address == "/VMC/Ext/Set/Config" && (message.values[0] is string)) { string path = (string)message.values[0]; if (File.Exists(path)) { //なぜか時間がかかる window.LoadSettings(path); } } //スルー情報 V2.6 else if (message.address != null && message.address.StartsWith("/VMC/Thru/")) { //転送する if (externalSender.isActiveAndEnabled && externalSender.uClient != null) { externalSender.uClient.Send(message.address, message.values); } } //Directional Light V2.9 else if (message.address == "/VMC/Ext/Light" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) && (message.values[8] is float) && (message.values[9] is float) && (message.values[10] is float) && (message.values[11] is float) ) { pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; float r = (float)message.values[8]; float g = (float)message.values[9]; float b = (float)message.values[10]; float a = (float)message.values[11]; window.MainDirectionalLight.color = new Color(r, g, b, a); window.MainDirectionalLightTransform.position = pos; window.MainDirectionalLightTransform.rotation = rot; } //ボーン姿勢 else if (message.address == "/VMC/Ext/Bone/Pos" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { string boneName = (string)message.values[0]; pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; //Humanoidボーンに該当するボーンがあるか調べる HumanBodyBones bone; if (HumanBodyBonesTryParse(ref boneName, out bone)) { //あれば位置と回転をキャッシュする if (HumanBodyBonesPositionTable.ContainsKey(bone)) { HumanBodyBonesPositionTable[bone] = pos; } else { HumanBodyBonesPositionTable.Add(bone, pos); } if (HumanBodyBonesRotationTable.ContainsKey(bone)) { HumanBodyBonesRotationTable[bone] = rot; } else { HumanBodyBonesRotationTable.Add(bone, rot); } } //受信と更新のタイミングは切り離した } } }
private void ProcessMessage(ref uOSC.Message message) { //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない if (message.address == null || message.values == null) { StatusMessage = "Bad message."; return; } //コントローラ操作情報 v2.1 if (message.address == "/VMC/Ext/Con" && (message.values[0] is int) && (message.values[1] is string) && (message.values[2] is int) && (message.values[3] is int) && (message.values[4] is int) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { con.active = (int)message.values[0]; con.name = (string)message.values[1]; con.IsLeft = (int)message.values[2]; con.IsTouch = (int)message.values[3]; con.IsAxis = (int)message.values[4]; con.Axis.x = (float)message.values[5]; con.Axis.y = (float)message.values[6]; con.Axis.z = (float)message.values[7]; //イベントを呼び出す if (ControllerInputAction != null) { ControllerInputAction.Invoke(con); } if (con.IsAxis == 0) { if (con.IsLeft == 1) { LastInput = "Left-" + con.name + " = " + con.active; InputDictionary["Left-" + con.name] = (con.active != 0); } else { LastInput = "Right-" + con.name + " = " + con.active; InputDictionary["Right-" + con.name] = (con.active != 0); } } } //キーボード操作情報 v2.1 else if (message.address == "/VMC/Ext/Key" && (message.values[0] is int) && (message.values[1] is string) && (message.values[2] is int) ) { key.active = (int)message.values[0]; key.name = (string)message.values[1]; key.keycode = (int)message.values[2]; //イベントを呼び出す if (KeyInputAction != null) { KeyInputAction.Invoke(key); } LastInput = "Key-" + key.name + " = " + key.active + " (" + key.keycode + ")"; } // v2.2 else if (message.address == "/VMC/Ext/Midi/Note" && (message.values[0] is int) && (message.values[1] is int) && (message.values[2] is int) && (message.values[3] is float) ) { note.active = (int)message.values[0]; note.channel = (int)message.values[1]; note.note = (int)message.values[2]; note.velocity = (float)message.values[3]; //イベントを呼び出す if (MidiNoteInputAction != null) { MidiNoteInputAction.Invoke(note); } LastInput = "Note-" + note.note + " = " + note.active + "/" + note.channel + "/" + note.velocity; InputDictionary["Note-" + note.note] = (note.active != 0); } // v2.2 else if (message.address == "/VMC/Ext/Midi/CC/Val" && (message.values[0] is int) && (message.values[1] is float) ) { ccvalue.knob = (int)message.values[0]; ccvalue.value = (float)message.values[1]; //イベントを呼び出す if (MidiCCValueInputAction != null) { MidiCCValueInputAction.Invoke(ccvalue); } LastInput = "CC Val " + ccvalue.knob + " = " + ccvalue.value; if (ccvalue.knob >= 0 && ccvalue.knob < 128) { CCValuesMonitor[ccvalue.knob] = ccvalue.value; } } // v2.2 else if (message.address == "/VMC/Ext/Midi/CC/Bit" && (message.values[0] is int) && (message.values[1] is int) ) { ccbutton.knob = (int)message.values[0]; ccbutton.active = (int)message.values[1]; //イベントを呼び出す if (MidiCCButtonInputAction != null) { MidiCCButtonInputAction.Invoke(ccbutton); } LastInput = "CC-" + ccbutton.knob + " = " + ccbutton.active; InputDictionary["CC-" + ccbutton.knob] = (ccbutton.active != 0); } }
private void ProcessMessage(ref uOSC.Message message) { //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない if (message.address == null || message.values == null) { StatusMessage = "Bad message."; return; } if (manager.receiver.isLoading) { //ローカル読込中は処理しない return; } if (manager.status.DVRC_AuthState != "AUTHENTICATION_OK") { //ログインしていない場合は受け付けない return; } if (message.address == "/VMC/Ext/Remote" && (message.values[0] is string) && //service (message.values[1] is string) //json ) { string service = message.values[0] as string; string json = message.values[1] as string; if (service == "dmmvrconnect") { var connect = JsonUtility.FromJson <dmmvrconnect>(json); if (user_id != connect.user_id || avatar_id != connect.avatar_id) { user_id = connect.user_id; avatar_id = connect.avatar_id; //メインスレッドに渡す synchronizationContext.Post(async _ => { Debug.Log("Avatar loading from Connect..."); var current_user = await Authentication.Instance.Okami.GetCurrentUserAsync(); if (user_id == current_user.id) { var avatar = await Authentication.Instance.Okami.GetAvatarAsync(current_user.id, avatar_id); Debug.Log(avatar); if (avatar != null) { await manager.LoadAvatarFromDVRSDK(avatar); } else { Debug.LogError("Avatar loading from Connect... Failed!"); } Debug.Log("Load from connect OK"); } else { Debug.Log("User id unmatch"); } }, null); } } else { StatusMessage = "Unknown service: " + service; } } }
private void ProcessMessage(ref uOSC.Message message) { //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない if (message.address == null || message.values == null) { StatusMessage = "Bad message."; return; } if (!RealPosition) { if (message.address == "/VMC/Ext/Hmd/Pos" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; devideUpdate("HMD", (string)message.values[0], pos, rot); //Debug.Log("HMD pos " + (string)message.values[0] + " : " + pos + "/" + rot); } // v2.2 else if (message.address == "/VMC/Ext/Con/Pos" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; devideUpdate("Controller", (string)message.values[0], pos, rot); //Debug.Log("Con pos " + (string)message.values[0] + " : " + pos + "/" + rot); } // v2.2 else if (message.address == "/VMC/Ext/Tra/Pos" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; devideUpdate("Tracker", (string)message.values[0], pos, rot); //Debug.Log("Tra pos " + (string)message.values[0] + " : " + pos + "/" + rot); } } else { if (message.address == "/VMC/Ext/Hmd/Pos/Local" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; devideUpdate("HMD", (string)message.values[0], pos, rot); //Debug.Log("HMD pos " + (string)message.values[0] + " : " + pos + "/" + rot); } // v2.2 else if (message.address == "/VMC/Ext/Con/Pos/Local" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; devideUpdate("Controller", (string)message.values[0], pos, rot); //Debug.Log("Con pos " + (string)message.values[0] + " : " + pos + "/" + rot); } // v2.2 else if (message.address == "/VMC/Ext/Tra/Pos/Local" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; devideUpdate("Tracker", (string)message.values[0], pos, rot); //Debug.Log("Tra pos " + (string)message.values[0] + " : " + pos + "/" + rot); } } }
private void ProcessMessage(ref uOSC.Message message) { //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない if (message.address == null || message.values == null) { StatusMessage = "Bad message."; return; } if (message.address == "/VMC/Ext/OK" && (message.values[0] is int)) { Available = (int)message.values[0]; if (Available == 0) { StatusMessage = "Waiting for [Load VRM]"; } else { StatusMessage = "OK"; } //V2.5 キャリブレーション状態 if ((message.values[1] is int) && (message.values[2] is int)) { calibrationState = (CalibrationState)message.values[1]; calibrationMode = (CalibrationMode)message.values[2]; } } //データ送信時刻 else if (message.address == "/VMC/Ext/T" && (message.values[0] is float)) { time = (float)message.values[0]; } //V2.4 受信情報 else if (message.address == "/VMC/Ext/Rcv" && (message.values[0] is int) && (message.values[1] is int)) { ReceiveEnable = (int)message.values[0] != 0; ReceivePort = (int)message.values[1]; } //V2.4 背景色情報 else if (message.address == "/VMC/Ext/Setting/Color" && (message.values[0] is float) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float)) { backgroundColor = new Color((float)message.values[0], (float)message.values[1], (float)message.values[2], (float)message.values[3]); } //V2.4 ウィンドウ情報 else if (message.address == "/VMC/Ext/Setting/Win" && (message.values[0] is int) && (message.values[1] is int) && (message.values[2] is int) && (message.values[3] is int)) { IsTopMost = (int)message.values[0] != 0; IsTransparent = (int)message.values[1] != 0; WindowClickThrough = (int)message.values[2] != 0; HideBorder = (int)message.values[3] != 0; } //V2.5 読み込み済み設定ファイルパス情報 else if (message.address == "/VMC/Ext/Config" && (message.values[0] is string)) { LoadedConfigPath = (string)message.values[0]; } }
//メッセージ処理本体 private void ProcessMessage(ref uOSC.Message message) { //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない if (message.address == null || message.values == null) { StatusMessage = "Bad message."; return; } //ルート位置がない場合 if (RootPositionTransform == null && Model != null) { //モデル姿勢をルート姿勢にする RootPositionTransform = Model.transform; } //ルート回転がない場合 if (RootRotationTransform == null && Model != null) { //モデル姿勢をルート姿勢にする RootRotationTransform = Model.transform; } //モーションデータ送信可否 if (message.address == "/VMC/Ext/OK" && (message.values[0] is int)) { Available = (int)message.values[0]; if (Available == 0) { StatusMessage = "Waiting for [Load VRM]"; } //V2.5 キャリブレーション状態(長さ3以上) if (message.values.Length >= 3) { if ((message.values[1] is int) && (message.values[2] is int)) { int calibrationState = (int)message.values[1]; int calibrationMode = (int)message.values[2]; //キャリブレーション出来ていないときは隠す if (HideInUncalibrated && Model != null) { Model.SetActive(calibrationState == 3); } //スケール同期をキャリブレーションと連動させる if (SyncCalibrationModeWithScaleOffsetSynchronize) { RootScaleOffsetSynchronize = !(calibrationMode == 0); //通常モードならオフ、MR系ならオン } } } return; } //データ送信時刻 else if (message.address == "/VMC/Ext/T" && (message.values[0] is float)) { time = (float)message.values[0]; PacketCounterInFrame++; //フレーム中のパケットフレーム数を測定 return; } //VRM自動読み込み else if (message.address == "/VMC/Ext/VRM" && (message.values[0] is string) && (message.values[1] is string) ) { string path = (string)message.values[0]; string title = (string)message.values[1]; //前回読み込んだパスと違う場合かつ、読み込みが許可されている場合 if (path != loadedVRMPath && enableAutoLoadVRM == true) { loadedVRMPath = path; loadedVRMName = title; LoadVRM(path); } return; } //オプション文字列 else if (message.address == "/VMC/Ext/Opt" && (message.values[0] is string)) { OptionString = (string)message.values[0]; return; } //モデルがないか、モデル姿勢、ルート姿勢が取得できないなら以降何もしない if (Model == null || Model.transform == null || RootPositionTransform == null || RootRotationTransform == null) { return; } //Root姿勢 if (message.address == "/VMC/Ext/Root/Pos" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { StatusMessage = "OK"; pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; //位置同期 if (RootPositionSynchronize) { RootPositionTransform.localPosition = pos; } //回転同期 if (RootRotationSynchronize) { RootRotationTransform.localRotation = rot; } //スケール同期とオフセット補正(v2.1拡張プロトコルの場合のみ) if (RootScaleOffsetSynchronize && message.values.Length > RootPacketLengthOfScaleAndOffset && (message.values[8] is float) && (message.values[9] is float) && (message.values[10] is float) && (message.values[11] is float) && (message.values[12] is float) && (message.values[13] is float) ) { scale.x = 1.0f / (float)message.values[8]; scale.y = 1.0f / (float)message.values[9]; scale.z = 1.0f / (float)message.values[10]; offset.x = (float)message.values[11]; offset.y = (float)message.values[12]; offset.z = (float)message.values[13]; Model.transform.localScale = scale; RootPositionTransform.localPosition = Vector3.Scale(RootPositionTransform.localPosition, scale); //位置同期が有効な場合のみオフセットを反映する if (RootPositionSynchronize) { offset = Vector3.Scale(offset, scale); RootPositionTransform.localPosition -= offset; } } else { Model.transform.localScale = Vector3.one; scale = Vector3.one; offset = Vector3.zero; } } //ボーン姿勢 else if (message.address == "/VMC/Ext/Bone/Pos" && (message.values[0] is string) && (message.values[1] is float) && (message.values[2] is float) && (message.values[3] is float) && (message.values[4] is float) && (message.values[5] is float) && (message.values[6] is float) && (message.values[7] is float) ) { string boneName = (string)message.values[0]; pos.x = (float)message.values[1]; pos.y = (float)message.values[2]; pos.z = (float)message.values[3]; rot.x = (float)message.values[4]; rot.y = (float)message.values[5]; rot.z = (float)message.values[6]; rot.w = (float)message.values[7]; //Humanoidボーンに該当するボーンがあるか調べる HumanBodyBones bone; if (HumanBodyBonesTryParse(ref boneName, out bone)) { //あれば位置と回転をキャッシュする if (HumanBodyBonesPositionTable.ContainsKey(bone)) { HumanBodyBonesPositionTable[bone] = pos; } else { HumanBodyBonesPositionTable.Add(bone, pos); } if (HumanBodyBonesRotationTable.ContainsKey(bone)) { HumanBodyBonesRotationTable[bone] = rot; } else { HumanBodyBonesRotationTable.Add(bone, rot); } } //受信と更新のタイミングは切り離した } //ブレンドシェープ同期 else if (message.address == "/VMC/Ext/Blend/Val" && (message.values[0] is string) && (message.values[1] is float) ) { if (BlendShapeSynchronize && blendShapeProxy != null) { blendShapeProxy.AccumulateValue((string)message.values[0], (float)message.values[1]); } } //ブレンドシェープ適用 else if (message.address == "/VMC/Ext/Blend/Apply") { if (BlendShapeSynchronize && blendShapeProxy != null) { blendShapeProxy.Apply(); } } }