/// <summary> /// Inserta el cuerpo con el volúmen especificado en la jerarquía /// </summary> /// <param name="newBody">Cuerpo</param> /// <param name="newVolume">Volúmen</param> public void Insert(RigidBody newBody, BoundingSphere newVolume) { if (this.IsLeaf) { // Si estamos en una rama final, la única opción es crear dos nuevos hijos y poner el nuevo cuerpo en uno de ellos // El primer hijo es una copia de este nodo this.FirstChildren = new BVHNode(this, Volume, Body); // El segundo hijo tiene la información del nuevo cuerpo this.LastChildren = new BVHNode(this, newVolume, newBody); // Limpiamos el cuerpo de esta rama, pues ahora está en el primer hijo this.Body = null; // Recalcular el volumen de este nodo this.RecalculateBoundingVolume(); } else { // Si no somos rama final, hay que decidir qué hijo se quedará con el cuerpo if (this.GetGrowth(this.FirstChildren.Volume, newVolume) < this.GetGrowth(this.LastChildren.Volume, newVolume)) { this.FirstChildren.Insert(newBody, newVolume); } else { this.LastChildren.Insert(newBody, newVolume); } } }
/// <summary> /// Busca los contactos potenciales entre este nodo y el nodo especificado, rellenando la lista de contactos potenciales facilitada, hasta el límite especificado /// </summary> /// <param name="other">Nodo con el que comparar</param> /// <param name="contacts">Lista de contactos poteciales</param> /// <param name="limit">Límite</param> /// <returns>Devuelve el número de contactos potenciales</returns> protected int GetPotentialContactsWith(ref BVHNode other, ref List <PotentialContact> contacts, int limit) { // Si no hay contacto entre los volúmenes superiores o el límite es 0, se termina el proceso if (!this.Overlaps(other) || limit == 0) { return(0); } // Si ambos son ramas finales, hay un contacto potencial if (this.IsLeaf && other.IsLeaf) { contacts.Add(new PotentialContact(this.Body, other.Body)); return(1); } // Determinar por cual nodo descender // Si uno es rama final, se desciende por el otro // Si ambos son ramas intermedias, entonces se debe usar el más grande por ser el más probable if (other.IsLeaf || (!this.IsLeaf && this.Volume.Volume() >= other.Volume.Volume())) { // Bajar por nuestro primer hijo int count = this.FirstChildren.GetPotentialContactsWith(ref other, ref contacts, limit); // Comprobar si tenemos suficiente espacio para continuar añadiendo contactos parciales if (limit > count) { return(count + this.LastChildren.GetPotentialContactsWith(ref other, ref contacts, limit - count)); } else { return(count); } } else { // Bajar por el primer hijo del otro int count = this.GetPotentialContactsWith(ref other.FirstChildren, ref contacts, limit); // Comprobar si queda espacio if (limit > count) { return(count + this.GetPotentialContactsWith(ref other.LastChildren, ref contacts, limit - count)); } else { return(count); } } }
/// <summary> /// Constructor /// </summary> /// <param name="parent">Nodo superior</param> /// <param name="volume">Volumen</param> /// <param name="body">Cuerpo</param> public BVHNode(BVHNode parent, BoundingSphere volume, RigidBody body) { this.Parent = parent; this.Volume = volume; this.Body = body; }
/// <summary> /// Busca contactos entre los nodos de la jerarquía y el nodo especificado /// </summary> /// <param name="other">Nodo con cuyo volúmen se compara</param> /// <returns>Devuelve verdadero si existe contacto</returns> protected bool Overlaps(BVHNode other) { return(this.Volume.Contains(other.Volume) != ContainmentType.Disjoint); }