private void OnEnable() { edittingAvatar = new VRCAvatar(); editorFolderPath = Path.GetDirectoryName( AssetDatabase.GetAssetPath(MonoScript.FromScriptableObject(this))); editorFolderPath = editorFolderPath.Substring(0, editorFolderPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); saveFolder = "Assets/"; licenseText = FileUtility.GetFileTexts(editorFolderPath + LICENSE_FILE_NAME); readmeText = FileUtility.GetFileTexts(editorFolderPath + README_FILE_NAME); usingSoftwareLicenseText = FileUtility.GetFileTexts(editorFolderPath + USING_SOFTWARE_FILE_NAME); avatarMonitorGUI = ScriptableObject.CreateInstance <AvatarMonitorGUI>(); animationsGUI = ScriptableObject.CreateInstance <AnimationsGUI>(); avatarInfoGUI = ScriptableObject.CreateInstance <AvatarInfoGUI>(); faceEmotionGUI = ScriptableObject.CreateInstance <FaceEmotionGUI>(); probeAnchorGUI = ScriptableObject.CreateInstance <ProbeAnchorGUI>(); meshBoundsGUI = ScriptableObject.CreateInstance <MeshBoundsGUI>(); shaderGUI = ScriptableObject.CreateInstance <ShaderGUI>(); toolGUIs.Add(ToolFunc.AvatarInfo, avatarInfoGUI); toolGUIs.Add(ToolFunc.FaceEmotion, faceEmotionGUI); toolGUIs.Add(ToolFunc.ProbeAnchor, probeAnchorGUI); toolGUIs.Add(ToolFunc.Bounds, meshBoundsGUI); toolGUIs.Add(ToolFunc.Shader, shaderGUI); avatarMonitorGUI.Initialize(CurrentTool); animationsGUI.Initialize(edittingAvatar, originalAvatar, saveFolder, this, faceEmotionGUI); avatarInfoGUI.Initialize(originalAvatar, edittingAvatar, avatarMonitorGUI); probeAnchorGUI.Initialize(originalAvatar); selectedToolGUI = avatarInfoGUI; CurrentTool = ToolFunc.AvatarInfo; (layoutType, language) = EditorSetting.instance.LoadSettingDataFromScriptableObject( editorFolderPath, language, avatarMonitorGUI, faceEmotionGUI); // Windowを開いたときにオブジェクトが選択されていればそれをアバターとして設定する if (Selection.gameObjects.Length == 1) { var selectionTransform = Selection.gameObjects.Single().transform; while (selectionTransform != null) { targetAvatarDescriptor = selectionTransform.GetComponent <VRC_AvatarDescriptor>(); if (targetAvatarDescriptor != null) { OnChangedAvatar(); break; } selectionTransform = selectionTransform.parent; } } SceneView.onSceneGUIDelegate += OnSceneGUI; }
/// <summary> /// アバターを写す用のカメラを設定する /// </summary> public VRCAvatar SetAvatarPreview(VRC_AvatarDescriptor descriptor) { var avatar = avatarMonitorField.AddAvatar(descriptor); avatarMonitorField.SetAvatarCamBgColor(monitorBgColor); this.avatar = avatar; return(avatar); }
void OnEnable() { if (avatar == null) { VRCSDK2.VRC_AvatarDescriptor validDescriptor = GetValidDescriptor(); if (validDescriptor != null) { InitForAvatar(validDescriptor); } } }
void InitForAvatar(VRCSDK2.VRC_AvatarDescriptor descriptor) { avatar = descriptor.gameObject; avatarDescriptor = descriptor; avatarAnimator = avatar.GetComponent <Animator>(); if (avatarAnimator == null) { avatarAnimator = avatar.AddComponent <Animator>(); } SetupOverride(ControllerType.STANDING); }
private void setupController() { AnimatorOverrideController o = new AnimatorOverrideController(); o.runtimeAnimatorController = AssetDatabase.LoadAssetAtPath <RuntimeAnimatorController>(TEMPLATE_PATH); AssetDatabase.CreateAsset(o, path + "/Minecraft.overrideController"); VRCSDK2.VRC_AvatarDescriptor descriptor = avatar.gameObject.GetComponent <VRCSDK2.VRC_AvatarDescriptor>(); descriptor.CustomSittingAnims = o; descriptor.CustomStandingAnims = o; Selection.activeObject = o; EditorGUIUtility.PingObject(o); }
void OnGUIAvatar(VRCSDK2.VRC_AvatarDescriptor avatar) { EditorGUILayout.InspectorTitlebar(avatar.gameObject.activeInHierarchy, avatar.gameObject); GUI.enabled = (GUIErrors.Count == 0 && checkedForIssues) || (APIUser.CurrentUser.developerType.HasValue && APIUser.CurrentUser.developerType.Value == APIUser.DeveloperType.Internal); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Build & Publish")) { VRC_SdkBuilder.shouldBuildUnityPackage = VRC.AccountEditorWindow.FutureProofPublishEnabled; VRC_SdkBuilder.ExportAndUploadAvatarBlueprint(avatar.gameObject); } EditorGUILayout.EndHorizontal(); GUI.enabled = true; OnGUIShowIssues(avatar); }
private void Awake() { Descriptor = m_Avatar.GetComponent <VRCSDK2.VRC_AvatarDescriptor>(); Primary = GameObject.Instantiate(m_Avatar, transform); Shadow = GameObject.Instantiate(m_Avatar, transform); m_CameraRig = GameObject.FindWithTag("MainCamera"); Primary.name = m_Avatar.name + " (Primary)"; Primary.SetActive(true); Primary.layer = LayerMask.NameToLayer("PlayerLocal"); Shadow.name = m_Avatar.name + " (Shadow)"; Shadow.SetActive(true); SetupPrimary(); SetupShadow(); SetupCamera(); }
void OnGUIAvatarSettings_KawaAltApiAvatarInfo(VRCSDK2.VRC_AvatarDescriptor avatar) { var a = avatar.apiAvatar as ApiAvatar; if (a != null) { var short_name = Kawa_CutTooLongString(a.name, 100); var short_desc = Kawa_CutTooLongString(a.description, 1000); EditorGUILayout.LabelField(short_name, titleGuiStyle); GUILayout.Label(short_desc, infoGuiStyle); EditorGUILayout.Space(); EditorGUILayout.LabelField("Version: " + a.version.ToString()); EditorGUILayout.LabelField("Unity Version: " + a.unityVersion); EditorGUILayout.LabelField("Created At: " + a.created_at.ToString("u")); EditorGUILayout.LabelField("Updated At: " + a.updated_at.ToString("u")); EditorGUILayout.LabelField("Supports Android: " + Kawa_SupportsAndroid(a.supportedPlatforms)); EditorGUILayout.LabelField("Supports Windows:" + Kawa_SupportsWindows(a.supportedPlatforms)); EditorGUILayout.Space(); EditorGUILayout.LabelField("Release: " + a.releaseStatus); EditorGUILayout.Space(); var tags = a.tags ?? new List <string>() { }; //var tags_a = tags.Where(x => x.StartsWith("author_tag_")).Select(x => x.Substring(11, x.Length - 11)).ToArray(); //var tags_na = tags.Where(x => !x.StartsWith("author_tag_")).ToArray(); var tags_na = tags; EditorGUILayout.LabelField("Tags: " + string.Join(", ", tags_na.ToArray()), EditorStyles.wordWrappedLabel); //EditorGUILayout.LabelField("Author Tags: " + string.Join(", ", tags_a.ToArray()), EditorStyles.wordWrappedLabel); } else { EditorGUILayout.LabelField(avatar.gameObject.name, titleGuiStyle); EditorGUILayout.LabelField("( Unpublished VRChat Avatar )"); } }
private void SetupOverrides() { VRCSDK2.VRC_AvatarDescriptor descriptor = avatar.gameObject.GetComponent <VRCSDK2.VRC_AvatarDescriptor>(); if (descriptor.CustomStandingAnims == null) { AnimatorOverrideController o = new AnimatorOverrideController(); o.runtimeAnimatorController = AssetDatabase.LoadAssetAtPath <RuntimeAnimatorController>(TEMPLATE_PATH); AssetDatabase.CreateAsset(o, exportPath + "Overrides.overrideController"); descriptor.CustomSittingAnims = o; descriptor.CustomStandingAnims = o; } else { Debug.Log("custom override set on CustomStandingAnims, Skipping override controller generation"); } Selection.activeObject = descriptor.CustomStandingAnims; EditorGUIUtility.PingObject(descriptor.CustomStandingAnims); }
static string ShowBuilder_KawaAltAvatar_AvatarSelector_GetEntryName(VRCSDK2.VRC_AvatarDescriptor avatar) { string entry_name = ""; var t = avatar.gameObject.transform; while (t != null) { entry_name = t.gameObject.name + " / " + entry_name; t = t.parent; } entry_name = avatar.gameObject.scene.name + " / " + entry_name; entry_name = entry_name.Trim(); if (entry_name.EndsWith("/")) { entry_name = entry_name.Substring(0, entry_name.Length - 1); } entry_name = entry_name.Trim(); return(entry_name); }
public VRCAvatar AddAvatar(VRC_AvatarDescriptor descriptor) { if (avatarObj != null) { UnityEngine.Object.DestroyImmediate(avatarObj); } var newAvatarObj = GameObject.Instantiate(descriptor.gameObject); newAvatarObj.name = descriptor.gameObject.name; newAvatarObj.transform.position = Vector3.zero; newAvatarObj.transform.rotation = Quaternion.identity; newAvatarObj.SetActive(true); AddGameObject(newAvatarObj); this.avatarObj = newAvatarObj; newAvatarObj.transform.position = new Vector3(0, 0, 0); this.descriptor = newAvatarObj.GetComponent <VRC_AvatarDescriptor>(); avatar = new VRCAvatar(this.descriptor); ResetCameraTransform(); return(avatar); }
bool AnalyzeIK(VRCSDK2.VRC_AvatarDescriptor ad, GameObject avObj, Animator anim) { bool hasHead = false; bool hasFeet = false; bool hasHands = false; bool hasThreeFingers = false; //bool hasToes = false; bool correctSpineHierarchy = false; bool correctArmHierarchy = false; bool correctLegHierarchy = false; bool status = true; Transform head = anim.GetBoneTransform(HumanBodyBones.Head); Transform lfoot = anim.GetBoneTransform(HumanBodyBones.LeftFoot); Transform rfoot = anim.GetBoneTransform(HumanBodyBones.RightFoot); Transform lhand = anim.GetBoneTransform(HumanBodyBones.LeftHand); Transform rhand = anim.GetBoneTransform(HumanBodyBones.RightHand); hasHead = null != head; hasFeet = (null != lfoot && null != rfoot); hasHands = (null != lhand && null != rhand); if (!hasHead || !hasFeet || !hasHands) { OnGUIError(ad, "Humanoid avatar must have head, hands and feet bones mapped."); return(false); } Transform lthumb = anim.GetBoneTransform(HumanBodyBones.LeftThumbProximal); Transform lindex = anim.GetBoneTransform(HumanBodyBones.LeftIndexProximal); Transform lmiddle = anim.GetBoneTransform(HumanBodyBones.LeftMiddleProximal); Transform rthumb = anim.GetBoneTransform(HumanBodyBones.RightThumbProximal); Transform rindex = anim.GetBoneTransform(HumanBodyBones.RightIndexProximal); Transform rmiddle = anim.GetBoneTransform(HumanBodyBones.RightMiddleProximal); hasThreeFingers = null != lthumb && null != lindex && null != lmiddle && null != rthumb && null != rindex && null != rmiddle; if (!hasThreeFingers) { // although its only a warning, we return here because the rest // of the analysis is for VRIK OnGUIWarning(ad, "Thumb, Index, and Middle finger bones are not mapped, Full-Body IK will be disabled."); status = false; } if (anim.GetBoneTransform(HumanBodyBones.UpperChest) != null) { OnGUIError(ad, "Your rig has the UPPERCHEST mapped in the Humanoid Rig. This will cause problems with IK."); return(false); } Transform pelvis = anim.GetBoneTransform(HumanBodyBones.Hips); Transform chest = anim.GetBoneTransform(HumanBodyBones.Chest); Transform torso = anim.GetBoneTransform(HumanBodyBones.Spine); Transform neck = anim.GetBoneTransform(HumanBodyBones.Neck); Transform lclav = anim.GetBoneTransform(HumanBodyBones.LeftShoulder); Transform rclav = anim.GetBoneTransform(HumanBodyBones.RightShoulder); if (null == neck || null == lclav || null == rclav || null == pelvis || null == torso || null == chest) { OnGUIError(ad, "Spine hierarchy missing elements, make sure that Pelvis, Spine, Chest, Neck and Shoulders are mapped."); return(false); } correctSpineHierarchy = lclav.parent == chest && rclav.parent == chest && neck.parent == chest; if (!correctSpineHierarchy) { OnGUIError(ad, "Spine hierarchy incorrect. Make sure that the parent of both Shoulders and the Neck is the Chest."); return(false); } Transform lshoulder = anim.GetBoneTransform(HumanBodyBones.LeftUpperArm); Transform lelbow = anim.GetBoneTransform(HumanBodyBones.LeftLowerArm); Transform rshoulder = anim.GetBoneTransform(HumanBodyBones.RightUpperArm); Transform relbow = anim.GetBoneTransform(HumanBodyBones.RightLowerArm); correctArmHierarchy = lshoulder.GetChild(0) == lelbow && lelbow.GetChild(0) == lhand && rshoulder.GetChild(0) == relbow && relbow.GetChild(0) == rhand; if (!correctArmHierarchy) { OnGUIWarning(ad, "LowerArm is not first child of UpperArm or Hand is not first child of LowerArm: you may have problems with Forearm rotations."); status = false; } Transform lhip = anim.GetBoneTransform(HumanBodyBones.LeftUpperLeg); Transform lknee = anim.GetBoneTransform(HumanBodyBones.LeftLowerLeg); Transform rhip = anim.GetBoneTransform(HumanBodyBones.RightUpperLeg); Transform rknee = anim.GetBoneTransform(HumanBodyBones.RightLowerLeg); correctLegHierarchy = lhip.GetChild(0) == lknee && lknee.GetChild(0) == lfoot && rhip.GetChild(0) == rknee && rknee.GetChild(0) == rfoot; if (!correctLegHierarchy) { OnGUIWarning(ad, "LowerLeg is not first child of UpperLeg or Foot is not first child of LowerLeg: you may have problems with Shin rotations."); status = false; } if (!(IsAncestor(pelvis, rfoot) && IsAncestor(pelvis, lfoot) && IsAncestor(pelvis, lhand) || IsAncestor(pelvis, rhand) || IsAncestor(pelvis, lhand))) { OnGUIWarning(ad, "This avatar has a split heirarchy (Hips bone is not the ancestor of all humanoid bones). IK may not work correctly."); status = false; } // if thigh bone rotations diverge from 180 from hip bone rotations, full-body tracking/ik does not work well Vector3 hipLocalUp = pelvis.InverseTransformVector(Vector3.up); Vector3 legLDir = lhip.TransformVector(hipLocalUp); Vector3 legRDir = rhip.TransformVector(hipLocalUp); float angL = Vector3.Angle(Vector3.up, legLDir); float angR = Vector3.Angle(Vector3.up, legRDir); if (angL < 175f || angR < 175f) { string angle = string.Format("{0:F1}", Mathf.Min(angL, angR)); OnGUIWarning(ad, "The angle between pelvis and thigh bones should be close to 180 degrees (this avatar's angle is " + angle + "). Your avatar may not work well with full-body IK and Tracking."); status = false; } return(status); }
// Attempts to remap a mecanim rig so that the upper chest bone // is blank, by moving the upper chest bone to chest and rebuilding // CURRENTLY DOES NOT WORK! void UpperChestFix(VRCSDK2.VRC_AvatarDescriptor ad, GameObject avObj, Animator anim) { // if upper chest was mapped we need to reconfigure rig // by moving upper chest to chest Transform pelvis = anim.GetBoneTransform(HumanBodyBones.Hips); Transform upchest = anim.GetBoneTransform(HumanBodyBones.UpperChest); Transform chest = anim.GetBoneTransform(HumanBodyBones.Chest); Transform torso = anim.GetBoneTransform(HumanBodyBones.Spine); Avatar origAvatar = anim.avatar; if (upchest != null) { // get every child transform of the animator Transform[] allBones = anim.GetComponentsInChildren <Transform>(); // get a list of the extra spine bones between spine and pelvis List <Transform> extras = FindBonesBetween(torso, pelvis); HumanDescription desc = new HumanDescription(); desc.upperArmTwist = 0.5f; desc.lowerArmTwist = 0.5f; desc.upperLegTwist = 0.5f; desc.lowerLegTwist = 0.5f; desc.armStretch = 0.05f; desc.legStretch = 0.05f; desc.feetSpacing = 0.0f; List <HumanBone> hbList = new List <HumanBone>(); List <SkeletonBone> sbList = new List <SkeletonBone>(); HumanBodyBones[] hbbArray = (HumanBodyBones[])System.Enum.GetValues(typeof(HumanBodyBones)); Dictionary <Transform, string> hbbDict = new Dictionary <Transform, string>(); for (int i = 0; i < hbbArray.Length; i++) { Transform t = anim.GetBoneTransform(hbbArray[i]); string n = hbbArray[i].ToString(); if (t != null && n != "LastBone") { hbbDict[t] = n; //Debug.LogError("Dictionary Added:"+hbbArray[i].ToString()); } } foreach (Transform bt in allBones) { // map the human bones if (hbbDict.Keys.Contains(bt)) { string hbName = hbbDict[bt]; //Debug.LogError("Processing: "+hbName); if (hbName != "Spine" && bt != null && !extras.Contains(bt)) { if (bt == upchest) { hbName = "Chest"; } else if (bt == chest) { hbName = "Spine"; } HumanBone hb = new HumanBone(); hb.boneName = bt.name; hb.humanName = hbName; //Debug.Log("Mapped human bone:" + hb.humanName + " to " + hb.boneName); hbList.Add(hb); } else { //Debug.LogError("Skipped:" + hbbDict[bt]); } } if (bt != null) { // THESE POSITIONS/ROTATIONS MUST BE FOR TPOSE !!! SkeletonBone sb = new SkeletonBone(); sb.name = bt.name; sb.position = bt.position; sb.rotation = bt.rotation; sb.scale = bt.localScale; sbList.Add(sb); } } // add any root bones above hip Transform root = pelvis.parent; while (root != null && root != anim.transform) { // THESE POSITIONS/ROTATIONS MUST BE FOR TPOSE !!! SkeletonBone sb = new SkeletonBone(); sb.name = root.name; sb.position = root.position; sb.rotation = root.rotation; sb.scale = root.localScale; sbList.Add(sb); root = root.parent; } desc.human = hbList.ToArray(); desc.skeleton = sbList.ToArray(); anim.avatar = AvatarBuilder.BuildHumanAvatar(avObj, desc); if (anim.avatar.isValid && anim.avatar.isHuman) { anim.avatar.name = "{ADJUSTED}" + origAvatar.name; // shift all the bone mappings torso = chest; chest = upchest; upchest = null; } else { OnGUIError(ad, "Automatic rig adjustment on " + origAvatar.name + " failed. You will need to manually configure the humanoid rig. Make sure the UpperChest slot is empty."); anim.avatar = origAvatar; return; } } if (anim.avatar.name.StartsWith("{ADJUSTED}")) { OnGUIWarning(ad, "Your rig has the UPPERCHEST mapped in the Humanoid Rig, and was automatically corrected " + "to use the CHEST instead. If you run into issues we recommend leaving the " + "UPPERCHEST blank and mapping your top spine bone to the CHEST."); } }
void OnGUIAvatarCheck(VRCSDK2.VRC_AvatarDescriptor avatar) { AvatarPerformanceStats perfStats = AvatarPerformance.CalculatePerformanceStats(avatar.Name, avatar.gameObject); OnGUIPerformanceInfo(avatar, perfStats, AvatarPerformanceCategory.Overall); OnGUIPerformanceInfo(avatar, perfStats, AvatarPerformanceCategory.PolyCount); OnGUIPerformanceInfo(avatar, perfStats, AvatarPerformanceCategory.AABB); var eventHandler = avatar.GetComponentInChildren <VRCSDK2.VRC_EventHandler>(); if (eventHandler != null) { OnGUIError(avatar, "This avatar contains an EventHandler, which is not currently supported in VRChat."); } if (avatar.lipSync == VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.VisemeBlendShape && avatar.VisemeSkinnedMesh == null) { OnGUIError(avatar, "This avatar uses Visemes but the Face Mesh is not specified."); } var anim = avatar.GetComponent <Animator>(); if (anim == null) { OnGUIWarning(avatar, "This avatar does not contain an animator, and will not animate in VRChat."); } else if (anim.isHuman == false) { OnGUIWarning(avatar, "This avatar is not imported as a humanoid rig and will not play VRChat's provided animation set."); } else if (avatar.gameObject.activeInHierarchy == false) { OnGUIError(avatar, "Your avatar is disabled in the scene hierarchy!"); } else { Transform foot = anim.GetBoneTransform(HumanBodyBones.LeftFoot); Transform shoulder = anim.GetBoneTransform(HumanBodyBones.LeftUpperArm); if (foot == null) { OnGUIError(avatar, "Your avatar is humanoid, but it's feet aren't specified!"); } if (shoulder == null) { OnGUIError(avatar, "Your avatar is humanoid, but it's upper arms aren't specified!"); } if (foot != null && shoulder != null) { Vector3 footPos = foot.position - avatar.transform.position; if (footPos.y < 0) { OnGUIWarning(avatar, "Avatar feet are beneath the avatar's origin (the floor). That's probably not what you want."); } Vector3 shoulderPosition = shoulder.position - avatar.transform.position; if (shoulderPosition.y < 0.2f) { OnGUIError(avatar, "This avatar is too short. The minimum is 20cm shoulder height."); } else if (shoulderPosition.y < 1.0f) { OnGUIWarning(avatar, "This avatar is short. This is probably shorter than you want."); } else if (shoulderPosition.y > 5.0f) { OnGUIWarning(avatar, "This avatar is too tall. The maximum is 5m shoulder height."); } else if (shoulderPosition.y > 2.5f) { OnGUIWarning(avatar, "This avatar is tall. This is probably taller than you want."); } } if (AnalyzeIK(avatar, avatar.gameObject, anim) == false) { OnGUILink(avatar, "See Avatar Rig Requirements for more information.", kAvatarRigRequirementsURL); } } IEnumerable <Component> componentsToRemove = VRCSDK2.AvatarValidation.FindIllegalComponents(avatar.gameObject); HashSet <string> componentsToRemoveNames = new HashSet <string>(); foreach (Component c in componentsToRemove) { if (componentsToRemoveNames.Contains(c.GetType().Name) == false) { componentsToRemoveNames.Add(c.GetType().Name); } } if (componentsToRemoveNames.Count > 0) { OnGUIError(avatar, "The following component types are found on the Avatar and will be removed by the client: " + string.Join(", ", componentsToRemoveNames.ToArray())); } if (VRCSDK2.AvatarValidation.EnforceAudioSourceLimits(avatar.gameObject).Count > 0) { OnGUIWarning(avatar, "Audio sources found on Avatar, they will be adjusted to safe limits, if necessary."); } if (VRCSDK2.AvatarValidation.EnforceAvatarStationLimits(avatar.gameObject).Count > 0) { OnGUIWarning(avatar, "Stations found on Avatar, they will be adjusted to safe limits, if necessary."); } if (avatar.gameObject.GetComponentInChildren <Camera>() != null) { OnGUIWarning(avatar, "Cameras are removed from non-local avatars at runtime."); } foreach (AvatarPerformanceCategory perfCategory in System.Enum.GetValues(typeof(AvatarPerformanceCategory))) { if (perfCategory == AvatarPerformanceCategory.Overall || perfCategory == AvatarPerformanceCategory.PolyCount || perfCategory == AvatarPerformanceCategory.AABB || perfCategory == AvatarPerformanceCategory.AvatarPerformanceCategoryCount) { continue; } OnGUIPerformanceInfo(avatar, perfStats, perfCategory); } OnGUILink(avatar, "Avatar Optimization Tips", kAvatarOptimizationTipsURL); }
public override void OnInspectorGUI() { if (avatarDescriptor == null) { avatarDescriptor = (VRCSDK2.VRC_AvatarDescriptor)target; } if (pipelineManager == null) { pipelineManager = avatarDescriptor.GetComponent <VRC.Core.PipelineManager>(); if (pipelineManager == null) { avatarDescriptor.gameObject.AddComponent <VRC.Core.PipelineManager>(); } } // DrawDefaultInspector(); if (VRCSdkControlPanel.window != null) { if (GUILayout.Button("Select this avatar in the SDK control panel")) { VRCSdkControlPanelAvatarBuilder.SelectAvatar(avatarDescriptor); } } avatarDescriptor.ViewPosition = EditorGUILayout.Vector3Field("View Position", avatarDescriptor.ViewPosition); //avatarDescriptor.Name = EditorGUILayout.TextField("Avatar Name", avatarDescriptor.Name); avatarDescriptor.Animations = (VRCSDK2.VRC_AvatarDescriptor.AnimationSet)EditorGUILayout.EnumPopup("Default Animation Set", avatarDescriptor.Animations); avatarDescriptor.CustomStandingAnims = (AnimatorOverrideController)EditorGUILayout.ObjectField("Custom Standing Anims", avatarDescriptor.CustomStandingAnims, typeof(AnimatorOverrideController), true, null); avatarDescriptor.CustomSittingAnims = (AnimatorOverrideController)EditorGUILayout.ObjectField("Custom Sitting Anims", avatarDescriptor.CustomSittingAnims, typeof(AnimatorOverrideController), true, null); avatarDescriptor.ScaleIPD = EditorGUILayout.Toggle("Scale IPD", avatarDescriptor.ScaleIPD); avatarDescriptor.lipSync = (VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle)EditorGUILayout.EnumPopup("Lip Sync", avatarDescriptor.lipSync); switch (avatarDescriptor.lipSync) { case VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.Default: if (GUILayout.Button("Auto Detect!")) { AutoDetectLipSync(); } break; case VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.JawFlapBlendShape: avatarDescriptor.VisemeSkinnedMesh = (SkinnedMeshRenderer)EditorGUILayout.ObjectField("Face Mesh", avatarDescriptor.VisemeSkinnedMesh, typeof(SkinnedMeshRenderer), true); if (avatarDescriptor.VisemeSkinnedMesh != null) { DetermineBlendShapeNames(); int current = -1; for (int b = 0; b < blendShapeNames.Count; ++b) { if (avatarDescriptor.MouthOpenBlendShapeName == blendShapeNames[b]) { current = b; } } string title = "Jaw Flap Blend Shape"; int next = EditorGUILayout.Popup(title, current, blendShapeNames.ToArray()); if (next >= 0) { avatarDescriptor.MouthOpenBlendShapeName = blendShapeNames[next]; } } break; case VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.JawFlapBone: avatarDescriptor.lipSyncJawBone = (Transform)EditorGUILayout.ObjectField("Jaw Bone", avatarDescriptor.lipSyncJawBone, typeof(Transform), true); break; case VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.VisemeBlendShape: SkinnedMeshRenderer prev = avatarDescriptor.VisemeSkinnedMesh; avatarDescriptor.VisemeSkinnedMesh = (SkinnedMeshRenderer)EditorGUILayout.ObjectField("Face Mesh", avatarDescriptor.VisemeSkinnedMesh, typeof(SkinnedMeshRenderer), true); if (avatarDescriptor.VisemeSkinnedMesh != prev) { shouldRefreshVisemes = true; } if (avatarDescriptor.VisemeSkinnedMesh != null) { DetermineBlendShapeNames(); if (avatarDescriptor.VisemeBlendShapes == null || avatarDescriptor.VisemeBlendShapes.Length != (int)VRCSDK2.VRC_AvatarDescriptor.Viseme.Count) { avatarDescriptor.VisemeBlendShapes = new string[(int)VRCSDK2.VRC_AvatarDescriptor.Viseme.Count]; } for (int i = 0; i < (int)VRCSDK2.VRC_AvatarDescriptor.Viseme.Count; ++i) { int current = -1; for (int b = 0; b < blendShapeNames.Count; ++b) { if (avatarDescriptor.VisemeBlendShapes[i] == blendShapeNames[b]) { current = b; } } string title = "Viseme: " + ((VRCSDK2.VRC_AvatarDescriptor.Viseme)i).ToString(); int next = EditorGUILayout.Popup(title, current, blendShapeNames.ToArray()); if (next >= 0) { avatarDescriptor.VisemeBlendShapes[i] = blendShapeNames[next]; } } if (shouldRefreshVisemes) { AutoDetectVisemes(); } } break; } EditorGUILayout.LabelField("Unity Version", avatarDescriptor.unityVersion); }
private void OnGUI() { if (LocalizeText.instance.langPair is null) { DrawNowLoading(); return; } using (new EditorGUILayout.HorizontalScope(GUILayout.Height(EditorGUIUtility.singleLineHeight * 1.5f))) { GUILayout.FlexibleSpace(); GatoGUILayout.Button( LocalizeText.instance.langPair.reloadAvatarButtonText, () => { OnChangedAvatar(); }, originalAvatar != null); EditorGUILayout.Space(); var toolInfoButtonText = (!isShowingToolInfo) ? LocalizeText.instance.langPair.toolInfoButtonText : LocalizeText.instance.langPair.close; var settingButtonText = (!isShowingSetting) ? LocalizeText.instance.langPair.settingButtonText : LocalizeText.instance.langPair.close; GatoGUILayout.Button( toolInfoButtonText, () => { isShowingToolInfo = !isShowingToolInfo; isShowingSetting = false; }, true, GUILayout.MinWidth(50)); GatoGUILayout.Button( settingButtonText, () => { isShowingSetting = !isShowingSetting; isShowingToolInfo = false; if (!isShowingSetting) { EditorSetting.instance.ApplySettingsToEditorGUI( edittingAvatar, faceEmotionGUI); } }, true, GUILayout.MinWidth(50)); } if (!isShowingToolInfo && !isShowingSetting) { using (new EditorGUILayout.VerticalScope()) { // アバター選択 using (var check = new EditorGUI.ChangeCheckScope()) { targetAvatarDescriptor = GatoGUILayout.ObjectField( LocalizeText.instance.langPair.avatarLabel, targetAvatarDescriptor); if (check.changed) { // アバター変更時の処理 if (targetAvatarDescriptor != null) { OnChangedAvatar(); } } } using (new EditorGUI.DisabledGroupScope(edittingAvatar.Descriptor == null)) { // LayoutType: Default if (layoutType == LayoutType.Default) { using (new EditorGUILayout.HorizontalScope()) { needRepaint = avatarMonitorGUI.DrawGUI(null); if (needRepaint) { Repaint(); } else { animationsGUI.DrawGUI(layoutOptions[0]); } } DrawToolSwitchTab(); selectedToolGUI.DrawGUI(null); } // LayoutType: Half else { using (new EditorGUILayout.HorizontalScope()) { needRepaint = avatarMonitorGUI.DrawGUI(null); if (needRepaint) { Repaint(); } using (new EditorGUILayout.VerticalScope()) { DrawToolSwitchTab(); if (CurrentTool == ToolFunc.AvatarInfo) { using (new EditorGUILayout.HorizontalScope()) { if (!needRepaint) { animationsGUI.DrawGUI(layoutOptions[1]); } } // アバター情報 avatarInfoGUI.DrawGUI(null); } else { selectedToolGUI.DrawGUI(null); } } } } EditorGUILayout.Space(); // ポーズ修正 GatoGUILayout.Button( LocalizeText.instance.langPair.resetPoseButtonText, () => { HumanoidPose.ResetPose(edittingAvatar.Descriptor.gameObject); HumanoidPose.ResetPose(originalAvatar.Descriptor.gameObject); }); // アップロード GatoGUILayout.Button( LocalizeText.instance.langPair.uploadAvatarButtonText, () => { VRCSDKUtility.UploadAvatar(VRCSDKUtility.IsNewSDKUI()); }); } } } else if (isShowingToolInfo) { ToolInfoGUI(); } else { SettingGUI(); } EditorGUILayout.Space(); }
void OnGUIAvatarCheck(VRCSDK2.VRC_AvatarDescriptor avatar) { int polycount; Bounds bounds; AnalyzeGeometry(avatar.gameObject, out bounds, out polycount); if (polycount < 10000) { OnGUIInformation(avatar, "Polygons: " + polycount); } else if (polycount < 15000) { OnGUIWarning(avatar, "Polygons: " + polycount + " - Please try to reduce your avatar poly count to less thatn 10k."); } else if (polycount < 20000) { OnGUIWarning(avatar, "Polygons: " + polycount + " - This avatar will not perform well on many systems."); } else { OnGUIError(avatar, "Polygons: " + polycount + " - This avatar has too many polygons. It must have less than 20k and should have less than 10k."); } if (bounds.size.x > 5f || bounds.size.y > 6.0f || bounds.size.z > 5f) { OnGUIError(avatar, "This avatar measures too large on at least one axis. It must be <5m on a side but it's bounds are " + bounds.size.ToString()); } var eventHandler = avatar.GetComponentInChildren <VRCSDK2.VRC_EventHandler>(); if (eventHandler != null) { OnGUIError(avatar, "This avatar contains an EventHandler, which is not currently supported in VRChat."); } if (avatar.lipSync == VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.VisemeBlendShape && avatar.VisemeSkinnedMesh == null) { OnGUIError(avatar, "This avatar uses Visemes but the Face Mesh is not specified."); } var anim = avatar.GetComponent <Animator>(); if (anim == null) { OnGUIWarning(avatar, "This avatar does not contain an animator, and will not animate in VRChat."); } else if (anim.isHuman == false) { OnGUIWarning(avatar, "This avatar is not imported as a humanoid rig and will not play VRChat's provided animation set."); } else if (avatar.gameObject.activeInHierarchy == false) { OnGUIError(avatar, "Your avatar is disabled in the scene heirarchy!"); } else { Transform foot = anim.GetBoneTransform(HumanBodyBones.LeftFoot); Transform shoulder = anim.GetBoneTransform(HumanBodyBones.LeftUpperArm); if (foot == null) { OnGUIError(avatar, "Your avatar is humanoid, but it's feet aren't specified!"); } if (shoulder == null) { OnGUIError(avatar, "Your avatar is humanoid, but it's upper arms aren't specified!"); } if (foot != null && shoulder != null) { Vector3 footPos = foot.position - avatar.transform.position; if (footPos.y < 0) { OnGUIWarning(avatar, "Avatar feet are beneath the avatar's origin (the floor). That's probably not what you want."); } Vector3 shoulderPosition = shoulder.position - avatar.transform.position; if (shoulderPosition.y < 0.2f) { OnGUIError(avatar, "This avatar is too short. The minimum is 20cm shoulder height."); } else if (shoulderPosition.y < 1.0f) { OnGUIWarning(avatar, "This avatar is short. This is probably shorter than you want."); } else if (shoulderPosition.y > 5.0f) { OnGUIWarning(avatar, "This avatar is too tall. The maximum is 5m shoulder height."); } else if (shoulderPosition.y > 2.5f) { OnGUIWarning(avatar, "This avatar is tall. This is probably taller than you want."); } } if (AnalyzeIK(avatar, avatar.gameObject, anim) == false) { OnGUILink(avatar, "See https://docs.vrchat.com/docs/rig-requirements for details."); } } IEnumerable <Component> componentsToRemove = VRCSDK2.AvatarValidation.FindIllegalComponents(avatar.Name, avatar.gameObject); HashSet <string> componentsToRemoveNames = new HashSet <string>(); foreach (Component c in componentsToRemove) { if (componentsToRemoveNames.Contains(c.GetType().Name) == false) { componentsToRemoveNames.Add(c.GetType().Name); } } if (componentsToRemoveNames.Count > 0) { OnGUIError(avatar, "The following component types are found on the Avatar and will be removed by the client: " + string.Join(", ", componentsToRemoveNames.ToArray())); } if (VRCSDK2.AvatarValidation.EnforceAudioSourceLimits(avatar.gameObject).Count > 0) { OnGUIWarning(avatar, "Audio sources found on Avatar, they will be adjusted to safe limits, if necessary."); } if (avatar.gameObject.GetComponentInChildren <Camera>() != null) { OnGUIWarning(avatar, "Cameras are removed from non-local avatars at runtime."); } }
public Extension(VRCSDK2.VRC_AvatarDescriptor avatar) { m_avatar = avatar; }
void OnGUIAvatarCheck(VRCSDK2.VRC_AvatarDescriptor avatar) { int polycount; Bounds bounds; AnalyzeGeometry(avatar.gameObject, out bounds, out polycount); OnGUIInformation(avatar, "Polygons: " + polycount + "\nBounds: " + bounds.size.ToString()); var eventHandler = avatar.GetComponentInChildren <VRCSDK2.VRC_EventHandler>(); if (eventHandler != null) { OnGUIError(avatar, "This avatar contains an EventHandler, which is not currently supported in VRChat."); } if (avatar.lipSync == VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.VisemeBlendShape && avatar.VisemeSkinnedMesh == null) { OnGUIError(avatar, "This avatar uses Visemes but the Face Mesh is not specified."); } var anim = avatar.GetComponent <Animator>(); if (anim == null) { OnGUIWarning(avatar, "This avatar does not contain an animator, and will not animate in VRChat."); } else if (anim.isHuman == false) { OnGUIWarning(avatar, "This avatar is not imported as a humanoid rig and will not play VRChat's provided animation set."); } else if (avatar.gameObject.activeInHierarchy == false) { OnGUIError(avatar, "Your avatar is disabled in the scene heirarchy!"); } else { Transform foot = anim.GetBoneTransform(HumanBodyBones.LeftFoot); Transform shoulder = anim.GetBoneTransform(HumanBodyBones.LeftUpperArm); if (foot == null) { OnGUIError(avatar, "Your avatar is humanoid, but it's feet aren't specified!"); } if (shoulder == null) { OnGUIError(avatar, "Your avatar is humanoid, but it's upper arms aren't specified!"); } if (foot != null && shoulder != null) { Vector3 footPos = foot.position - avatar.transform.position; if (footPos.y < 0) { OnGUIWarning(avatar, "Avatar feet are beneath the avatar's origin (the floor). That's probably not what you want."); } Vector3 shoulderPosition = shoulder.position - avatar.transform.position; if (shoulderPosition.y < 0.2f) { OnGUIError(avatar, "This avatar is too short. The minimum is 20cm shoulder height."); } else if (shoulderPosition.y < 1.0f) { OnGUIWarning(avatar, "This avatar is short. This is probably shorter than you want."); } else if (shoulderPosition.y > 5.0f) { OnGUIWarning(avatar, "This avatar is too tall. The maximum is 5m shoulder height."); } else if (shoulderPosition.y > 2.5f) { OnGUIWarning(avatar, "This avatar is tall. This is probably taller than you want."); } } if (AnalyzeIK(avatar, avatar.gameObject, anim) == false) { OnGUILink(avatar, "See https://docs.vrchat.com/docs/rig-requirements for details."); } } }