//低頻度(1秒以上)で送信する情報もの。ただし送信要求が来たら即時発信する public void SendPerLowRate() { //status送信が無効な場合はこれらも送信しない if (periodStatus != 0) { uOSC.Bundle infoBundle = new uOSC.Bundle(uOSC.Timestamp.Immediate); //受信有効情報(Receive enable) //有効可否と、ポート番号の送信 infoBundle.Add(new uOSC.Message("/VMC/Ext/Rcv", (int)(externalReceiver.isActiveAndEnabled ? 1 : 0), externalReceiver.receivePort)); //【イベント送信】DirectionalLight位置・色(DirectionalLight transform & color) if ((window.MainDirectionalLightTransform != null) && (window.MainDirectionalLight.color != null)) { infoBundle.Add(new uOSC.Message("/VMC/Ext/Light", "Light", window.MainDirectionalLightTransform.position.x, window.MainDirectionalLightTransform.position.y, window.MainDirectionalLightTransform.position.z, window.MainDirectionalLightTransform.rotation.x, window.MainDirectionalLightTransform.rotation.y, window.MainDirectionalLightTransform.rotation.z, window.MainDirectionalLightTransform.rotation.w, window.MainDirectionalLight.color.r, window.MainDirectionalLight.color.g, window.MainDirectionalLight.color.b, window.MainDirectionalLight.color.a)); } //【イベント送信】現在の設定 infoBundle.Add(new uOSC.Message("/VMC/Ext/Setting/Color", ControlWPFWindow.CurrentSettings.BackgroundColor.r, ControlWPFWindow.CurrentSettings.BackgroundColor.g, ControlWPFWindow.CurrentSettings.BackgroundColor.b, ControlWPFWindow.CurrentSettings.BackgroundColor.a )); infoBundle.Add(new uOSC.Message("/VMC/Ext/Setting/Win", ControlWPFWindow.CurrentSettings.IsTopMost ? 1 : 0, ControlWPFWindow.CurrentSettings.IsTransparent ? 1 : 0, ControlWPFWindow.CurrentSettings.WindowClickThrough ? 1 : 0, ControlWPFWindow.CurrentSettings.HideBorder ? 1 : 0 )); //送信 uClient?.Send(infoBundle); //【イベント送信】VRM基本情報(VRM information) [独立送信](大きいため単独で送る) if (vrmdata != null) { //ファイルパス, キャラ名 uClient?.Send(new uOSC.Message("/VMC/Ext/VRM", vrmdata.FilePath, vrmdata.Title)); } else if (string.IsNullOrEmpty(remoteName) == false) { uClient?.Send(new uOSC.Message("/VMC/Ext/Remote", remoteName, remoteJson)); } //【イベント送信】設定ファイルパス(Loaded config path) [独立送信](大きいため単独で送る) if (window != null) { //ファイルパス, キャラ名 uClient?.Send(new uOSC.Message("/VMC/Ext/Config", window.lastLoadedConfigPath)); } //【イベント送信】Option文字列(Option string) [独立送信](大きいため単独で送る) uClient?.Send(new uOSC.Message("/VMC/Ext/Opt", optionString)); } }
void LateUpdate() { uClient.Clear(); bundle = new Bundle(); if (Model == null) { Animator[] avatars = FindObjectsOfType <Animator>(); if (avatars.Length > 1) { if (error != null) { error.text = "Error: Please only put one avatar into the scene."; } return; } else if (avatars.Length == 0) { if (error != null) { error.text = "Error: Please put exactly one avatar into the scene."; } return; } if (error != null) { error.text = null; } Model = avatars[0].gameObject; modelPos = Model.transform.position; modelRot = Model.transform.rotation; if (animator) { Transform hips = animator.GetBoneTransform(HumanBodyBones.Hips); if (hips != null) { hipsPos = hips.position; hipsPosLocal = hips.localPosition; hipsRot = hips.rotation; hipsRotLocalInv = Quaternion.Inverse(hips.localRotation); } } } //モデルが更新されたときのみ読み込み if (Model != null && OldModel != Model) { animator = Model.GetComponent <Animator>(); blendShapeProxy = Model.GetComponent <VRMBlendShapeProxy>(); OldModel = Model; } if (Model != null && animator != null && uClient != null) { //Root var RootTransform = Model.transform; Vector3 pos = RootTransform.position; if (RootTransform != null) { SendVMC("/VMC/Ext/Root/Pos", "root", pos.x, pos.y, pos.z, RootTransform.rotation.x, RootTransform.rotation.y, RootTransform.rotation.z, RootTransform.rotation.w); } //Bones foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones))) { if (bone != HumanBodyBones.LastBone) { var Transform = animator.GetBoneTransform(bone); if (Transform != null) { Vector3 position = Transform.localPosition; Quaternion rotation = Transform.localRotation; if (bone == HumanBodyBones.Hips) { // Calculate a positional offset for the hips that includes the movement of transforms between the model root and the hips, but excludes the movement of the root // First move the root back to its original position Vector3 rootPos = Model.transform.position; Model.transform.position = modelPos; // Move the hips to its original absolute position Transform.position = hipsPos; // Get its local position, which will be offset by the cumulative offsets of intermediate transforms Vector3 localHipsOrig = Transform.localPosition; // Restore the positions of hips and root Transform.localPosition = position; Model.transform.position = rootPos; // Subtract the local position offset position -= localHipsOrig - hipsPosLocal; // Do the same thing for rotation // First turn the root back to its original rotation Quaternion rootRot = Model.transform.rotation; Model.transform.rotation = modelRot; // Return the hips to its original absolute rotation Transform.rotation = hipsRot; // Get its local rotation, which will be rotated by the cumulative rotations of intermediate transforms Quaternion localHipsRotOrig = Transform.localRotation; // Restore the rotations of hips and root Transform.localRotation = rotation; Model.transform.rotation = rootRot; // Inverse rotate the local rotation difference rotation = rotation * Quaternion.Inverse(localHipsRotOrig * hipsRotLocalInv); } SendVMC("/VMC/Ext/Bone/Pos", bone.ToString(), position.x, position.y, position.z, rotation.x, rotation.y, rotation.z, rotation.w); } } } //ボーン位置を仮想トラッカーとして送信 SendBoneTransformForTracker(HumanBodyBones.Head, "Head"); SendBoneTransformForTracker(HumanBodyBones.Spine, "Spine"); SendBoneTransformForTracker(HumanBodyBones.LeftHand, "LeftHand"); SendBoneTransformForTracker(HumanBodyBones.RightHand, "RightHand"); SendBoneTransformForTracker(HumanBodyBones.LeftFoot, "LeftFoot"); SendBoneTransformForTracker(HumanBodyBones.RightFoot, "RightFoot"); //BlendShape if (blendShapeProxy != null) { foreach (var b in blendShapeProxy.GetValues()) { SendVMC("/VMC/Ext/Blend/Val", b.Key.ToString(), (float)b.Value ); } SendVMC("/VMC/Ext/Blend/Apply"); } //Available SendVMC("/VMC/Ext/OK", 1); SendVMC("/VMC/Ext/T", Time.time); if (sendBundle) { uClient.Send(bundle); } } else { SendVMC("/VMC/Ext/OK", 0); SendVMC("/VMC/Ext/T", Time.time); if (sendBundle) { uClient.Send(bundle); } } }
//基本的に毎フレーム送信するもの void SendPerFrame() { uOSC.Bundle rootBundle = new uOSC.Bundle(uOSC.Timestamp.Immediate); if (CurrentModel != null && animator != null) { //Root if (vrik == null) { vrik = CurrentModel.GetComponent <VRIK>(); Debug.Log("ExternalSender: VRIK Updated"); } if (frameOfRoot > periodRoot && periodRoot != 0) { frameOfRoot = 1; if (vrik != null) { var RootTransform = vrik.references.root; var offset = handTrackerRoot.transform; if (RootTransform != null && offset != null) { rootBundle.Add(new uOSC.Message("/VMC/Ext/Root/Pos", "root", RootTransform.position.x, RootTransform.position.y, RootTransform.position.z, RootTransform.rotation.x, RootTransform.rotation.y, RootTransform.rotation.z, RootTransform.rotation.w, offset.localScale.x, offset.localScale.y, offset.localScale.z, offset.position.x, offset.position.y, offset.position.z)); } } } frameOfRoot++; //Bones if (frameOfBone > periodBone && periodBone != 0) { frameOfBone = 1; uOSC.Bundle boneBundle = new uOSC.Bundle(uOSC.Timestamp.Immediate); int cnt = 0;//パケット分割カウンタ foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones))) { if (bone == HumanBodyBones.LastBone) { continue; } var Transform = animator.GetBoneTransform(bone); if (Transform != null) { boneBundle.Add(new uOSC.Message("/VMC/Ext/Bone/Pos", bone.ToString(), Transform.localPosition.x, Transform.localPosition.y, Transform.localPosition.z, Transform.localRotation.x, Transform.localRotation.y, Transform.localRotation.z, Transform.localRotation.w)); cnt++; //1200バイトを超えない程度に分割する if (cnt > PACKET_DIV_BONE) { uClient?.Send(boneBundle); boneBundle = new uOSC.Bundle(uOSC.Timestamp.Immediate); cnt = 0; } } } //余ったボーンは雑多な情報と共に送る rootBundle.Add(boneBundle); } frameOfBone++; //Blendsharp if (blendShapeProxy == null) { blendShapeProxy = CurrentModel.GetComponent <VRMBlendShapeProxy>(); Debug.Log("ExternalSender: VRMBlendShapeProxy Updated"); } if (frameOfBlendShape > periodBlendShape && periodBlendShape != 0) { frameOfBlendShape = 1; uOSC.Bundle blendShapeBundle = new uOSC.Bundle(uOSC.Timestamp.Immediate); if (blendShapeProxy != null) { foreach (var b in blendShapeProxy.GetValues()) { blendShapeBundle.Add(new uOSC.Message("/VMC/Ext/Blend/Val", b.Key.ToString(), (float)b.Value )); } blendShapeBundle.Add(new uOSC.Message("/VMC/Ext/Blend/Apply")); } uClient?.Send(blendShapeBundle); } frameOfBlendShape++; } //Camera if (frameOfCamera > periodCamera && periodCamera != 0) { frameOfCamera = 1; if (currentCamera != null) { rootBundle.Add(new uOSC.Message("/VMC/Ext/Cam", "Camera", currentCamera.transform.position.x, currentCamera.transform.position.y, currentCamera.transform.position.z, currentCamera.transform.rotation.x, currentCamera.transform.rotation.y, currentCamera.transform.rotation.z, currentCamera.transform.rotation.w, currentCamera.fieldOfView)); } } frameOfCamera++; //TrackerSend if (frameOfDevices > periodDevices && periodDevices != 0) { frameOfDevices = 1; rootBundle.Add(new uOSC.Message("/VMC/Ext/Hmd/Pos", trackerHandler.HMDObject.name, trackerHandler.HMDObject.transform.position.x, trackerHandler.HMDObject.transform.position.y, trackerHandler.HMDObject.transform.position.z, trackerHandler.HMDObject.transform.rotation.x, trackerHandler.HMDObject.transform.rotation.y, trackerHandler.HMDObject.transform.rotation.z, trackerHandler.HMDObject.transform.rotation.w)); rootBundle.Add(new uOSC.Message("/VMC/Ext/Hmd/Pos/Local", trackerHandler.HMDObject.name, trackerHandler.HMDObject.transform.localPosition.x, trackerHandler.HMDObject.transform.localPosition.y, trackerHandler.HMDObject.transform.localPosition.z, trackerHandler.HMDObject.transform.localRotation.x, trackerHandler.HMDObject.transform.localRotation.y, trackerHandler.HMDObject.transform.localRotation.z, trackerHandler.HMDObject.transform.localRotation.w)); foreach (var c in trackerHandler.Controllers) { rootBundle.Add(new uOSC.Message("/VMC/Ext/Con/Pos", c.name, c.transform.position.x, c.transform.position.y, c.transform.position.z, c.transform.rotation.x, c.transform.rotation.y, c.transform.rotation.z, c.transform.rotation.w)); rootBundle.Add(new uOSC.Message("/VMC/Ext/Con/Pos/Local", c.name, c.transform.localPosition.x, c.transform.localPosition.y, c.transform.localPosition.z, c.transform.localRotation.x, c.transform.localRotation.y, c.transform.localRotation.z, c.transform.localRotation.w)); } foreach (var c in trackerHandler.Trackers) { rootBundle.Add(new uOSC.Message("/VMC/Ext/Tra/Pos", c.name, c.transform.position.x, c.transform.position.y, c.transform.position.z, c.transform.rotation.x, c.transform.rotation.y, c.transform.rotation.z, c.transform.rotation.w)); rootBundle.Add(new uOSC.Message("/VMC/Ext/Tra/Pos/Local", c.name, c.transform.localPosition.x, c.transform.localPosition.y, c.transform.localPosition.z, c.transform.localRotation.x, c.transform.localRotation.y, c.transform.localRotation.z, c.transform.localRotation.w)); } } frameOfDevices++; //Status if (frameOfStatus > periodStatus && periodStatus != 0) { frameOfStatus = 1; int available = 0; if (CurrentModel != null && animator != null) { //Available available = 1; } if (window != null) { rootBundle.Add(new uOSC.Message("/VMC/Ext/OK", (int)available, (int)window.calibrationState, (int)window.lastCalibrateType)); } rootBundle.Add(new uOSC.Message("/VMC/Ext/T", Time.time)); } frameOfStatus++; uClient?.Send(rootBundle); //---End of frame--- }