< Summary

Class:GPUSkinning.GPUSkinningUtils
Assembly:RenderUtils
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Rendering/Utils/GPUSkinning/SimpleGPUSkinning.cs
Covered lines:18
Uncovered lines:0
Coverable lines:18
Total lines:114
Line coverage:100% (18 of 18)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
EncodeBindPosesIntoMesh(...)0%220100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Rendering/Utils/GPUSkinning/SimpleGPUSkinning.cs

#LineLine coverage
 1using System.Linq;
 2using UnityEngine;
 3using Object = UnityEngine.Object;
 4
 5namespace GPUSkinning
 6{
 7    public interface IGPUSkinning
 8    {
 9        Renderer renderer { get; }
 10        void Update();
 11        void Prepare(SkinnedMeshRenderer skr, bool encodeBindPoses = false);
 12    }
 13
 14    public static class GPUSkinningUtils
 15    {
 16        /// <summary>
 17        /// This must be done once per SkinnedMeshRenderer before animating.
 18        /// </summary>
 19        /// <param name="skr"></param>
 20        public static void EncodeBindPosesIntoMesh(SkinnedMeshRenderer skr)
 21        {
 122            Mesh sharedMesh = skr.sharedMesh;
 123            int vertexCount = sharedMesh.vertexCount;
 124            Vector4[] bone01data = new Vector4[vertexCount];
 125            Vector4[] bone23data = new Vector4[vertexCount];
 26
 127            BoneWeight[] boneWeights = sharedMesh.boneWeights;
 28
 209629            for ( int i = 0; i < vertexCount; i ++ )
 30            {
 104731                BoneWeight boneWeight = boneWeights[i];
 104732                bone01data[i].x = boneWeight.boneIndex0;
 104733                bone01data[i].y = boneWeight.weight0;
 104734                bone01data[i].z = boneWeight.boneIndex1;
 104735                bone01data[i].w = boneWeight.weight1;
 36
 104737                bone23data[i].x = boneWeight.boneIndex2;
 104738                bone23data[i].y = boneWeight.weight2;
 104739                bone23data[i].z = boneWeight.boneIndex3;
 104740                bone23data[i].w = boneWeight.weight3;
 41            }
 42
 143            skr.sharedMesh.tangents = bone01data;
 144            skr.sharedMesh.SetUVs(1, bone23data);
 145        }
 46    }
 47
 48    public class SimpleGPUSkinning : IGPUSkinning
 49    {
 50        private static readonly int BONE_MATRICES = Shader.PropertyToID("_Matrices");
 51        private static readonly int BIND_POSES = Shader.PropertyToID("_BindPoses");
 52        private static readonly int RENDERER_WORLD_INVERSE = Shader.PropertyToID("_WorldInverse");
 53
 54        public Renderer renderer { get; private set; }
 55
 56        private Transform[] bones;
 57        private Matrix4x4[] boneMatrices;
 58
 59        public void Prepare(SkinnedMeshRenderer skr, bool encodeBindPoses = false)
 60        {
 61            if ( encodeBindPoses )
 62                GPUSkinningUtils.EncodeBindPosesIntoMesh(skr);
 63
 64            boneMatrices = new Matrix4x4[skr.bones.Length];
 65
 66            GameObject go = skr.gameObject;
 67
 68            if (!go.TryGetComponent(out MeshFilter meshFilter))
 69                meshFilter = go.AddComponent<MeshFilter>();
 70
 71            meshFilter.sharedMesh = skr.sharedMesh;
 72
 73            renderer = go.AddComponent<MeshRenderer>();
 74            renderer.enabled = skr.enabled;
 75            renderer.sharedMaterials = skr.sharedMaterials;
 76            foreach (Material material in renderer.sharedMaterials)
 77            {
 78                material.SetMatrixArray(BIND_POSES, skr.sharedMesh.bindposes.ToArray());
 79                material.EnableKeyword("_GPU_SKINNING");
 80            }
 81
 82            bones = skr.bones;
 83            meshFilter.mesh.bounds = new Bounds(new Vector3(0, 2, 0), new Vector3(1, 3, 1));
 84            UpdateMatrices();
 85
 86            Object.Destroy(skr);
 87        }
 88
 89        public void Update()
 90        {
 91            if (!renderer.gameObject.activeInHierarchy)
 92                return;
 93
 94            UpdateMatrices();
 95        }
 96
 97        private void UpdateMatrices()
 98        {
 99            int bonesLength = bones.Length;
 100            for (int i = 0; i < bonesLength; i++)
 101            {
 102                Transform bone = bones[i];
 103                boneMatrices[i] = bone.localToWorldMatrix;
 104            }
 105
 106            for (int index = 0; index < renderer.sharedMaterials.Length; index++)
 107            {
 108                Material material = renderer.sharedMaterials[index];
 109                material.SetMatrix(RENDERER_WORLD_INVERSE, renderer.transform.worldToLocalMatrix);
 110                material.SetMatrixArray(BONE_MATRICES, boneMatrices);
 111            }
 112        }
 113    }
 114}