예제 #1
0
        /// <summary>
        /// プレハブをVRChatへアップロード可能な状態にします。
        /// </summary>
        /// <param name="prefabInstance">現在のシーンに存在するプレハブのインスタンス。</param>
        /// <param name="clips"><see cref="VRMUtility.GetAllVRMBlendShapeClips"/>の戻り値。</param>
        /// <param name="forQuest">Quest版用アバター向けに変換するなら <c>true</c>。</param>
        /// <param name="swayingObjectsConverterSetting">揺れ物を変換するか否かの設定。<c>forQuest</c> が <c>true</c> の場合は無視されます。</param>
        /// <param name="takingOverSwayingParameters">揺れ物のパラメータを変換せずDynamic Boneのデフォルト値を利用するなら<c>false</c>。</param>
        /// <param name="swayingParametersConverter"></param>
        /// <param name="swayingParametersConverter"></param>
        /// <param name="addedShouldersPositionY">VRChat上でモデルがなで肩・いかり肩になる問題について、Shoulder/UpperArmボーンのPositionのYに加算する値。</param>
        /// <param name="addedArmaturePositionY">VRChat上で足が沈む問題について、Hipsボーンの一つ上のオブジェクトのPositionのYに加算する値。</param>
        /// <param name="useShapeKeyNormalsAndTangents"><c>false</c> の場合、シェイプキーの法線・接線を削除します。</param>
        /// <returns>変換中に発生したメッセージ。</returns>
        public static IEnumerable <(string message, MessageType type)> Convert(
            GameObject prefabInstance,
            IEnumerable <VRMBlendShapeClip> clips,
            bool forQuest,
            SwayingObjectsConverterSetting swayingObjectsConverterSetting,
            bool takingOverSwayingParameters = true,
            VRMSpringBonesToDynamicBonesConverter.ParametersConverter swayingParametersConverter = null,
            VRMBlendShapeClip vrmBlendShapeForFINGERPOINT = null,
            bool keepingUpperChest             = false,
            float addedShouldersPositionY      = 0.0f,
            float addedArmaturePositionY       = 0.0f,
            bool useShapeKeyNormalsAndTangents = false
            )
        {
            AssetDatabase.SaveAssets();

#if VRC_SDK_VRCSDK3
            prefabInstance.AddComponent <VRCAvatarDescriptor>();
            prefabInstance.GetOrAddComponent <PipelineManager>();
#else
            throw new PlatformNotSupportedException("VRChat SDK3-Avatars has not been imported.");
#endif

            var messages = new List <(string, MessageType)>();
            messages.AddRange(GeometryCorrector.Apply(avatar: prefabInstance));
            BlendShapeReplacer.Apply(
                avatar: prefabInstance,
                clips: clips,
                useShapeKeyNormalsAndTangents,
                vrmBlendShapeForFINGERPOINT
                );
            messages.AddRange(ComponentsReplacer.Apply(
                                  avatar: prefabInstance,
                                  swayingObjectsConverterSetting: forQuest
                    ? SwayingObjectsConverterSetting.RemoveSwayingObjects
                    : swayingObjectsConverterSetting,
                                  swayingParametersConverter: takingOverSwayingParameters
                    ? swayingParametersConverter
                    : null
                                  ));
            messages.AddRange(VRChatsBugsWorkaround.Apply(
                                  avatar: prefabInstance,
                                  keepingUpperChest,
                                  addedShouldersPositionY: addedShouldersPositionY,
                                  addedArmaturePositionY: addedArmaturePositionY
                                  ));
            VRChatUtility.RemoveBlockedComponents(prefabInstance, forQuest);
            Undo.RegisterCreatedObjectUndo(prefabInstance, "Convert VRM for VRChat");

            AssetDatabase.SaveAssets();
            return(messages);
        }
예제 #2
0
        /// <summary>
        /// クラスに含まれる処理を適用します。
        /// </summary>
        /// <param name="avatar"></param>
        /// <param name="swayingParametersConverter"></param>
        /// <returns></returns>
        internal static IEnumerable <(string, MessageType)> Apply(
            GameObject avatar,
            Converter.SwayingObjectsConverterSetting swayingObjectsConverterSetting,
            VRMSpringBonesToDynamicBonesConverter.ParametersConverter swayingParametersConverter
            )
        {
            var messages = new List <(string, MessageType)>();

            ConvertVRMFirstPerson(avatar: avatar);

            if (DynamicBoneType == null ||
                swayingObjectsConverterSetting == Converter.SwayingObjectsConverterSetting.RemoveSwayingObjects)
            {
                return(messages);
            }

            var ignoreColliders
                = swayingObjectsConverterSetting == Converter.SwayingObjectsConverterSetting.ConvertVrmSpringBonesOnly;

            if (!ignoreColliders)
            {
                ComponentsReplacer.RemoveUnusedColliderGroups(avatar);
            }

            var animator = avatar.GetComponent <Animator>();

            VRMSpringBonesToDynamicBonesConverter.Convert(
                source: animator,
                destination: animator,
                ignoreColliders: ignoreColliders,
                parametersConverter: swayingParametersConverter
                );

            messages.AddRange(VRChatUtility.CalculateDynamicBoneLimitations(prefabInstance: avatar));

            return(messages);
        }
