public void RunPerformanceScan(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { _limitComponentScansPerFrame = false; try { _coroutines.Push(RunPerformanceScanEnumerator(avatarObject, perfStats, shouldIgnoreComponent)); while (_coroutines.Count > 0) { IEnumerator currentCoroutine = _coroutines.Peek(); if (currentCoroutine.MoveNext()) { IEnumerator nestedCoroutine = currentCoroutine.Current as IEnumerator; if (nestedCoroutine != null) { _coroutines.Push(nestedCoroutine); } } else { _coroutines.Pop(); } } _coroutines.Clear(); } finally { _limitComponentScansPerFrame = true; } }
public IEnumerator ApplyPerformanceFilters( GameObject avatarObject, AvatarPerformanceStats perfStats, PerformanceRating ratingLimit, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent, AvatarPerformance.FilterBlockCallback onBlock ) { foreach (AbstractPerformanceFilter performanceFilter in performanceFilters) { if (performanceFilter == null) { continue; } bool avatarBlocked = false; yield return(performanceFilter.ApplyPerformanceFilter(avatarObject, perfStats, ratingLimit, shouldIgnoreComponent, () => { avatarBlocked = true; })); if (!avatarBlocked) { continue; } onBlock(); break; } }
public override IEnumerator RunPerformanceScan(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { int totalClothVertices = 0; List <Cloth> clothBuffer = new List <Cloth>(16); avatarObject.GetComponentsInChildren(includeInactiveObjectsInStats, clothBuffer); if (shouldIgnoreComponent != null) { clothBuffer.RemoveAll(c => shouldIgnoreComponent(c)); } perfStats.clothCount = clothBuffer.Count; foreach (Cloth cloth in clothBuffer) { if (cloth == null) { continue; } Vector3[] clothVertices = cloth.vertices; if (clothVertices == null) { continue; } totalClothVertices += clothVertices.Length; } perfStats.clothMaxVertices = totalClothVertices; yield break; }
public abstract IEnumerator ApplyPerformanceFilter( GameObject avatarObject, AvatarPerformanceStats perfStats, PerformanceRating ratingLimit, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent, AvatarPerformance.FilterBlockCallback onBlock );
public static AvatarPerformanceStats CalculatePerformanceStats(string avatarName, GameObject avatarObject) { AvatarPerformanceStats stats = new AvatarPerformanceStats(); Stack <IEnumerator> coroutines = new Stack <IEnumerator>(); coroutines.Push(CalculatePerformanceStatsEnumerator(avatarName, avatarObject, stats)); while (coroutines.Count > 0) { IEnumerator currentCoroutine = coroutines.Peek(); if (currentCoroutine.MoveNext()) { IEnumerator nestedCoroutine = currentCoroutine.Current as IEnumerator; if (nestedCoroutine != null) { coroutines.Push(nestedCoroutine); } } else { coroutines.Pop(); } } return(stats); }
private static void AnalyzeMeshRenderers(IEnumerable <Renderer> renderers, AvatarPerformanceStats perfStats) { int count = 0; int materialSlots = 0; foreach (Renderer renderer in renderers) { MeshRenderer meshRenderer = renderer as MeshRenderer; if (meshRenderer == null) { continue; } count++; MeshFilter meshFilter = meshRenderer.GetComponent <MeshFilter>(); if (meshFilter == null) { continue; } Mesh sharedMesh = meshFilter.sharedMesh; if (sharedMesh != null) { materialSlots += sharedMesh.subMeshCount; } } perfStats.meshCount += count; perfStats.materialCount += materialSlots; }
void OnGUIPerformanceInfo(Object avatar, AvatarPerformanceStats perfStats, AvatarPerformanceCategory perfCategory) { string text; PerformanceInfoDisplayLevel displayLevel; PerformanceRating rating = perfStats.GetPerformanceRatingForCategory(perfCategory); perfStats.GetSDKPerformanceInfoText(out text, out displayLevel, perfCategory, rating); if (displayLevel == PerformanceInfoDisplayLevel.None || string.IsNullOrEmpty(text)) { return; } if (displayLevel == PerformanceInfoDisplayLevel.Verbose && showAvatarPerformanceDetails) { OnGUIStat(avatar, text, rating); } if (displayLevel == PerformanceInfoDisplayLevel.Info) { OnGUIStat(avatar, text, rating); } if (displayLevel == PerformanceInfoDisplayLevel.Warning) { OnGUIStat(avatar, text, rating); } if (displayLevel == PerformanceInfoDisplayLevel.Error) { OnGUIStat(avatar, text, rating); OnGUIError(avatar, text); } }
public override IEnumerator RunPerformanceScan(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { int animatorCount = 0; List <Animator> animatorBuffer = new List <Animator>(16); avatarObject.GetComponentsInChildren(includeInactiveObjectsInStats, animatorBuffer); if (shouldIgnoreComponent != null) { animatorBuffer.RemoveAll(c => shouldIgnoreComponent(c)); } animatorCount += animatorBuffer.Count; yield return(null); List <Animation> animationBuffer = new List <Animation>(16); avatarObject.GetComponentsInChildren(includeInactiveObjectsInStats, animationBuffer); if (shouldIgnoreComponent != null) { animationBuffer.RemoveAll(c => shouldIgnoreComponent(c)); } animatorCount += animationBuffer.Count; perfStats.animatorCount = animatorCount; yield return(null); }
private void AnalyzeSkinnedMeshRenderers(IEnumerable <Renderer> renderers, AvatarPerformanceStats perfStats) { Profiler.BeginSample("AnalyzeSkinnedMeshRenderers"); int count = 0; int materialSlots = 0; int skinnedBoneCount = 0; HashSet <Transform> transformIgnoreBuffer = new HashSet <Transform>(); foreach (Renderer renderer in renderers) { Profiler.BeginSample("Analyze SkinnedMeshRenderer"); SkinnedMeshRenderer skinnedMeshRenderer = renderer as SkinnedMeshRenderer; if (skinnedMeshRenderer == null) { Profiler.EndSample(); continue; } count++; Mesh sharedMesh = skinnedMeshRenderer.sharedMesh; if (sharedMesh != null) { materialSlots += sharedMesh.subMeshCount; } // bone count Profiler.BeginSample("Count Bones"); Transform[] bones = skinnedMeshRenderer.bones; foreach (Transform bone in bones) { Profiler.BeginSample("Count Bone"); if (bone == null || transformIgnoreBuffer.Contains(bone)) { Profiler.EndSample(); continue; } transformIgnoreBuffer.Add(bone); skinnedBoneCount++; Profiler.EndSample(); } Profiler.EndSample(); Profiler.EndSample(); } transformIgnoreBuffer.Clear(); Profiler.EndSample(); perfStats.skinnedMeshCount += count; perfStats.materialCount += materialSlots; perfStats.boneCount += skinnedBoneCount; }
public override IEnumerator RunPerformanceScan(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { List <ParticleSystem> particleSystems = new List <ParticleSystem>(16); avatarObject.GetComponentsInChildren(includeInactiveObjectsInStats, particleSystems); if (shouldIgnoreComponent != null) { particleSystems.RemoveAll(c => shouldIgnoreComponent(c)); } yield return(AnalyzeParticleSystemRenderers(particleSystems, perfStats)); }
public IEnumerator RunPerformanceScan(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { foreach (AbstractPerformanceScanner performanceScanner in performanceScanners) { if (performanceScanner == null) { continue; } yield return(performanceScanner.RunPerformanceScan(avatarObject, perfStats, shouldIgnoreComponent)); } }
public override IEnumerator RunPerformanceScan(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { List <Light> lightBuffer = new List <Light>(16); avatarObject.GetComponentsInChildren(includeInactiveObjectsInStats, lightBuffer); if (shouldIgnoreComponent != null) { lightBuffer.RemoveAll(c => shouldIgnoreComponent(c)); } perfStats.lightCount = lightBuffer.Count; yield break; }
public override IEnumerator RunPerformanceScan(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { List <Collider> colliderBuffer = new List <Collider>(16); avatarObject.GetComponentsInChildren(includeInactiveObjectsInStats, colliderBuffer); colliderBuffer.RemoveAll( o => { if (shouldIgnoreComponent != null && shouldIgnoreComponent(o)) { return(true); } if (o.GetComponent <VRC_Station>() != null) { return(true); } return(false); } ); perfStats.physicsColliderCount = colliderBuffer.Count; yield return(null); List <Rigidbody> rigidbodyBuffer = new List <Rigidbody>(16); avatarObject.GetComponentsInChildren(includeInactiveObjectsInStats, rigidbodyBuffer); rigidbodyBuffer.RemoveAll( o => { if (shouldIgnoreComponent != null && shouldIgnoreComponent(o)) { return(true); } if (o.GetComponent <VRC_Station>() != null) { return(true); } return(false); } ); perfStats.physicsRigidbodyCount = rigidbodyBuffer.Count; yield return(null); }
/// <summary> /// Questの制限値に関するエラーメッセージを取得します。 /// </summary> /// <param name="prefab"></param> /// <returns></returns> private static IEnumerable <Converter.Message> GenerateQuestLimitationsErrorMessages(GameObject prefab) { var messages = new List <Converter.Message>(); AvatarPerformanceStats statistics = new AvatarPerformanceStats(); AvatarPerformance.CalculatePerformanceStats("", prefab, statistics); AvatarPerformanceStatsLevel performanceStatLimits = VRChatUtility.AvatarPerformanceStatsLevelSets["Quest"].medium; foreach (var limitation in new[] { new { current = statistics.skinnedMeshCount, limit = performanceStatLimits.skinnedMeshCount, message = _("The number of Skinned Mesh Renderer components is {0}.") }, new { current = statistics.meshCount, limit = performanceStatLimits.meshCount, message = _("The number of (non-Skinned) Mesh Renderer components is {0}.") }, new { current = statistics.materialCount, limit = performanceStatLimits.materialCount, message = _("The number of material slots (sub-meshes) is {0}.") }, new { current = statistics.boneCount, limit = performanceStatLimits.boneCount, message = _("The number of Bones is {0}.") }, }) { if (limitation.current > limitation.limit) { messages.Add(new Converter.Message { message = string.Format(limitation.message, limitation.current) + string.Format( _("If this value exceeds {0}, the avatar will not shown under the default user setting."), limitation.limit ), type = MessageType.Error, }); } } return(messages); }
public override IEnumerator RunPerformanceScan(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { List <Renderer> renderers = new List <Renderer>(16); avatarObject.GetComponentsInChildren(includeInactiveObjectsInStats, renderers); if (shouldIgnoreComponent != null) { renderers.RemoveAll(c => shouldIgnoreComponent(c)); } AnalyzeGeometry(avatarObject, renderers, perfStats); AnalyzeMeshRenderers(renderers, perfStats); AnalyzeSkinnedMeshRenderers(renderers, perfStats); yield return(null); }
public override IEnumerator RunPerformanceScan(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { List <LineRenderer> lineRenderers = new List <LineRenderer>(16); avatarObject.GetComponentsInChildren(includeInactiveObjectsInStats, lineRenderers); if (shouldIgnoreComponent != null) { lineRenderers.RemoveAll(c => shouldIgnoreComponent(c)); } int numLineRenderers = lineRenderers.Count; perfStats.lineRendererCount += numLineRenderers; perfStats.materialCount += numLineRenderers; yield break; }
/// <summary> /// DynamicBoneの制限の既定値を超えていた場合、警告メッセージを返します。 /// </summary> /// <seealso cref="AvatarPerformance.AnalyzeDynamicBone"/> /// <param name="prefabInstance"></param> /// <returns></returns> private static IEnumerable <Converter.Message> GetMessagesAboutDynamicBoneLimits(GameObject avatar) { var messages = new List <Converter.Message>(); #if VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3 AvatarPerformanceStats statistics = new AvatarPerformanceStats(); AvatarPerformance.CalculatePerformanceStats(avatar.GetComponent <VRMMeta>().Meta.Title, avatar, statistics); AvatarPerformanceStatsLevel mediumPerformanceStatLimits = VRChatUtility.AvatarPerformanceStatsLevelSets["PC"].medium; if (statistics.dynamicBoneSimulatedBoneCount > mediumPerformanceStatLimits.dynamicBoneSimulatedBoneCount) { messages.Add(new Converter.Message { message = string.Format( _("The “Dynamic Bone Simulated Bone Count” is {0}."), statistics.dynamicBoneSimulatedBoneCount ) + string.Format( _("If this value exceeds {0}, the default user setting disable all Dynamic Bones."), mediumPerformanceStatLimits.dynamicBoneSimulatedBoneCount ), type = MessageType.Warning, }); } if (statistics.dynamicBoneCollisionCheckCount > mediumPerformanceStatLimits.dynamicBoneCollisionCheckCount) { messages.Add(new Converter.Message { message = string.Format( _("The “Dynamic Bone Collision Check Count” is {0}."), statistics.dynamicBoneCollisionCheckCount ) + string.Format( _("If this value exceeds {0}, the default user setting disable all Dynamic Bones."), mediumPerformanceStatLimits.dynamicBoneCollisionCheckCount ), type = MessageType.Warning, }); } #endif return(messages); }
private static void AnalyzeMeshRenderers(IEnumerable <Renderer> renderers, AvatarPerformanceStats perfStats) { Profiler.BeginSample("AnalyzeMeshRenderers"); int count = 0; int materialSlots = 0; foreach (Renderer renderer in renderers) { Profiler.BeginSample("Analyze MeshRenderer"); MeshRenderer meshRenderer = renderer as MeshRenderer; if (meshRenderer == null) { Profiler.EndSample(); continue; } count++; Profiler.BeginSample("Get MeshFilter"); MeshFilter meshFilter = meshRenderer.GetComponent <MeshFilter>(); Profiler.EndSample(); if (meshFilter == null) { Profiler.EndSample(); continue; } Mesh sharedMesh = meshFilter.sharedMesh; if (sharedMesh != null) { materialSlots += sharedMesh.subMeshCount; } } Profiler.EndSample(); perfStats.meshCount = count; perfStats.materialCount = perfStats.materialCount.GetValueOrDefault() + materialSlots; }
public static IEnumerator ApplyPerformanceFiltersEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, PerformanceRating minPerfRating, FilterBlockCallback onBlock) { // Performance Filtering is disabled. if (minPerfRating == PerformanceRating.None) { yield break; } PerformanceFilterSet performanceFilterSet = GetPerformanceFilterSet(); if (performanceFilterSet == null) { yield break; } bool avatarBlocked = false; yield return(performanceFilterSet.ApplyPerformanceFilters( avatarObject, perfStats, minPerfRating, ShouldIgnoreComponentInternal, () => { avatarBlocked = true; } )); if (!avatarBlocked) { yield break; } VRC.Core.Logger.LogFormat( "Avatar hidden due to low performance rating: [{0}] {1} - minimum setting: {2}", perfStats.avatarName, perfStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.Overall), minPerfRating ); onBlock(); }
public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { // Cloth List <Cloth> clothBuffer = new List <Cloth>(); yield return(ScanAvatarForComponentsOfType(avatarObject, clothBuffer)); if (shouldIgnoreComponent != null) { clothBuffer.RemoveAll(c => shouldIgnoreComponent(c)); } int totalClothVertices = 0; foreach (Cloth cloth in clothBuffer) { if (cloth == null) { continue; } Vector3[] clothVertices = cloth.vertices; if (clothVertices == null) { continue; } totalClothVertices += clothVertices.Length; } perfStats.clothCount = clothBuffer.Count; perfStats.clothMaxVertices = totalClothVertices; }
public abstract IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent);
public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { // Line Renderers List <LineRenderer> lineRendererBuffer = new List <LineRenderer>(); yield return(ScanAvatarForComponentsOfType(avatarObject, lineRendererBuffer)); if (shouldIgnoreComponent != null) { lineRendererBuffer.RemoveAll(c => shouldIgnoreComponent(c)); } int numLineRenderers = lineRendererBuffer.Count; perfStats.lineRendererCount = numLineRenderers; perfStats.materialCount = perfStats.materialCount.GetValueOrDefault() + numLineRenderers; }
private static IEnumerator AnalyzeParticleSystemRenderers(IEnumerable <ParticleSystem> particleSystems, AvatarPerformanceStats perfStats) { int particleSystemCount = 0; ulong particleTotalCount = 0; ulong particleTotalMaxMeshPolyCount = 0; bool particleTrailsEnabled = false; bool particleCollisionEnabled = false; int materialSlots = 0; foreach (ParticleSystem particleSystem in particleSystems) { int particleCount = particleSystem.main.maxParticles; if (particleCount <= 0) { continue; } particleSystemCount++; particleTotalCount += (uint)particleCount; ParticleSystemRenderer particleSystemRenderer = particleSystem.GetComponent <ParticleSystemRenderer>(); if (particleSystemRenderer == null) { continue; } materialSlots++; // mesh particles if (particleSystemRenderer.renderMode == ParticleSystemRenderMode.Mesh && particleSystemRenderer.meshCount > 0) { uint highestPolyCount = 0; Mesh[] meshes = new Mesh[particleSystemRenderer.meshCount]; int particleRendererMeshCount = particleSystemRenderer.GetMeshes(meshes); for (int meshIndex = 0; meshIndex < particleRendererMeshCount; meshIndex++) { Mesh mesh = meshes[meshIndex]; if (mesh == null) { continue; } uint polyCount = MeshUtils.GetMeshTriangleCount(mesh); if (polyCount > highestPolyCount) { highestPolyCount = polyCount; } } ulong maxMeshParticlePolyCount = (uint)particleCount * highestPolyCount; particleTotalMaxMeshPolyCount += maxMeshParticlePolyCount; } if (particleSystem.trails.enabled) { particleTrailsEnabled = true; materialSlots++; } if (particleSystem.collision.enabled) { particleCollisionEnabled = true; } } perfStats.particleSystemCount = particleSystemCount; perfStats.particleTotalCount = particleTotalCount > int.MaxValue ? int.MaxValue : (int)particleTotalCount; perfStats.particleMaxMeshPolyCount = particleTotalMaxMeshPolyCount > int.MaxValue ? int.MaxValue : (int)particleTotalMaxMeshPolyCount; perfStats.particleTrailsEnabled = particleTrailsEnabled; perfStats.particleCollisionEnabled = particleCollisionEnabled; perfStats.materialCount += materialSlots; yield break; }
public static IEnumerator CalculatePerformanceStatsEnumerator(string avatarName, GameObject avatarObject, AvatarPerformanceStats perfStats) { perfStats.Reset(); perfStats.avatarName = avatarName; PerformanceScannerSet performanceScannerSet = GetPerformanceScannerSet(); if (performanceScannerSet != null) { yield return(performanceScannerSet.RunPerformanceScanEnumerator(avatarObject, perfStats, ShouldIgnoreComponentInternal)); } // cache performance ratings perfStats.CalculateAllPerformanceRatings(); }
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 IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { if (_dynamicBoneType == null) { yield break; } // Dynamic Bone as Component List <Component> dynamicBoneComponentBuffer = new List <Component>(); List <object> dynamicBoneColliderObjectBuffer = new List <object>(); yield return(ScanAvatarForComponentsOfType(_dynamicBoneType, avatarObject, dynamicBoneComponentBuffer)); if (shouldIgnoreComponent != null) { dynamicBoneComponentBuffer.RemoveAll(c => shouldIgnoreComponent(c)); } int totalSimulatedBoneCount = 0; int totalCollisionChecks = 0; Profiler.BeginSample("Analyze Dynamic Bones"); foreach (Component dynamicBone in dynamicBoneComponentBuffer) { Profiler.BeginSample("Single Dynamic Bone Component"); int simulatedBones = 0; // Add extra bones to the end of each chain if end bones are being used. float endLength = (float)_dynamicBoneEndLengthFieldInfo.GetValue(dynamicBone); Vector3 endOffset = (Vector3)_dynamicBoneEndOffsetFieldInfo.GetValue(dynamicBone); bool hasEndBones = endLength > 0 || endOffset != Vector3.zero; Transform root = (Transform)_dynamicBoneRootFieldInfo.GetValue(dynamicBone); if (root != null) { List <Transform> exclusions = (List <Transform>)_dynamicBoneExclusionsFieldInfo.GetValue(dynamicBone); // Calculate number of simulated bones for the hierarchy simulatedBones = CountTransformsRecursively(root, exclusions, hasEndBones); totalSimulatedBoneCount += simulatedBones; } int colliderListEntryCount = 0; IList colliderList = (IList)_dynamicBoneCollidersFieldInfo.GetValue(dynamicBone); if (colliderList != null) { foreach (object collider in colliderList) { colliderListEntryCount += 1; if (collider != null && !dynamicBoneColliderObjectBuffer.Contains(collider)) { dynamicBoneColliderObjectBuffer.Add(collider); } } } // The root bone is skipped in collision checks. totalCollisionChecks += (simulatedBones - 1) * colliderListEntryCount; Profiler.EndSample(); } Profiler.EndSample(); yield return(null); perfStats.dynamicBoneComponentCount = dynamicBoneComponentBuffer.Count; perfStats.dynamicBoneSimulatedBoneCount = totalSimulatedBoneCount; perfStats.dynamicBoneColliderCount = dynamicBoneColliderObjectBuffer.Count; perfStats.dynamicBoneCollisionCheckCount = totalCollisionChecks; }
protected override bool DrawWizardGUI() { base.DrawWizardGUI(); isValid = true; if (this.callbackFunctions) { Type callBackFunctions = this.callbackFunctions.GetClass(); this.swayingParametersConverter = Delegate.CreateDelegate( type: typeof(Converter.SwayingParametersConverter), target: callBackFunctions, method: "SwayingParametersConverter", ignoreCase: false, throwOnBindFailure: false ) as Converter.SwayingParametersConverter; 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 VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3 foreach (var type in Converter.RequiredComponents) { if (!this.avatar.GetComponent(type)) { EditorGUILayout.HelpBox(string.Format(_("Not set “{0}” component."), type), MessageType.Error); 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); } string version = VRChatUtility.GetSupportedUnityVersion(); 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 (!isValid || !this.forQuest) { return(true); } AvatarPerformanceStats statistics = new AvatarPerformanceStats(); AvatarPerformance.CalculatePerformanceStats( avatarName: avatar.GetComponent <VRMMeta>().Meta.Title, avatarObject: this.avatar.gameObject, perfStats: statistics ); int currentPolycount = (int)statistics.polyCount; int maxPolycount = VRChatUtility.AvatarPerformanceStatsLevelSets["Quest"].medium.polyCount; if (currentPolycount > maxPolycount) { EditorGUILayout.HelpBox(string.Format( _("The number of polygons is {0}."), currentPolycount ) + string.Format( _("If this value exceeds {0}, the avatar will not shown under the default user setting."), maxPolycount ), MessageType.Error); } #else EditorGUILayout.HelpBox(_("VRChat SDK2 or SDK3 has not been imported."), MessageType.Error); isValid = false; #endif return(true); }
public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { // Colliders List <Collider> colliderBuffer = new List <Collider>(); yield return(ScanAvatarForComponentsOfType(avatarObject, colliderBuffer)); colliderBuffer.RemoveAll( o => { if (shouldIgnoreComponent != null && shouldIgnoreComponent(o)) { return(true); } if (o.GetComponent <VRC.SDKBase.VRC_Station>() != null) { return(true); } return(false); } ); perfStats.physicsColliderCount = colliderBuffer.Count; // Rigidbodies List <Rigidbody> rigidbodyBuffer = new List <Rigidbody>(); yield return(ScanAvatarForComponentsOfType(avatarObject, rigidbodyBuffer)); rigidbodyBuffer.RemoveAll( o => { if (shouldIgnoreComponent != null && shouldIgnoreComponent(o)) { return(true); } if (o.GetComponent <VRC.SDKBase.VRC_Station>() != null) { return(true); } return(false); } ); perfStats.physicsRigidbodyCount = rigidbodyBuffer.Count; }
private static void LoadEditorResources() { AvatarPerformanceStats.Initialize(); }
public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) { // Particle Systems List <ParticleSystem> particleSystemBuffer = new List <ParticleSystem>(); yield return(ScanAvatarForComponentsOfType(avatarObject, particleSystemBuffer)); if (shouldIgnoreComponent != null) { particleSystemBuffer.RemoveAll(c => shouldIgnoreComponent(c)); } AnalyzeParticleSystemRenderers(particleSystemBuffer, perfStats); yield return(null); }