Example #1
0
        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;
        }
Example #2
0
        /// <summary>
        /// アバターを写す用のカメラを設定する
        /// </summary>
        public VRCAvatar SetAvatarPreview(VRC_AvatarDescriptor descriptor)
        {
            var avatar = avatarMonitorField.AddAvatar(descriptor);

            avatarMonitorField.SetAvatarCamBgColor(monitorBgColor);
            this.avatar = avatar;

            return(avatar);
        }
Example #3
0
 void OnEnable()
 {
     if (avatar == null)
     {
         VRCSDK2.VRC_AvatarDescriptor validDescriptor = GetValidDescriptor();
         if (validDescriptor != null)
         {
             InitForAvatar(validDescriptor);
         }
     }
 }
Example #4
0
    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);
    }
Example #6
0
    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);
    }
Example #7
0
    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 )");
        }
    }
Example #9
0
    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);
    }
Example #11
0
        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);
        }
Example #12
0
    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);
    }
Example #13
0
    // 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);
    }
Example #16
0
        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();
        }
Example #17
0
    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.");
        }
    }
Example #18
0
 public Extension(VRCSDK2.VRC_AvatarDescriptor avatar)
 {
     m_avatar = avatar;
 }
Example #19
0
    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.");
            }
        }
    }