/// <summary> /// Registers the specified object with the tree. /// </summary> private bool RegisterGameObject(GameObject gameObject) { if (!CanGameObjectBeRegisteredWithTree(gameObject)) { return(false); } // Build the object's sphere Box objectWorldBox = gameObject.GetWorldBox(); Sphere3D objectSphere = objectWorldBox.GetEncapsulatingSphere(); // Add the object as a terminal node. Also store the node in the dictionary so that we can // use it when it's needed. SphereTreeNode <GameObject> objectNode = _sphereTree.AddTerminalNode(objectSphere, gameObject); _gameObjectToNode.Add(gameObject, objectNode); #if !USE_TRANSFORM_HAS_CHANGED _gameObjectToTransformData.Add(gameObject, GetGameObjectTransformData(gameObject)); #endif // If it is a mesh object, start silent building the mesh if (gameObject.HasMesh()) { EditorMesh editorMesh = EditorMeshDatabase.Instance.CreateEditorMesh(gameObject.GetMesh()); if (editorMesh != null) { EditorMeshDatabase.Instance.AddMeshToSilentBuild(editorMesh); } } EditorCamera.Instance.AdjustObjectVisibility(gameObject); return(true); }
/// <summary> /// Returns a list that contains all terminal nodes that intersect or are fully /// encapsulated by the specified sphere. /// </summary> public List <SphereTreeNode <T> > OverlapSphere(Sphere3D sphere) { var overlappedTerminalNodes = new List <SphereTreeNode <T> >(20); OverlapSphereRecurse(sphere, _rootNode, overlappedTerminalNodes); return(overlappedTerminalNodes); }
/// <summary> /// Recursive method which is used to step down the tree hierarchy collecting all terminal nodes /// which are overlapped by the specified sphere. /// </summary> private void OverlapSphereRecurse(Sphere3D sphere, SphereTreeNode <T> parentNode, List <SphereTreeNode <T> > overlappedTerminalNodes) { // If the parent is not overlapped there is no need to go any further if (!parentNode.Sphere.OverlapsFullyOrPartially(sphere)) { return; } else { // If this is a terminal node, add it to the output list and return if (parentNode.IsTerminal) { overlappedTerminalNodes.Add(parentNode); return; } else { // Recurs for each child node List <SphereTreeNode <T> > childNodes = parentNode.Children; foreach (SphereTreeNode <T> childNode in childNodes) { OverlapSphereRecurse(sphere, childNode, overlappedTerminalNodes); } } } }
/// <summary> /// Adds a terminal node to the tree. /// </summary> /// <remarks> /// The function does not integrate the node inside the sphere hierarchy. It /// will only add it to the integration pending queue. The actual integration /// process will be performed inside 'PerformPendingUpdates'. /// </remarks> /// <param name="sphere"> /// The node's sphere. /// </param> /// <param name="data"> /// The node's data. /// </param> /// <returns> /// The node which was added to the tree. /// </returns> public SphereTreeNode <T> AddTerminalNode(Sphere3D sphere, T data) { // Create a new node and mark it as terminal var newTerminalNode = new SphereTreeNode <T>(sphere, this, data); newTerminalNode.SetFlag(SphereTreeNodeFlags.Terminal); // Add the node to the integration queue AddNodeToIntegrationQueue(newTerminalNode); return(newTerminalNode); }
public bool OverlapsFullyOrPartially(Sphere3D sphere) { float distanceBetweenCenters = GetDistanceBetweenCenters(sphere); // Fully? if (distanceBetweenCenters + sphere.Radius <= _radius) { return(true); } // Partially? return(distanceBetweenCenters - sphere.Radius <= _radius); }
public Sphere3D Encapsulate(Sphere3D sphere) { float distanceBetweenCenters = GetDistanceBetweenCenters(sphere); float newDiameter = distanceBetweenCenters + _radius + sphere.Radius; float newRadius = newDiameter * 0.5f; Vector3 fromThisToOther = sphere.Center - Center; fromThisToOther.Normalize(); Vector3 newCenter = Center - fromThisToOther * _radius + fromThisToOther * newRadius; return(new Sphere3D(newCenter, newRadius)); }
/// <summary> /// Handles the transform change for the specified object transform. /// </summary> private void HandleObjectTransformChange(Transform gameObjectTransform) { // Just ensure that the object is registered with the tree GameObject gameObject = gameObjectTransform.gameObject; if (!IsGameObjectRegistered(gameObject)) { return; } // Store the object's node for easy access. We will need to instruct the // tree to update this node as needed. SphereTreeNode <GameObject> objectNode = _gameObjectToNode[gameObject]; // We will first have to detect what has changed. So we will compare the // object's sphere as it is now with what was before. bool updateCenter = false; bool updateRadius = false; Sphere3D previousSphere = objectNode.Sphere; Sphere3D currentSphere = gameObject.GetWorldBox().GetEncapsulatingSphere(); // Detect what changed if (previousSphere.Center != currentSphere.Center) { updateCenter = true; } if (previousSphere.Radius != currentSphere.Radius) { updateRadius = true; } // Call the appropriate node update method if (updateCenter && updateRadius) { _sphereTree.UpdateTerminalNodeCenterAndRadius(objectNode, currentSphere.Center, currentSphere.Radius); } else if (updateCenter) { _sphereTree.UpdateTerminalNodeCenter(objectNode, currentSphere.Center); } else if (updateRadius) { _sphereTree.UpdateTerminalNodeRadius(objectNode, currentSphere.Radius); } EditorCamera.Instance.AdjustObjectVisibility(gameObject); }
/// <summary> /// Returns a list of all objects which are overlapped by the specified sphere. /// </summary> /// <param name="sphere"> /// The sphere involved in the overlap query. /// </param> /// <param name="objectOverlapPrecision"> /// The desired overlap precision. For the moment this is not used. /// </param> public List <GameObject> OverlapSphere(Sphere3D sphere, ObjectOverlapPrecision objectOverlapPrecision = ObjectOverlapPrecision.ObjectBox) { // Retrieve all the sphere tree nodes which are overlapped by the sphere. If no nodes are overlapped, // we can return an empty list because it means that no objects could possibly be overlapped either. List <SphereTreeNode <GameObject> > allOverlappedNodes = _sphereTree.OverlapSphere(sphere); if (allOverlappedNodes.Count == 0) { return(new List <GameObject>()); } // Loop through all overlapped nodes var overlappedObjects = new List <GameObject>(); foreach (SphereTreeNode <GameObject> node in allOverlappedNodes) { // Store the node's object for easy access GameObject gameObject = node.Data; // Note: It is important to check for null because the object may have been destroyed. 'RemoveNullObjectNodes' // removes null objects but given the order in which Unity calls certain key functions such as 'OnSceneGUI' // and any editor registered callbacks, null object references can still pop up. if (gameObject == null) { continue; } if (!gameObject.activeSelf) { continue; } // We need to perform an additional check. Even though the sphere overlaps the object's node (which is // another sphere), we must also check if the sphere overlaps the object's world oriented box. This allows // for better precision. OrientedBox objectWorldOrientedBox = gameObject.GetWorldOrientedBox(); if (sphere.OverlapsFullyOrPartially(objectWorldOrientedBox)) { overlappedObjects.Add(gameObject); } } return(overlappedObjects); }
public List <GameObject> OverlapSphere(Sphere3D sphere, ObjectOverlapPrecision overlapPrecision = ObjectOverlapPrecision.ObjectBox) { return(_gameObjectSphereTree.OverlapSphere(sphere, overlapPrecision)); }
public SphereTreeNode(Sphere3D sphere, SphereTree <T> tree, T data = default(T)) { _tree = tree; _data = data; _sphere = sphere; }
public void Encapsulate(SphereTreeNode <T> node) { _sphere = _sphere.Encapsulate(node.Sphere); }
public float GetDistanceBetweenCentersSq(Sphere3D sphere) { return((Center - sphere.Center).sqrMagnitude); }
public float GetDistanceBetweenCenters(Sphere3D sphere) { return((_center - sphere.Center).magnitude); }
public Sphere3D(Sphere3D source) { _radius = source._radius; _center = source._center; }
public bool FullyOverlaps(Sphere3D sphere) { return(GetDistanceBetweenCenters(sphere) + sphere.Radius <= _radius); }