/// <summary>
    /// Initializes a new instance of the <see cref="CLTarget"/> class.
    /// </summary>
    /// <param name="layersToExclude">Layers to exclude for ray casting</param>
    /// <param name="sceneObj">Corresponding scene object.</param>
    /// <param name="_renderables">Renderables (list of objects from which AABB is computed). If empty, we use colliders.</param>
    /// <param name="_colliders">Colliders (list of objects to be used for ray casting)</param>
    /// <param name="_nRays">number of rays to use for checking visibility</param>
    public CLTarget(GameObject sceneObj, List <GameObject> _renderables, List <GameObject> _colliders, int layersToExclude = 1 << 2,
                    VisibilityPointGenerationMethod _visibilityPointGeneration = VisibilityPointGenerationMethod.ON_MESH, int _nRays = 8)
    {
        gameObject = sceneObj;
        name       = sceneObj.name;

        if (_renderables.Count > 0)
        {
            renderables         = new List <GameObject>(_renderables);
            useRenderersForSize = true;
        }
        else
        {
            useRenderersForSize = false;
        }
        colliders = new List <GameObject>(_colliders);
        nRays     = _nRays;
        layerMask = ~layersToExclude;
        visibilityPointGeneration = _visibilityPointGeneration;


        foreach (GameObject g in colliders)
        {
            collidersLayers.Add(g.layer);
        }

        UpdateBounds();

        PreComputeVisibilityPoints(false, Math.Max(2 * colliders.Count, 50));
    }
    /// <summary>
    /// Precomputes a number of visibility points inside the target BB, to be used later for visibility checking.
    /// Visibility points are generated according to the chosen method (value of visibilityPointGeneration member)
    /// We generate 50 visibility points (this could be a parameter ...)
    /// </summary>
    /// <param name="standingOnGround">If set to <c>true</c> standing on ground.</param>
    private void PreComputeVisibilityPoints(bool standingOnGround, int numberofPoints = 50)
    {
        visibilityPoints = new List <Vector3> (numberofPoints);


        switch (visibilityPointGeneration)
        {
        case VisibilityPointGenerationMethod.ON_MESH:
        {
            // remove everything in scene except target (it should be enough to simply move the target to a special layer)

            foreach (GameObject go in colliders)
            {
                go.layer = LayerMask.NameToLayer("CameraControl");
            }

            // find target center, and proper distance such that target is entirely on screen from every angle
            float d = radius / Mathf.Tan(50.0f);                      // supposing a h-fow of 100

            // compute n points on unit sphere
            List <Vector3> samples = TargetUtils.ComputePointsOnSphere(numberofPoints, boundingBox.center, radius);

            // for visibility: cast 1 ray from each point to center, save point of intersection
            foreach (Vector3 point in samples)
            {
                RaycastHit hitPoint;
                bool       hit = Physics.Linecast(point, boundingBox.center, out hitPoint, 1 << LayerMask.NameToLayer("CameraControl"));

                if (hit)
                {
                    visibilityPoints.Add(hitPoint.point);
                }
            }



            break;
        }

        case VisibilityPointGenerationMethod.UNIFORM_IN_BB:
        {
            // We take the AABB, and choose a number of points inside it . For simplicity, we allow only an odd number of rays.
            // For more than 9 points, we move to random generation

            visibilityPoints.Add(boundingBox.center);

            if (numberofPoints > 1 && numberofPoints < 10)                        // add two points along the longest dimension of the AABB

            {
                float[] extents = new float[] { boundingBox.extents.x, boundingBox.extents.y, boundingBox.extents.z };
                int[]   indices = new int[] { 0, 1, 2 };
                Array.Sort(extents, indices);
                int longest       = indices [2];
                int secondLongest = indices [1];
                int shortest      = indices [0];

                Vector3 p1 = boundingBox.center;
                p1 [longest] = 0.25f * boundingBox.min [longest] + 0.75f * boundingBox.max [longest];

                Vector3 p2 = boundingBox.center;
                p2 [longest] = 0.75f * boundingBox.min [longest] + 0.25f * boundingBox.max [longest];

                if (numberofPoints > 3)
                {
                    Vector3 p3 = boundingBox.center;
                    p3 [secondLongest] = 0.75f * boundingBox.min [secondLongest] + 0.25f * boundingBox.max [secondLongest];

                    Vector3 p4 = boundingBox.center;
                    p4 [secondLongest] = 0.25f * boundingBox.min [secondLongest] + 0.75f * boundingBox.max [secondLongest];

                    if (numberofPoints > 5)
                    {
                        p1 [secondLongest] = 0.25f * boundingBox.min [secondLongest] + 0.75f * boundingBox.max [secondLongest];
                        p1 [shortest]      = 0.25f * boundingBox.min [shortest] + 0.75f * boundingBox.max [shortest];

                        p2 [secondLongest] = 0.25f * boundingBox.min [secondLongest] + 0.75f * boundingBox.max [secondLongest];
                        p2 [shortest]      = 0.25f * boundingBox.min [shortest] + 0.75f * boundingBox.max [shortest];

                        p3 [shortest] = 0.25f * boundingBox.min [shortest] + 0.75f * boundingBox.max [shortest];

                        p4 [shortest] = 0.75f * boundingBox.min [shortest] + 0.25f * boundingBox.max [shortest];

                        Vector3 p5 = boundingBox.center;
                        p5 [longest]       = 0.25f * boundingBox.min [longest] + 0.75f * boundingBox.max [longest];
                        p5 [secondLongest] = 0.75f * boundingBox.min [secondLongest] + 0.25f * boundingBox.max [secondLongest];
                        p5 [shortest]      = 0.75f * boundingBox.min [shortest] + 0.25f * boundingBox.max [shortest];

                        Vector3 p6 = boundingBox.center;
                        p6 [longest]       = 0.75f * boundingBox.min [longest] + 0.25f * boundingBox.max [longest];
                        p6 [secondLongest] = 0.75f * boundingBox.min [secondLongest] + 0.25f * boundingBox.max [secondLongest];
                        p6 [shortest]      = 0.75f * boundingBox.min [shortest] + 0.25f * boundingBox.max [shortest];

                        if (numberofPoints == 9)
                        {
                            p3 [longest] = 0.75f * boundingBox.min [longest] + 0.25f * boundingBox.max [longest];

                            p4 [longest] = 0.25f * boundingBox.min [longest] + 0.75f * boundingBox.max [longest];

                            Vector3 p7 = boundingBox.center;
                            p7 [longest]       = 0.25f * boundingBox.min [longest] + 0.75f * boundingBox.max [longest];
                            p7 [secondLongest] = 0.75f * boundingBox.min [secondLongest] + 0.25f * boundingBox.max [secondLongest];
                            p7 [shortest]      = 0.25f * boundingBox.min [shortest] + 0.75f * boundingBox.max [shortest];

                            Vector3 p8 = boundingBox.center;
                            p8 [longest]       = 0.75f * boundingBox.min [longest] + 0.25f * boundingBox.max [longest];
                            p8 [secondLongest] = 0.25f * boundingBox.min [secondLongest] + 0.75f * boundingBox.max [secondLongest];
                            p8 [shortest]      = 0.75f * boundingBox.min [shortest] + 0.25f * boundingBox.max [shortest];

                            visibilityPoints.Add(p7);
                            visibilityPoints.Add(p8);
                        }

                        visibilityPoints.Add(p5);
                        visibilityPoints.Add(p6);
                    }

                    visibilityPoints.Add(p3);
                    visibilityPoints.Add(p4);
                }


                visibilityPoints.Add(p1);
                visibilityPoints.Add(p2);
            }
            else
            {
                visibilityPointGeneration = VisibilityPointGenerationMethod.RANDOM;
            }

            break;
        }

        case (VisibilityPointGenerationMethod.RANDOM):
        {                  // random generation, corresponds to VisibilityPointGenerationMethod.RANDOM
            if (numberofPoints >= colliders.Count)
            {
                // assign 1 random point per collider, until they are over
                int colliderIndex = 0;
                while (numberofPoints > 0)
                {
                    Vector3 newPoint = TargetUtils.RandomPointInsideBounds(colliders [colliderIndex].GetComponent <Collider> ().bounds);
                    visibilityPoints.Add(newPoint);
                    colliderIndex = (colliderIndex + 1) % colliders.Count;
                    numberofPoints--;
                }
            }
            else                          // if we have more colliders than points, then let's consider the AABB of the target assign points inside it. Not ideal, but...

            {
                while (numberofPoints > 0)
                {
                    Vector3 newPoint = TargetUtils.RandomPointInsideBounds(boundingBox);
                    visibilityPoints.Add(newPoint);
                    numberofPoints--;
                }
            }

            break;
        }


        default:
        {
            Debug.Log("Warning: NO visibility points computed for target " + name);
            break;
        }
        }
    }