コード例 #1
0
        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;
            }
        }
コード例 #2
0
        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;
            }
        }
コード例 #3
0
        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;
        }
コード例 #4
0
 public abstract IEnumerator ApplyPerformanceFilter(
     GameObject avatarObject,
     AvatarPerformanceStats perfStats,
     PerformanceRating ratingLimit,
     AvatarPerformance.IgnoreDelegate shouldIgnoreComponent,
     AvatarPerformance.FilterBlockCallback onBlock
     );
コード例 #5
0
        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);
        }
コード例 #6
0
        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;
        }
コード例 #7
0
    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);
        }
    }
コード例 #8
0
        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);
        }
コード例 #9
0
        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;
        }
コード例 #10
0
        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));
        }
コード例 #11
0
        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));
            }
        }
コード例 #12
0
        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;
        }
コード例 #13
0
        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);
        }
コード例 #14
0
        /// <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);
        }
コード例 #15
0
        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);
        }
コード例 #16
0
        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;
        }
コード例 #17
0
        /// <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;
        }
コード例 #19
0
        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();
        }
コード例 #20
0
        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;
        }
コード例 #21
0
 public abstract IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent);
コード例 #22
0
        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;
        }
コード例 #23
0
        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;
        }
コード例 #24
0
        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();
        }
コード例 #25
0
    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);
    }
コード例 #26
0
        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;
        }
コード例 #27
0
        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);
        }
コード例 #28
0
        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;
        }
コード例 #29
0
 private static void LoadEditorResources()
 {
     AvatarPerformanceStats.Initialize();
 }
コード例 #30
0
        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);
        }