/// <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); }
/// <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); }
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); }