InstanceData CreateInstanceData(int packageCount)
        {
            InstanceData data = new InstanceData();

            data.worldMatrix        = new List <Matrix4x4[]> [packageCount];
            data.frameIndex         = new List <float[]> [packageCount];
            data.preFrameIndex      = new List <float[]> [packageCount];
            data.transitionProgress = new List <float[]> [packageCount];
            for (int i = 0; i != packageCount; ++i)
            {
                data.worldMatrix[i]        = new List <Matrix4x4[]>();
                data.frameIndex[i]         = new List <float[]>();
                data.preFrameIndex[i]      = new List <float[]>();
                data.transitionProgress[i] = new List <float[]>();
            }
            return(data);
        }
        private VertexCache CreateVertexCache(string prefabName, int renderName, int alias, Mesh mesh)
        {
            VertexCache vertexCache = new VertexCache();
            int         cacheName   = renderName + alias;

            vertexCachePool[cacheName]   = vertexCache;
            vertexCache.nameCode         = cacheName;
            vertexCache.mesh             = mesh;
            vertexCache.boneTextureIndex = FindTexture_internal(prefabName);
            vertexCache.weight           = new Vector4[mesh.vertexCount];
            vertexCache.boneIndex        = new Vector4[mesh.vertexCount];
            int          packageCount = GetPackageCount(vertexCache);
            InstanceData data         = null;
            int          instanceName = prefabName.GetHashCode() + alias;

            if (!instanceDataPool.TryGetValue(instanceName, out data))
            {
                data = CreateInstanceData(packageCount);
                instanceDataPool.Add(instanceName, data);
            }
            vertexCache.instanceBlockList = new Dictionary <int, MaterialBlock>();
            return(vertexCache);
        }
        public InstancingPackage CreatePackage(InstanceData data, Mesh mesh, Material[] originalMaterial, int animationIndex)
        {
            InstancingPackage package = new InstancingPackage();

            package.material     = new Material[mesh.subMeshCount];
            package.subMeshCount = mesh.subMeshCount;
            package.size         = 1;
            for (int i = 0; i != mesh.subMeshCount; ++i)
            {
                package.material[i] = new Material(originalMaterial[i]);
#if UNITY_5_6_OR_NEWER
                package.material[i].enableInstancing = UseInstancing;
#endif
                if (UseInstancing)
                {
                    package.material[i].EnableKeyword("INSTANCING_ON");
                }
                else
                {
                    package.material[i].DisableKeyword("INSTANCING_ON");
                }

                package.propertyBlock = new MaterialPropertyBlock();
                package.material[i].EnableKeyword("USE_CONSTANT_BUFFER");
                package.material[i].DisableKeyword("USE_COMPUTE_BUFFER");
            }

            Matrix4x4[] mat                = new Matrix4x4[instancingPackageSize];
            float[]     frameIndex         = new float[instancingPackageSize];
            float[]     preFrameIndex      = new float[instancingPackageSize];
            float[]     transitionProgress = new float[instancingPackageSize];
            data.worldMatrix[animationIndex].Add(mat);
            data.frameIndex[animationIndex].Add(frameIndex);
            data.preFrameIndex[animationIndex].Add(preFrameIndex);
            data.transitionProgress[animationIndex].Add(transitionProgress);
            return(package);
        }
        private void Render()
        {
            foreach (var obj in vertexCachePool)
            {
                VertexCache vertexCache = obj.Value;
                foreach (var block in vertexCache.instanceBlockList)
                {
                    List <InstancingPackage>[] packageList = block.Value.packageList;
                    for (int k = 0; k != packageList.Length; ++k)
                    {
                        for (int i = 0; i != packageList[k].Count; ++i)
                        {
                            InstancingPackage package = packageList[k][i];
                            if (package.instancingCount == 0)
                            {
                                continue;
                            }
                            for (int j = 0; j != package.subMeshCount; ++j)
                            {
                                InstanceData data = block.Value.instanceData;
                                if (useInstancing)
                                {
#if UNITY_EDITOR
                                    PreparePackageMaterial(package, vertexCache, k);
#endif
                                    package.propertyBlock.SetFloatArray("frameIndex", data.frameIndex[k][i]);
                                    package.propertyBlock.SetFloatArray("preFrameIndex", data.preFrameIndex[k][i]);
                                    package.propertyBlock.SetFloatArray("transitionProgress", data.transitionProgress[k][i]);
                                    Graphics.DrawMeshInstanced(vertexCache.mesh,
                                                               j,
                                                               package.material[j],
                                                               data.worldMatrix[k][i],
                                                               package.instancingCount,
                                                               package.propertyBlock,
                                                               vertexCache.shadowcastingMode,
                                                               vertexCache.receiveShadow,
                                                               vertexCache.layer);
                                }
                                else
                                {
                                    package.material[j].SetFloat("frameIndex", data.frameIndex[k][i][0]);
                                    package.material[j].SetFloat("preFrameIndex", data.preFrameIndex[k][i][0]);
                                    package.material[j].SetFloat("transitionProgress", data.transitionProgress[k][i][0]);
                                    Graphics.DrawMesh(vertexCache.mesh,
                                                      data.worldMatrix[k][i][0],
                                                      package.material[j],
                                                      0,
                                                      null,
                                                      j);
                                }
                            }
                            package.instancingCount = 0;
                        }
                        block.Value.runtimePackageIndex[k] = 0;
                    }
                }

//                 if (obj.Value.instancingData == null)
//                     continue;
//                 vertexCache.bufInstance.SetData(obj.Value.instancingData);
//
//                 for (int i = 0; i != vertexCache.subMeshCount; ++i)
//                 {
//                     Material material = vertexCache.instanceMaterial[i];
//                     material.SetBuffer("buf_InstanceMatrices", vertexCache.bufInstance);
//                     vertexCache.args[i][1] = (uint)vertexCache.currentInstancingIndex;
//                     vertexCache.bufArgs[i].SetData(vertexCache.args[i]);
//
//                     Graphics.DrawMeshInstancedIndirect(vertexCache.mesh,
//                                     i,
//                                     vertexCache.instanceMaterial[i],
//                                     new Bounds(Vector3.zero, new Vector3(10000.0f, 10000.0f, 10000.0f)),
//                                     vertexCache.bufArgs[i]);
//                 }
//                 vertexCache.currentInstancingIndex = 0;
            }
        }
        void ApplyBoneMatrix()
        {
            Vector3 cameraPosition = cameraTransform.position;

            for (int i = 0; i != aniInstancingList.Count; ++i)
            {
                AnimationInstancing instance = aniInstancingList[i];
                if (!instance.IsPlaying())
                {
                    continue;
                }
                if (instance.aniIndex < 0 && instance.parentInstance == null)
                {
                    continue;
                }

                if (instance.applyRootMotion)
                {
                    ApplyRootMotion(instance);
                }

                instance.UpdateAnimation();
                instance.boundingSpere.position = instance.worldTransform.position;
                boundingSphere[i] = instance.boundingSpere;

                if (!instance.visible)
                {
                    continue;
                }
                instance.UpdateLod(cameraPosition);

                AnimationInstancing.LodInfo lod = instance.lodInfo[instance.lodLevel];
                int aniTextureIndex             = -1;
                if (instance.parentInstance != null)
                {
                    aniTextureIndex = instance.parentInstance.aniTextureIndex;
                }
                else
                {
                    aniTextureIndex = instance.aniTextureIndex;
                }

                Matrix4x4 worldMat = instance.worldTransform.localToWorldMatrix;
                for (int j = 0; j != lod.vertexCacheList.Length; ++j)
                {
                    VertexCache   cache = lod.vertexCacheList[j];
                    MaterialBlock block = lod.materialBlockList[j];
                    Debug.Assert(block != null);
                    int packageIndex = block.runtimePackageIndex[aniTextureIndex];
                    Debug.Assert(packageIndex < block.packageList[aniTextureIndex].Count);
                    InstancingPackage package = block.packageList[aniTextureIndex][packageIndex];
                    if (package.instancingCount + 1 > instancingPackageSize)
                    {
                        ++block.runtimePackageIndex[aniTextureIndex];
                        packageIndex = block.runtimePackageIndex[aniTextureIndex];
                        if (packageIndex >= block.packageList[aniTextureIndex].Count)
                        {
                            InstancingPackage newPackage = CreatePackage(block.instanceData,
                                                                         cache.mesh,
                                                                         cache.materials,
                                                                         aniTextureIndex);
                            block.packageList[aniTextureIndex].Add(newPackage);
                            PreparePackageMaterial(newPackage, cache, aniTextureIndex);
                            newPackage.instancingCount = 1;
                        }
                        block.packageList[aniTextureIndex][packageIndex].instancingCount = 1;
                    }
                    else
                    {
                        ++package.instancingCount;
                    }

                    {
                        VertexCache       vertexCache = cache;
                        InstanceData      data        = block.instanceData;
                        int               index       = block.runtimePackageIndex[aniTextureIndex];
                        InstancingPackage pkg         = block.packageList[aniTextureIndex][index];
                        int               count       = pkg.instancingCount - 1;
                        if (count >= 0)
                        {
                            Matrix4x4[] arrayMat = data.worldMatrix[aniTextureIndex][index];
                            arrayMat[count].m00 = worldMat.m00;
                            arrayMat[count].m01 = worldMat.m01;
                            arrayMat[count].m02 = worldMat.m02;
                            arrayMat[count].m03 = worldMat.m03;
                            arrayMat[count].m10 = worldMat.m10;
                            arrayMat[count].m11 = worldMat.m11;
                            arrayMat[count].m12 = worldMat.m12;
                            arrayMat[count].m13 = worldMat.m13;
                            arrayMat[count].m20 = worldMat.m20;
                            arrayMat[count].m21 = worldMat.m21;
                            arrayMat[count].m22 = worldMat.m22;
                            arrayMat[count].m23 = worldMat.m23;
                            arrayMat[count].m30 = worldMat.m30;
                            arrayMat[count].m31 = worldMat.m31;
                            arrayMat[count].m32 = worldMat.m32;
                            arrayMat[count].m33 = worldMat.m33;
                            float frameIndex = 0, preFrameIndex = -1, transition = 0f;
                            if (instance.parentInstance != null)
                            {
                                frameIndex = instance.parentInstance.aniInfo[instance.parentInstance.aniIndex].animationIndex + instance.parentInstance.curFrame;
                                if (instance.parentInstance.preAniIndex >= 0)
                                {
                                    preFrameIndex = instance.parentInstance.aniInfo[instance.parentInstance.preAniIndex].animationIndex + instance.parentInstance.preAniFrame;
                                }
                                transition = instance.parentInstance.transitionProgress;
                            }
                            else
                            {
                                frameIndex = instance.aniInfo[instance.aniIndex].animationIndex + instance.curFrame;
                                if (instance.preAniIndex >= 0)
                                {
                                    preFrameIndex = instance.aniInfo[instance.preAniIndex].animationIndex + instance.preAniFrame;
                                }
                                transition = instance.transitionProgress;
                            }
                            data.frameIndex[aniTextureIndex][index][count]         = frameIndex;
                            data.preFrameIndex[aniTextureIndex][index][count]      = preFrameIndex;
                            data.transitionProgress[aniTextureIndex][index][count] = transition;
                        }
                    }
                }
            }
        }