예제 #3
0
        protected override bool DrawWizardGUI()
        {
            base.DrawWizardGUI();
            this.isValid = true;

            if (this.callbackFunctions)
            {
                Type callBackFunctions = this.callbackFunctions.GetClass();

                this.swayingParametersConverter = Delegate.CreateDelegate(
                    type: typeof(VRMSpringBonesToDynamicBonesConverter.ParametersConverter),
                    target: callBackFunctions,
                    method: "SwayingParametersConverter",
                    ignoreCase: false,
                    throwOnBindFailure: false
                    ) as VRMSpringBonesToDynamicBonesConverter.ParametersConverter;

                this.postConverting = Delegate.CreateDelegate(
                    type: typeof(Wizard.PostConverting),
                    target: callBackFunctions,
                    method: "PostConverting",
                    ignoreCase: false,
                    throwOnBindFailure: false
                    ) as Wizard.PostConverting;
            }

            var indentStyle = new GUIStyle()
            {
                padding = new RectOffset()
                {
                    left = Wizard.Indent
                }
            };

            EditorGUILayout.LabelField(
                (this.swayingParametersConverter != null ? "☑" : "☐")
                + " public static DynamicBoneParameters SwayingParametersConverter(SpringBoneParameters, BoneInfo)",
                indentStyle
                );

            EditorGUILayout.LabelField(
                (this.postConverting != null ? "☑" : "☐")
                + " public static void PostConverting(GameObject, VRMMeta)",
                indentStyle
                );

            if (VRChatUtility.SDKVersion == 2)
            {
                EditorGUILayout.HelpBox(_("The conversion from VRM to VRChat avatar is not supported by VRChat SDK2."), MessageType.Error);
                this.isValid = false;
                return(true);
            }
            else if (VRChatUtility.SDKVersion == null)
            {
                EditorGUILayout.HelpBox(_("VRChat SDK3-Avatars has not been imported."), MessageType.Error);
                this.isValid = false;
                return(true);
            }

            foreach (var type in Converter.RequiredComponents)
            {
                if (!this.avatar.GetComponent(type))
                {
                    EditorGUILayout.HelpBox(string.Format(_("Not set “{0}” component."), type), MessageType.Error);
                    this.isValid = false;
                }
            }

            IEnumerable <string> excludedSpringBoneComments = this.excludedSpringBoneComments.Except(new[] { "" });

            if (excludedSpringBoneComments.Count() > 0)
            {
                IEnumerable <string> comments = excludedSpringBoneComments.Except(
                    this.GetSpringBonesWithComments(prefab: this.avatar.gameObject, comments: excludedSpringBoneComments)
                    .Select(commentAndSpringBones => commentAndSpringBones.Key)
                    );
                if (comments.Count() > 0)
                {
                    EditorGUILayout.HelpBox(string.Join(separator: "\n• ", value: new[] { _("VRMSpringBones with the below Comments do not exist.") }
                                                        .Concat(comments).ToArray()), MessageType.Warning);
                }
            }

            if (this.combineMeshes)
            {
                IEnumerable <string> notCombineRendererObjectNames
                    = this.notCombineRendererObjectNames.Except(new[] { "" });
                if (notCombineRendererObjectNames.Count() > 0)
                {
                    IEnumerable <string> names = notCombineRendererObjectNames.Except(
                        this.avatar.GetComponentsInChildren <SkinnedMeshRenderer>()
                        .Concat <Component>(this.avatar.GetComponentsInChildren <MeshRenderer>())
                        .Select(renderer => renderer.name)
                        );
                    if (names.Count() > 0)
                    {
                        EditorGUILayout.HelpBox(string.Join(separator: "\n• ", value: new[] { _("Renderers on the below name GameObject do not exist.") }
                                                            .Concat(names).ToArray()), MessageType.Warning);
                    }
                }
            }
            else
            {
                EditorGUILayout.HelpBox(_("If you do not “Combine Meshes”,"
                                          + " and any of VRMBlendShapes references meshes other than the mesh having most shape keys"
                                          + " or the mesh is not direct child of the avatar root,"
                                          + " the avatar will not be converted correctly."), MessageType.Warning);
            }

            if (!string.IsNullOrEmpty(this.blendShapeForFingerpoint) &&
                !VRMUtility.GetUserDefinedBlendShapeClip(this.avatar, this.blendShapeForFingerpoint))
            {
                EditorGUILayout.HelpBox(string.Format(
                                            _("There is no user-defined VRMBlensShape with the name “{0}”."),
                                            this.blendShapeForFingerpoint
                                            ), MessageType.Warning);
            }

            var version = VRChatUtility.SDKSupportedUnityVersion;

            if (version != "" && Application.unityVersion != version)
            {
                EditorGUILayout.HelpBox(string.Format(
                                            _("Unity {0} is running. If you are using a different version than {1}, VRChat SDK might not work correctly. Recommended using Unity downloaded from {2} ."),
                                            Application.unityVersion,
                                            version,
                                            VRChatUtility.DownloadURL
                                            ), MessageType.Warning);
            }

            if (!this.isValid || !this.forQuest)
            {
                return(true);
            }

            var currentTriangleCount = VRChatUtility.CountTriangle(this.avatar.gameObject);

            if (currentTriangleCount > VRChatUtility.Limitations.triangleCount)
            {
                EditorGUILayout.HelpBox(string.Format(
                                            _("The number of polygons is {0}."),
                                            currentTriangleCount
                                            ) + string.Format(
                                            _("If this value exceeds {0}, the avatar will not shown under the default user setting."),
                                            VRChatUtility.Limitations.triangleCount
                                            ), MessageType.Error);
            }

            return(true);
        }