/// <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; } } }