diff --git a/lib/managers/collision_manager.rb b/lib/managers/collision_manager.rb index e878c06..351e8b1 100644 --- a/lib/managers/collision_manager.rb +++ b/lib/managers/collision_manager.rb @@ -27,10 +27,8 @@ class IMICFPS @physics_manager.update - # binding.irb - # p @aabb_tree collisions.each do |ent, list| - # puts "#{ent.class} -> [#{list.map{|e| e.class}.join(', ')}]" + # puts "#{ent.class} -> [#{list.map{|e| e.class}.join(', ')}] (#{Gosu.milliseconds})" end end @@ -39,6 +37,7 @@ class IMICFPS end def check_broadphase + # FIXME: Cache collisions to speed things up @collisions.clear broadphase = {} @@ -54,13 +53,33 @@ class IMICFPS end broadphase.each do |entity, _collisions| - _collisions.reject! {|ent| !entity.bounding_box.intersect?(ent.bounding_box)} - # TODO: mesh aabb tree vs other mesh aabb tree check - # TODO: triangle vs other triangle check _collisions.each do |ent| + # aabb vs aabb + next unless entity.bounding_box.intersect?(ent.bounding_box) + # entity model aabb tree vs ent model aabb tree + # ent_tree_search = ent.model.aabb_tree.search(localize_entity_bounding_box(entity, ent), true) + # next if ent_tree_search.size == 0 + + # puts "#{ent.class} -> #{ent_tree_search.size} (#{Gosu.milliseconds})" + + # entity.position.y = ent_tree_search.first.object.vertices.first.y if entity.is_a?(Player) && ent.is_a?(Terrain) + @collisions[entity] = _collisions end end end + + # AABBTree on entities is relative to model origin of 0,0,0 + def localize_entity_bounding_box(entity, target) + return entity.bounding_box if target.position == 0 && target.rotation == 0 + + # "tranform" entity bounding box into target's space + local = (target.position) # needs tweaking, works well enough for now + box = entity.bounding_box.clone + box.min -= local + box.max -= local + + return box + end end end diff --git a/lib/math/bounding_box.rb b/lib/math/bounding_box.rb index ba099cb..8e5b448 100644 --- a/lib/math/bounding_box.rb +++ b/lib/math/bounding_box.rb @@ -2,9 +2,9 @@ class IMICFPS class BoundingBox attr_accessor :min, :max - def initialize - @min = Vector.new - @max = Vector.new + def initialize(minx = 0, miny = 0, minz = 0, maxx = 0, maxy = 0, maxz = 0) + @min = Vector.new(minx, miny, minz) + @max = Vector.new(maxx, maxy, maxz) end def ==(other) @@ -116,5 +116,9 @@ class IMICFPS def sum @min.sum + @max.sum end + + def clone + BoundingBox.new(@min.x, @min.y, @min.z, @max.x, @max.y, @max.z) + end end end \ No newline at end of file diff --git a/lib/math/vector.rb b/lib/math/vector.rb index a641def..a42a23a 100644 --- a/lib/math/vector.rb +++ b/lib/math/vector.rb @@ -22,10 +22,17 @@ class IMICFPS # def xyzw=(nx, ny, nz, nw); @x = nx; @y = ny; @z = nz; @weight = nw; end def ==(other) - @x == other.x && - @y == other.y && - @z == other.z && - @weight == other.weight + if other.is_a?(Numeric) + @x == other && + @y == other && + @z == other && + @weight == other + else + @x == other.x && + @y == other.y && + @z == other.z && + @weight == other.weight + end end def +(other) diff --git a/lib/objects/entities/test_object.rb b/lib/objects/entities/test_object.rb index 7444875..e3a5b31 100644 --- a/lib/objects/entities/test_object.rb +++ b/lib/objects/entities/test_object.rb @@ -2,6 +2,7 @@ class IMICFPS class TestObject < Entity def setup bind_model("base", "war_factory") + @backface_culling = false end end end diff --git a/lib/objects/entity.rb b/lib/objects/entity.rb index 177c036..58433dc 100644 --- a/lib/objects/entity.rb +++ b/lib/objects/entity.rb @@ -7,8 +7,8 @@ class IMICFPS include GLU include CommonMethods attr_accessor :scale, :visible, :renderable, :backface_culling - attr_reader :position, :rotation, :velocity, :collision - attr_reader :model, :name, :debug_color, :bounding_box + attr_accessor :position, :rotation, :velocity + attr_reader :model, :name, :debug_color, :bounding_box, :collision def initialize(x: 0, y: 0, z: 0, bound_model: nil, scale: MODEL_METER_SCALE, backface_culling: true, auto_manage: true, manifest_file: nil) @position = Vector.new(x, y, z) @scale = scale diff --git a/lib/renderer/bounding_box_renderer.rb b/lib/renderer/bounding_box_renderer.rb index 482be96..0a26cb4 100644 --- a/lib/renderer/bounding_box_renderer.rb +++ b/lib/renderer/bounding_box_renderer.rb @@ -32,7 +32,6 @@ class IMICFPS return end end - @bounding_boxes[mesh_object_id] = {} @bounding_boxes[mesh_object_id] = {object: object, box: box, color: color, objects: []} box = object.normalize_bounding_box diff --git a/lib/renderer/opengl_renderer.rb b/lib/renderer/opengl_renderer.rb index b952420..3f1b4df 100644 --- a/lib/renderer/opengl_renderer.rb +++ b/lib/renderer/opengl_renderer.rb @@ -57,7 +57,7 @@ class IMICFPS glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_COLOR_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) - if model.model_has_texture + if model.has_texture? glEnable(GL_TEXTURE_2D) glBindTexture(GL_TEXTURE_2D, model.materials[model.textured_material].texture_id) glEnableClientState(GL_TEXTURE_COORD_ARRAY) @@ -96,7 +96,7 @@ class IMICFPS glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) glDisableClientState(GL_NORMAL_ARRAY) - if model.model_has_texture + if model.has_texture? glDisableClientState(GL_TEXTURE_COORD_ARRAY) # glBindTexture(GL_TEXTURE_2D, 0) glDisable(GL_TEXTURE_2D) diff --git a/lib/trees/aabb_tree.rb b/lib/trees/aabb_tree.rb index ec29f8b..49b6e95 100644 --- a/lib/trees/aabb_tree.rb +++ b/lib/trees/aabb_tree.rb @@ -36,11 +36,11 @@ class IMICFPS end # Returns a list of all collided objects inside Bounding Box - def search(bounding_box) + def search(bounding_box, return_nodes = false) items = [] if @root items = @root.search_subtree(bounding_box) - items.map! {|e| e.object} + items.map! {|e| e.object} unless return_nodes end return items diff --git a/lib/wavefront/model.rb b/lib/wavefront/model.rb index f75dffa..051293c 100644 --- a/lib/wavefront/model.rb +++ b/lib/wavefront/model.rb @@ -12,11 +12,12 @@ class IMICFPS attr_accessor :objects, :materials, :vertices, :texures, :normals, :faces attr_accessor :scale, :entity - attr_reader :position, :bounding_box, :model_has_texture, :textured_material + attr_reader :position, :bounding_box, :textured_material attr_reader :normals_buffer, :uvs_buffer, :vertices_buffer attr_reader :vertices_buffer_data, :uvs_buffer_data, :normals_buffer_data attr_reader :vertex_array_id + attr_reader :aabb_tree def initialize(file_path:, entity: nil) @entity = entity @@ -42,39 +43,24 @@ class IMICFPS puts "#{@file_path.split('/').last} took #{((Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)-start_time)/1000.0).round(2)} seconds to parse" if $debug - allocate_gl_objects - populate_buffers - populate_arrays + # allocate_gl_objects + # populate_buffers + # populate_arrays @objects.each {|o| @vertex_count+=o.vertices.size} @objects.each_with_index do |o, i| puts " Model::Object Name: #{o.name}, Vertices: #{o.vertices.size}" if $debug end window.number_of_vertices+=@vertex_count - @model_has_texture = false + @has_texture = false @materials.each do |key, material| if material.texture_id - @model_has_texture = true + @has_texture = true @textured_material = key end end - @aabb_tree = AABBTree.new - @faces.each do |face| - box = BoundingBox.new - box.min = face.vertices.first.dup - box.max = face.vertices.first.dup - - face.vertices.each do |vertex| - if vertex.sum < box.min.sum - box.min = vertex.dup - elsif vertex.sum > box.max.sum - box.max = vertex.dup - end - end - - @aabb_tree.insert(face, box) - end + build_collision_tree end def allocate_gl_objects @@ -124,13 +110,36 @@ class IMICFPS glBindBuffer(GL_ARRAY_BUFFER, 0) end + def build_collision_tree + @aabb_tree = AABBTree.new + @faces.each do |face| + box = BoundingBox.new + box.min = face.vertices.first.dup + box.max = face.vertices.first.dup + + face.vertices.each do |vertex| + if vertex.sum < box.min.sum + box.min = vertex.dup + elsif vertex.sum > box.max.sum + box.max = vertex.dup + end + end + + # FIXME: Handle negatives + box.min -= Vector.new(-0.1, -0.1, -0.1) + box.max += Vector.new( 0.1, 0.1, 0.1) + @aabb_tree.insert(face, box) + end + puts @aabb_tree.inspect if $debug + end + def update @position = @entity.position @scale = @entity.scale - # if @scale != @entity.scale - # puts "oops for #{self}: #{@scale} != #{@entity.scale}" - # self.objects.each(&:reflatten) if self.objects && self.objects.count > 0 - # end + end + + def has_texture? + @has_texture end end end