< 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:155
Line coverage:95% (38 of 40)
Covered branches:0
Total branches:0
Covered methods:1
Total methods:1
Method coverage:100% (1 of 1)

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
 13        void Update();
 14
 15        void Prepare(SkinnedMeshRenderer skr, bool encodeBindPoses = false);
 16    }
 17
 18    public static class GPUSkinningUtils
 19    {
 20        /// <summary>
 21        /// This must be done once per SkinnedMeshRenderer before animating.
 22        /// </summary>
 23        /// <param name="skr"></param>
 24        public static void EncodeBindPosesIntoMesh(SkinnedMeshRenderer skr)
 25        {
 126            Mesh sharedMesh = skr.sharedMesh;
 127            int vertexCount = sharedMesh.vertexCount;
 28
 129            NativeArray<Vector4> bone01data = new NativeArray<Vector4>(vertexCount, Allocator.Temp, NativeArrayOptions.U
 130            NativeArray<Vector4> bone23data = new NativeArray<Vector4>(vertexCount, Allocator.Temp, NativeArrayOptions.U
 31
 132            var bonesPerVertex = sharedMesh.GetBonesPerVertex();
 133            var boneWeightsNative = sharedMesh.GetAllBoneWeights();
 134            var boneIndex = 0;
 35
 209636            for (int i = 0; i < vertexCount; i++)
 37            {
 104738                byte boneCount = bonesPerVertex[i];
 39
 104740                if (boneCount == 0)
 41                {
 042                    bone01data[i] = new Vector4(0, 0, 0, 0);
 043                    bone23data[i] = new Vector4(0, 0, 0, 0);
 44                }
 104745                else if (boneCount == 1)
 46                {
 24447                    var bw0 = boneWeightsNative[boneIndex];
 24448                    bone01data[i] = new Vector4(bw0.boneIndex, bw0.weight, 0, 0);
 24449                    bone23data[i] = new Vector4(0, 0, 0, 0);
 50                }
 80351                else if (boneCount == 2)
 52                {
 42253                    var bw0 = boneWeightsNative[boneIndex];
 42254                    var bw1 = boneWeightsNative[boneIndex + 1];
 42255                    bone01data[i] = new Vector4(bw0.boneIndex, bw0.weight, bw1.boneIndex, bw1.weight);
 42256                    bone23data[i] = new Vector4(0, 0, 0, 0);
 57                }
 38158                else if (boneCount == 3)
 59                {
 16460                    var bw0 = boneWeightsNative[boneIndex];
 16461                    var bw1 = boneWeightsNative[boneIndex + 1];
 16462                    var bw2 = boneWeightsNative[boneIndex + 2];
 16463                    bone01data[i] = new Vector4(bw0.boneIndex, bw0.weight, bw1.boneIndex, bw1.weight);
 16464                    bone23data[i] = new Vector4(bw2.boneIndex, bw2.weight, 0, 0);
 65                }
 21766                else if (boneCount >= 4)
 67                {
 21768                    var bw0 = boneWeightsNative[boneIndex];
 21769                    var bw1 = boneWeightsNative[boneIndex + 1];
 21770                    var bw2 = boneWeightsNative[boneIndex + 2];
 21771                    var bw3 = boneWeightsNative[boneIndex + 3];
 21772                    bone01data[i] = new Vector4(bw0.boneIndex, bw0.weight, bw1.boneIndex, bw1.weight);
 21773                    bone23data[i] = new Vector4(bw2.boneIndex, bw2.weight, bw3.boneIndex, bw3.weight);
 74                }
 75
 104776                boneIndex += boneCount;
 77            }
 78
 179            sharedMesh.SetTangents(bone01data);
 180            sharedMesh.SetUVs(1, bone23data);
 81
 182            bone01data.Dispose();
 183            bone23data.Dispose();
 184        }
 85    }
 86
 87    public class SimpleGPUSkinning : IGPUSkinning
 88    {
 89        private static readonly int BONE_MATRICES = Shader.PropertyToID("_Matrices");
 90        private static readonly int BIND_POSES = Shader.PropertyToID("_BindPoses");
 91        private static readonly int RENDERER_WORLD_INVERSE = Shader.PropertyToID("_WorldInverse");
 92
 93        public Renderer renderer { get; private set; }
 94
 95        private Transform[] bones;
 96        private Matrix4x4[] boneMatrices;
 97
 98        public void Prepare(SkinnedMeshRenderer skr, bool encodeBindPoses = false)
 99        {
 100            if (encodeBindPoses)
 101                GPUSkinningUtils.EncodeBindPosesIntoMesh(skr);
 102
 103            boneMatrices = new Matrix4x4[skr.bones.Length];
 104
 105            GameObject go = skr.gameObject;
 106
 107            if (!go.TryGetComponent(out MeshFilter meshFilter))
 108                meshFilter = go.AddComponent<MeshFilter>();
 109
 110            meshFilter.sharedMesh = skr.sharedMesh;
 111
 112            renderer = go.AddComponent<MeshRenderer>();
 113            renderer.enabled = skr.enabled;
 114            renderer.sharedMaterials = skr.sharedMaterials;
 115
 116            foreach (Material material in renderer.sharedMaterials)
 117            {
 118                material.SetMatrixArray(BIND_POSES, skr.sharedMesh.bindposes.ToArray());
 119                material.EnableKeyword("_GPU_SKINNING");
 120            }
 121
 122            bones = skr.bones;
 123            renderer.localBounds = new Bounds(new Vector3(0, 2, 0), new Vector3(1, 3, 1));
 124            UpdateMatrices();
 125
 126            Object.Destroy(skr);
 127        }
 128
 129        public void Update()
 130        {
 131            if (!renderer.gameObject.activeInHierarchy)
 132                return;
 133
 134            UpdateMatrices();
 135        }
 136
 137        private void UpdateMatrices()
 138        {
 139            int bonesLength = bones.Length;
 140
 141            for (int i = 0; i < bonesLength; i++)
 142            {
 143                Transform bone = bones[i];
 144                boneMatrices[i] = bone.localToWorldMatrix;
 145            }
 146
 147            for (int index = 0; index < renderer.sharedMaterials.Length; index++)
 148            {
 149                Material material = renderer.sharedMaterials[index];
 150                material.SetMatrix(RENDERER_WORLD_INVERSE, renderer.transform.worldToLocalMatrix);
 151                material.SetMatrixArray(BONE_MATRICES, boneMatrices);
 152            }
 153        }
 154    }
 155}