Last active
February 17, 2025 21:31
-
-
Save d4rkc0d3r/b975d64a37c64a73be221749614fd5fc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #if UNITY_EDITOR | |
| using System.Collections; | |
| using System.Collections.Generic; | |
| using UnityEngine; | |
| using UnityEngine.Rendering; | |
| using UnityEditor; | |
| using System.Linq; | |
| public class MeshVRAMSize : EditorWindow | |
| { | |
| Object selected; | |
| private int ByteSize(VertexAttributeFormat format) | |
| { | |
| switch(format) | |
| { | |
| case VertexAttributeFormat.UNorm8: | |
| case VertexAttributeFormat.SNorm8: | |
| case VertexAttributeFormat.UInt8: | |
| case VertexAttributeFormat.SInt8: | |
| return 1; | |
| case VertexAttributeFormat.Float16: | |
| case VertexAttributeFormat.UNorm16: | |
| case VertexAttributeFormat.SNorm16: | |
| case VertexAttributeFormat.UInt16: | |
| case VertexAttributeFormat.SInt16: | |
| return 2; | |
| case VertexAttributeFormat.Float32: | |
| case VertexAttributeFormat.UInt32: | |
| case VertexAttributeFormat.SInt32: | |
| default: | |
| return 4; | |
| } | |
| } | |
| private (int vertexAttributes, int blendShapes) CalculateMeshVRAMSize(Mesh mesh) | |
| { | |
| var vertexAttributes = mesh.GetVertexAttributes(); | |
| int vertexAttributeVRAMSize = 0; | |
| foreach (var vertexAttribute in vertexAttributes) | |
| { | |
| int skinnedMeshPositionNormalTangentMultiplier = 1; | |
| // skinned meshes have 2x the amount of position, normal and tangent data since they store both the un-skinned and skinned data | |
| // we check for the blend indices and blend weights attributes since they are required for skinned meshes | |
| if (mesh.HasVertexAttribute(VertexAttribute.BlendIndices) && mesh.HasVertexAttribute(VertexAttribute.BlendWeight) && | |
| (vertexAttribute.attribute == VertexAttribute.Position || vertexAttribute.attribute == VertexAttribute.Normal || vertexAttribute.attribute == VertexAttribute.Tangent)) | |
| skinnedMeshPositionNormalTangentMultiplier = 2; | |
| vertexAttributeVRAMSize += ByteSize(vertexAttribute.format) * vertexAttribute.dimension * skinnedMeshPositionNormalTangentMultiplier; | |
| } | |
| var deltaPositions = new Vector3[mesh.vertexCount]; | |
| var deltaNormals = new Vector3[mesh.vertexCount]; | |
| var deltaTangents = new Vector3[mesh.vertexCount]; | |
| int blendShapeVRAMSize = 0; | |
| for (int i = 0; i < mesh.blendShapeCount; i++) | |
| { | |
| var blendShapeName = mesh.GetBlendShapeName(i); | |
| var blendShapeFrameCount = mesh.GetBlendShapeFrameCount(i); | |
| for (int j = 0; j < blendShapeFrameCount; j++) | |
| { | |
| mesh.GetBlendShapeFrameVertices(i, j, deltaPositions, deltaNormals, deltaTangents); | |
| for (int k = 0; k < deltaPositions.Length; k++) | |
| { | |
| if (deltaPositions[k] != Vector3.zero || deltaNormals[k] != Vector3.zero || deltaTangents[k] != Vector3.zero) | |
| { | |
| // every affected vertex has 1 uint for the index, 3 floats for the position, 3 floats for the normal and 3 floats for the tangent | |
| // this is true even if all normals or tangents in all blend shapes are zero | |
| blendShapeVRAMSize += 40; | |
| } | |
| } | |
| } | |
| } | |
| return (vertexAttributeVRAMSize * mesh.vertexCount, blendShapeVRAMSize); | |
| } | |
| int blendShapeVRAMSize = -1; | |
| int vertexAttributeVRAMSize = -1; | |
| void OnGUI() | |
| { | |
| EditorGUI.BeginChangeCheck(); | |
| selected = EditorGUILayout.ObjectField(selected, typeof(Object), true); | |
| if (EditorGUI.EndChangeCheck()) | |
| { | |
| blendShapeVRAMSize = -1; | |
| vertexAttributeVRAMSize = -1; | |
| } | |
| var mesh = selected as Mesh; | |
| if (mesh == null) | |
| { | |
| var skinnedMeshRenderer = selected as SkinnedMeshRenderer; | |
| if (skinnedMeshRenderer != null) | |
| mesh = skinnedMeshRenderer.sharedMesh; | |
| var gameObject = selected as GameObject; | |
| if (gameObject != null && gameObject.GetComponent<SkinnedMeshRenderer>() != null) | |
| mesh = gameObject.GetComponent<SkinnedMeshRenderer>().sharedMesh; | |
| if (gameObject != null && gameObject.GetComponent<MeshFilter>() != null) | |
| mesh = gameObject.GetComponent<MeshFilter>().sharedMesh; | |
| } | |
| if (mesh == null) | |
| { | |
| selected = null; | |
| return; | |
| } | |
| if (blendShapeVRAMSize == -1 || vertexAttributeVRAMSize == -1) | |
| { | |
| var vramSize = CalculateMeshVRAMSize(mesh); | |
| vertexAttributeVRAMSize = vramSize.vertexAttributes; | |
| blendShapeVRAMSize = vramSize.blendShapes; | |
| } | |
| EditorGUILayout.LabelField($"Vertex Count: {mesh.vertexCount}"); | |
| EditorGUILayout.LabelField($"Blend Shape Count: {mesh.blendShapeCount}"); | |
| EditorGUILayout.LabelField($"Vertex Attribute VRAM Size: {vertexAttributeVRAMSize / 1024f / 1024f:f2} MiB"); | |
| EditorGUILayout.LabelField($"Blend Shape VRAM Size: {blendShapeVRAMSize / 1024f / 1024f:f2} MiB"); | |
| EditorGUILayout.LabelField($"Total VRAM Size: {(vertexAttributeVRAMSize + blendShapeVRAMSize) / 1024f / 1024f:f2} MiB"); | |
| } | |
| [MenuItem("Tools/d4rkpl4y3r/Mesh VRAM Size")] | |
| public static void OpenWindow() | |
| { | |
| var window = GetWindow(typeof(MeshVRAMSize)) as MeshVRAMSize; | |
| } | |
| } | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment