< Summary

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

Metrics

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

File(s)

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

#LineLine coverage
 1using System.Linq;
 2using Unity.Collections;
 3using UnityEngine;
 4using UnityEngine.Profiling;
 5using Object = UnityEngine.Object;
 6
 7namespace GPUSkinning
 8{
 9    public interface IGPUSkinning
 10    {
 11        Renderer renderer { get; }
 12        void Update();
 13        void Prepare(SkinnedMeshRenderer skr, bool encodeBindPoses = false);
 14    }
 15
 16    public static class GPUSkinningUtils
 17    {
 18        /// <summary>
 19        /// This must be done once per SkinnedMeshRenderer before animating.
 20        /// </summary>
 21        /// <param name="skr"></param>
 22        public static void EncodeBindPosesIntoMesh(SkinnedMeshRenderer skr)
 23        {
 124            Mesh sharedMesh = skr.sharedMesh;
 125            int vertexCount = sharedMesh.vertexCount;
 26
 127            NativeArray<Vector4> bone01data = new NativeArray<Vector4>(vertexCount, Allocator.Temp, NativeArrayOptions.U
 128            NativeArray<Vector4> bone23data = new NativeArray<Vector4>(vertexCount, Allocator.Temp, NativeArrayOptions.U
 29
 130            var bonesPerVertex = sharedMesh.GetBonesPerVertex();
 131            var boneWeightsNative = sharedMesh.GetAllBoneWeights();
 132            var boneIndex = 0;
 209633            for ( int i = 0; i < vertexCount; i ++ )
 34            {
 104735                byte boneCount = bonesPerVertex[i];
 104736                if (boneCount == 0)
 37                {
 038                    bone01data[i] = new Vector4(0, 0, 0, 0);
 039                    bone23data[i] = new Vector4(0, 0, 0, 0);
 40                }
 104741                else if (boneCount == 1)
 42                {
 24443                    var bw0 = boneWeightsNative[boneIndex];
 24444                    bone01data[i] = new Vector4(bw0.boneIndex, bw0.weight, 0, 0);
 24445                    bone23data[i] = new Vector4(0, 0, 0, 0);
 46                }
 80347                else if (boneCount == 2)
 48                {
 42249                    var bw0 = boneWeightsNative[boneIndex];
 42250                    var bw1 = boneWeightsNative[boneIndex+1];
 42251                    bone01data[i] = new Vector4(bw0.boneIndex, bw0.weight, bw1.boneIndex, bw1.weight);
 42252                    bone23data[i] = new Vector4(0, 0, 0, 0);
 53                }
 38154                else if (boneCount == 3)
 55                {
 16456                    var bw0 = boneWeightsNative[boneIndex];
 16457                    var bw1 = boneWeightsNative[boneIndex+1];
 16458                    var bw2 = boneWeightsNative[boneIndex+2];
 16459                    bone01data[i] = new Vector4(bw0.boneIndex, bw0.weight, bw1.boneIndex, bw1.weight);
 16460                    bone23data[i] = new Vector4(bw2.boneIndex, bw2.weight, 0, 0);
 61                }
 21762                else if (boneCount >= 4)
 63                {
 21764                    var bw0 = boneWeightsNative[boneIndex];
 21765                    var bw1 = boneWeightsNative[boneIndex+1];
 21766                    var bw2 = boneWeightsNative[boneIndex+2];
 21767                    var bw3 = boneWeightsNative[boneIndex+3];
 21768                    bone01data[i] = new Vector4(bw0.boneIndex, bw0.weight, bw1.boneIndex, bw1.weight);
 21769                    bone23data[i] = new Vector4(bw2.boneIndex, bw2.weight, bw3.boneIndex, bw3.weight);
 70                }
 71
 104772                boneIndex += boneCount;
 73            }
 74
 175            sharedMesh.SetTangents(bone01data);
 176            sharedMesh.SetUVs(1, bone23data);
 77
 178            bone01data.Dispose();
 179            bone23data.Dispose();
 180        }
 81
 82    }
 83
 84    public class SimpleGPUSkinning : IGPUSkinning
 85    {
 86        private static readonly int BONE_MATRICES = Shader.PropertyToID("_Matrices");
 87        private static readonly int BIND_POSES = Shader.PropertyToID("_BindPoses");
 88        private static readonly int RENDERER_WORLD_INVERSE = Shader.PropertyToID("_WorldInverse");
 89
 90        public Renderer renderer { get; private set; }
 91
 92        private Transform[] bones;
 93        private Matrix4x4[] boneMatrices;
 94
 95        public void Prepare(SkinnedMeshRenderer skr, bool encodeBindPoses = false)
 96        {
 97            if ( encodeBindPoses )
 98                GPUSkinningUtils.EncodeBindPosesIntoMesh(skr);
 99
 100            boneMatrices = new Matrix4x4[skr.bones.Length];
 101
 102            GameObject go = skr.gameObject;
 103
 104            if (!go.TryGetComponent(out MeshFilter meshFilter))
 105                meshFilter = go.AddComponent<MeshFilter>();
 106
 107            meshFilter.sharedMesh = skr.sharedMesh;
 108
 109            renderer = go.AddComponent<MeshRenderer>();
 110            renderer.enabled = skr.enabled;
 111            renderer.sharedMaterials = skr.sharedMaterials;
 112            foreach (Material material in renderer.sharedMaterials)
 113            {
 114                material.SetMatrixArray(BIND_POSES, skr.sharedMesh.bindposes.ToArray());
 115                material.EnableKeyword("_GPU_SKINNING");
 116            }
 117
 118            bones = skr.bones;
 119            meshFilter.mesh.bounds = new Bounds(new Vector3(0, 2, 0), new Vector3(1, 3, 1));
 120            UpdateMatrices();
 121
 122            Object.Destroy(skr);
 123        }
 124
 125        public void Update()
 126        {
 127            if (!renderer.gameObject.activeInHierarchy)
 128                return;
 129
 130            UpdateMatrices();
 131        }
 132
 133        private void UpdateMatrices()
 134        {
 135            int bonesLength = bones.Length;
 136            for (int i = 0; i < bonesLength; i++)
 137            {
 138                Transform bone = bones[i];
 139                boneMatrices[i] = bone.localToWorldMatrix;
 140            }
 141
 142            for (int index = 0; index < renderer.sharedMaterials.Length; index++)
 143            {
 144                Material material = renderer.sharedMaterials[index];
 145                material.SetMatrix(RENDERER_WORLD_INVERSE, renderer.transform.worldToLocalMatrix);
 146                material.SetMatrixArray(BONE_MATRICES, boneMatrices);
 147            }
 148        }
 149    }
 150}