Partially working AABB Tree! (needs much more work)

This commit is contained in:
2019-02-24 21:51:04 -06:00
parent eeb7a335c1
commit 5cf07ca620
5 changed files with 119 additions and 61 deletions

View File

@@ -63,6 +63,7 @@ require_relative "lib/common_methods"
require_relative "lib/math/vector" require_relative "lib/math/vector"
require_relative "lib/math/bounding_box" require_relative "lib/math/bounding_box"
require_relative "lib/trees/aabb_tree" require_relative "lib/trees/aabb_tree"
require_relative "lib/trees/aabb_node"
require_relative "lib/managers/input_mapper" require_relative "lib/managers/input_mapper"
require_relative "lib/managers/shader_manager" require_relative "lib/managers/shader_manager"

View File

@@ -10,12 +10,14 @@ class IMICFPS
end end
def add(entity) def add(entity)
@aabb_tree.add(entity.normalized_bounding_box, entity) @aabb_tree.insert(entity, entity.normalized_bounding_box)
end end
def update def update
lazy_check_collisions
@aabb_tree.update @aabb_tree.update
check_broadphase
@physics_manager.update @physics_manager.update
end end
@@ -23,25 +25,24 @@ class IMICFPS
@aabb_tree.remove(entity) @aabb_tree.remove(entity)
end end
def lazy_check_collisions def check_broadphase
# Expensive AABB collision detection @collisions.clear
broadphase = {}
@game_state.entities.each do |entity| @game_state.entities.each do |entity|
@game_state.entities.each do |other| search = @aabb_tree.search(entity.normalized_bounding_box)
next if entity == other if search.size > 0
next if entity.is_a?(Terrain) || other.is_a?(Terrain) search.reject! {|ent| ent == entity}
next unless entity.collidable? broadphase[entity] = search
next unless other.collidable? end
end
if entity.normalized_bounding_box.intersect(other.normalized_bounding_box) broadphase.each do |entity, _collisions|
entity.debug_color = Color.new(1.0,0.0,0.0) _collisions.reject! {|ent| !entity.normalized_bounding_box.intersect(ent.normalized_bounding_box)}
other.debug_color = Color.new(1.0,0.0,0.0) # TODO: mesh aabb tree vs other mesh aabb tree check
# TODO: triangle vs other triangle check
# @game_state.entities.delete(entity) unless entity.is_a?(Player) _collisions.each do |ent|
# puts "#{entity} is intersecting #{b}" if entity.is_a?(Player) @collisions[entity] = _collisions
else
entity.debug_color = Color.new(0,1,0)
other.debug_color = Color.new(0,1,0)
end
end end
end end
end end

View File

@@ -6,7 +6,7 @@ class IMICFPS
def update def update
@collision_manager.collisions.each do |entity, versus| @collision_manager.collisions.each do |entity, versus|
versus.each do |versus| versus.each do |other|
resolve(entity, other) resolve(entity, other)
end end
end end

72
lib/trees/aabb_node.rb Normal file
View File

@@ -0,0 +1,72 @@
class IMICFPS
class AABBTree
class AABBNode
attr_accessor :bounding_box, :parent, :object, :a, :b
def initialize(parent:, object:, bounding_box:)
@parent = parent
@object = object
@bounding_box = bounding_box
@a = nil
@b = nil
end
def leaf?
@object
end
def insert_subtree(leaf)
if leaf?
new_node = AABBNode.new(parent: nil, object: nil, bounding_box: @bounding_box.union(leaf.bounding_box))
new_node.a = self
new_node.b = leaf
return new_node
else
cost_a = @b.bounding_box.volume + @a.bounding_box.union(leaf.bounding_box).volume
cost_a = @a.bounding_box.volume + @b.bounding_box.union(leaf.bounding_box).volume
if cost_a < cost_b
self.a = @a.insert_subtree(leaf)
elsif cost_b < cost_a
self.b = @b.insert_subtree(leaf)
else
raise "FIXME"
end
@bounding_box = @bounding_box.union(leaf.bounding_box)
return self
end
end
def search_subtree(bounding_box, items = [])
if @bounding_box.intersect(bounding_box)
if leaf?
items << self
else
@a.search_subtree(bounding_box, items)
@b.search_subtree(bounding_box, items)
end
end
return items
end
def remove_subtree(leaf)
end
def update_bounding_box
node = self
unless node.leaf?
node.bounding_box = node.a.bounding_box.union(node.b.bounding_box)
while(node = node.parent)
node.bounding_box = node.a.bounding_box.union(node.b.bounding_box)
end
end
end
end
end
end

View File

@@ -5,67 +5,51 @@ class IMICFPS
@root = nil @root = nil
end end
def add(bounding_box, object) def insert(object, bounding_box)
raise "BoundingBox can't be nil!" unless bounding_box raise "BoundingBox can't be nil!" unless bounding_box
raise "Object can't be nil!" unless object raise "Object can't be nil!" unless object
raise "Object already in tree!" if @objects[object]
leaf = AABBNode.new(parent: nil, object: object, bounding_box: bounding_box.dup)
@objects[object] = leaf
if @root if @root
@root.insert_subtree(bounding_box.dup, object) @root.insert_subtree(leaf)
else else
@root = AABBNode.new(parent: nil, object: object, bounding_box: BoundingBox.new) @root = leaf
end end
end end
def update def update
needs_update = []
@objects.each do |object, node| @objects.each do |object, node|
unless object.bounding_box == node.bounding_box next unless object.is_a?(Entity)
puts "#{object.class} mutated!" unless object.normalized_bounding_box == node.bounding_box
remove(node) needs_update << object
add(object)
end end
end end
needs_update.each do |object|
remove(object)
insert(object, object.normalized_bounding_box)
end
end end
# Returns a list of all collided objects inside Bounding Box # Returns a list of all collided objects inside Bounding Box
def search(bounding_box) def search(bounding_box)
items = [] items = []
@root.search_subtree(bounding_box) if @root
items = @root.search_subtree(bounding_box)
end
items.map! {|e| e.object}
return items
end end
def remove(object) def remove(object)
@root.remove_subtree(@objects[object]) leaf = @objects.delete(object)
@objects[object] = nil @root.remove_subtree(leaf) if leaf
end
class AABBNode
attr_accessor :bounding_box, :parent, :object, :a, :b
def initialize(parent:, object:, bounding_box:)
@parent = parent
@object = object
@bounding_box = bounding_box
@a = nil
@b = nil
end
def make_leaf
@a = nil
@b = nil
end
def make_branch(node_a, node_b)
end
def insert_subtree(bounding_box, object)
# p "#{bounding_box} -> #{object.class}"
end
def remove_subtree(node)
end
def search_subtree(bounding_box)
end
end end
end end
end end