/// <summary>
        /// Generates instancing renderer data for a given GameObject, at the given LOD level.
        /// </summary>
        /// <param name="lod">Which LOD level to generate renderers in</param>
        /// <param name="gameObject">GameObject</param>
        /// <param name="settings">GPU Instancer settings to find appropriate shader for materials</param>
        /// <param name="includeChildren">if true, renderers for all found children of this gameObject will be created as well</param>
        private bool CreateRenderersFromGameObject(int lod, GameObject gameObject, GPUInstancerShaderBindings shaderBindings, bool createShadowMPB)
        {
            if (instanceLODs == null || instanceLODs.Count <= lod || instanceLODs[lod] == null)
            {
                Debug.LogError("Can't create renderer(s): Invalid LOD");
                return(false);
            }

            if (!gameObject)
            {
                Debug.LogError("Can't create renderer(s): reference GameObject is null");
                return(false);
            }

            List <MeshRenderer> meshRenderers = new List <MeshRenderer>();

            GetMeshRenderersOfTransform(gameObject.transform, meshRenderers);

            if (meshRenderers == null || meshRenderers.Count == 0)
            {
                Debug.LogError("Can't create renderer(s): no MeshRenderers found in the reference GameObject <" + gameObject.name +
                               "> or any of its children");
                return(false);
            }

            foreach (MeshRenderer meshRenderer in meshRenderers)
            {
                if (meshRenderer.GetComponent <MeshFilter>() == null)
                {
                    Debug.LogWarning("MeshRenderer with no MeshFilter found on GameObject <" + gameObject.name +
                                     "> (Child: <" + meshRenderer.gameObject + ">). Are you missing a component?");
                    continue;
                }

                List <Material> instanceMaterials = new List <Material>();

                for (int m = 0; m < meshRenderer.sharedMaterials.Length; m++)
                {
                    instanceMaterials.Add(shaderBindings.GetInstancedMaterial(meshRenderer.sharedMaterials[m]));
                }

                Matrix4x4 transformOffset  = Matrix4x4.identity;
                Transform currentTransform = meshRenderer.gameObject.transform;
                while (currentTransform != gameObject.transform)
                {
                    transformOffset  = Matrix4x4.TRS(currentTransform.localPosition, currentTransform.localRotation, currentTransform.localScale) * transformOffset;
                    currentTransform = currentTransform.parent;
                }

                MaterialPropertyBlock mpb = new MaterialPropertyBlock();
                meshRenderer.GetPropertyBlock(mpb);
                MaterialPropertyBlock shadowMPB = null;
                if (createShadowMPB)
                {
                    shadowMPB = new MaterialPropertyBlock();
                    meshRenderer.GetPropertyBlock(shadowMPB);
                }
                AddRenderer(lod, meshRenderer.GetComponent <MeshFilter>().sharedMesh, instanceMaterials, transformOffset, mpb, meshRenderer.shadowCastingMode != UnityEngine.Rendering.ShadowCastingMode.Off, meshRenderer.gameObject.layer, shadowMPB);
            }

            return(true);
        }
        /// <summary>
        /// Generates all LOD and render data from the supplied Unity LODGroup. Deletes all existing LOD data.
        /// </summary>
        /// <param name="lodGroup">Unity LODGroup</param>
        /// <param name="settings">GPU Instancer settings to find appropriate shader for materials</param>
        private bool GenerateLODsFromLODGroup(LODGroup lodGroup, GPUInstancerShaderBindings shaderBindings, bool createShadowMPB)
        {
            if (instanceLODs == null)
            {
                instanceLODs = new List <GPUInstancerPrototypeLOD>();
            }
            else
            {
                instanceLODs.Clear();
            }

            for (int lod = 0; lod < lodGroup.GetLODs().Length; lod++)
            {
                bool            hasBillboardRenderer = false;
                List <Renderer> lodRenderers         = new List <Renderer>();
                if (lodGroup.GetLODs()[lod].renderers != null)
                {
                    foreach (Renderer renderer in lodGroup.GetLODs()[lod].renderers)
                    {
                        if (renderer != null && renderer is MeshRenderer && renderer.GetComponent <MeshFilter>() != null)
                        {
                            lodRenderers.Add(renderer);
                        }
                        else if (renderer != null && renderer is BillboardRenderer)
                        {
                            hasBillboardRenderer = true;
                        }
                    }
                }

                if (!lodRenderers.Any())
                {
                    if (!hasBillboardRenderer)
                    {
                        Debug.LogWarning("LODGroup has no mesh renderers. Prefab: " + lodGroup.gameObject.name + " LODIndex: " + lod);
                    }
                    continue;
                }

                AddLod(lodGroup.GetLODs()[lod].screenRelativeTransitionHeight);

                for (int r = 0; r < lodRenderers.Count; r++)
                {
                    List <Material> instanceMaterials = new List <Material>();
                    for (int m = 0; m < lodRenderers[r].sharedMaterials.Length; m++)
                    {
                        instanceMaterials.Add(shaderBindings.GetInstancedMaterial(lodRenderers[r].sharedMaterials[m]));
                    }

                    Matrix4x4 transformOffset  = Matrix4x4.identity;
                    Transform currentTransform = lodRenderers[r].gameObject.transform;
                    while (currentTransform != lodGroup.gameObject.transform)
                    {
                        transformOffset  = Matrix4x4.TRS(currentTransform.localPosition, currentTransform.localRotation, currentTransform.localScale) * transformOffset;
                        currentTransform = currentTransform.parent;
                    }

                    MaterialPropertyBlock mpb = new MaterialPropertyBlock();
                    lodRenderers[r].GetPropertyBlock(mpb);
                    MaterialPropertyBlock shadowMPB = null;
                    if (createShadowMPB)
                    {
                        shadowMPB = new MaterialPropertyBlock();
                        lodRenderers[r].GetPropertyBlock(shadowMPB);
                    }
                    AddRenderer(lod, lodRenderers[r].GetComponent <MeshFilter>().sharedMesh, instanceMaterials, transformOffset, mpb, lodRenderers[r].shadowCastingMode != UnityEngine.Rendering.ShadowCastingMode.Off, lodRenderers[r].gameObject.layer, shadowMPB);
                }
            }
            return(true);
        }