From 7271c0e4a1a05195f352877eb4feb1170bb516ce Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Sun, 9 Dec 2018 21:17:12 -0600 Subject: [PATCH] Fixed bounding box rendering! fixed AABB collision detection (was a bit weird), misc. tweaks and fixes. --- Gemfile.lock | 6 +- lib/objects/game_object.rb | 32 ++++-- lib/objects/model_loader.rb | 2 +- lib/renderer/bounding_box_renderer.rb | 143 ++++++++++++++++---------- lib/renderer/opengl_renderer.rb | 10 +- lib/renderer/renderer.rb | 16 +-- lib/states/game_states/game.rb | 28 +++-- lib/wavefront/model.rb | 26 +++++ lib/wavefront/object.rb | 2 +- 9 files changed, 175 insertions(+), 90 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index d80565f..2f1a19f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,8 +3,8 @@ GEM specs: glu (8.2.2) glu (8.2.2-x86-mingw32) - gosu (0.14.0) - gosu (0.14.0-x86-mingw32) + gosu (0.14.4) + gosu (0.14.4-x86-mingw32) opengl-bindings (1.6.7) PLATFORMS @@ -17,4 +17,4 @@ DEPENDENCIES opengl-bindings BUNDLED WITH - 1.16.4 + 1.16.6 diff --git a/lib/objects/game_object.rb b/lib/objects/game_object.rb index b4d494e..568f265 100644 --- a/lib/objects/game_object.rb +++ b/lib/objects/game_object.rb @@ -64,21 +64,25 @@ class IMICFPS def draw end + def update model.update @delta_time = Gosu.milliseconds end + def debug_color=(color) + @debug_color = color + end + # Do two Axis Aligned Bounding Boxes intersect? def intersect(a, b) - a = a.normalize_bounding_box(a.model.bounding_box) - b = b.normalize_bounding_box(b.model.bounding_box) + a = a.normalize_bounding_box_with_offset(a.model.bounding_box) + b = b.normalize_bounding_box_with_offset(b.model.bounding_box) - puts "bounding boxes match!" if a == b - if (((a.min_x <= b.min_x && b.max_x <= a.max_x) || (b.min_x <= a.min_x && a.min_x <= b.max_x)) && - ((a.min_y <= b.min_y && b.max_y <= a.max_y) || (b.min_y <= a.min_y && a.min_y <= b.max_y)) && - ((a.min_z <= b.min_z && b.max_z <= a.max_z) || (b.min_z <= a.min_z && a.min_z <= b.max_z))) - # if (a.max_x >= b.max_x && a.min_x <= b.max_x) && (a.max_y >= b.min_y && a.min_y <= b.max_y) && (a.max_z >= b.min_z && a.min_z <= b.max_z) + # puts "bounding boxes match!" if a == b + if (a.min_x <= b.max_x && a.max_x >= b.min_x) && + (a.min_y <= b.max_y && a.max_y >= b.min_y) && + (a.min_z <= b.max_z && a.max_z >= b.min_z) return true else return false @@ -86,6 +90,19 @@ class IMICFPS end def normalize_bounding_box(box) + temp = BoundingBox.new + temp.min_x = box.min_x.to_f*scale + temp.min_y = box.min_y.to_f*scale + temp.min_z = box.min_z.to_f*scale + + temp.max_x = box.max_x.to_f*scale + temp.max_y = box.max_y.to_f*scale + temp.max_z = box.max_z.to_f*scale + + return temp + end + + def normalize_bounding_box_with_offset(box) temp = BoundingBox.new temp.min_x = box.min_x.to_f*scale+x temp.min_y = box.min_y.to_f*scale+y @@ -95,7 +112,6 @@ class IMICFPS temp.max_y = box.max_y.to_f*scale+y temp.max_z = box.max_z.to_f*scale+z - # puts "b: #{box}, Temp: #{temp}" return temp end diff --git a/lib/objects/model_loader.rb b/lib/objects/model_loader.rb index d4028b7..0ddb28e 100644 --- a/lib/objects/model_loader.rb +++ b/lib/objects/model_loader.rb @@ -36,7 +36,7 @@ class IMICFPS found = false if CACHE[@type].is_a?(Hash) if CACHE[@type][@file_path] - @model = CACHE[@type][@file_path].dup # Don't know why, but adding .dup improves performance with Sponza (1 fps -> 20 fps) + @model = CACHE[@type][@file_path]#.dup # Don't know why, but adding .dup improves performance with Sponza (1 fps -> 20 fps) puts "Used cached model for: #{@file_path.split('/').last}" found = true end diff --git a/lib/renderer/bounding_box_renderer.rb b/lib/renderer/bounding_box_renderer.rb index 2422493..70f3517 100644 --- a/lib/renderer/bounding_box_renderer.rb +++ b/lib/renderer/bounding_box_renderer.rb @@ -3,9 +3,10 @@ class IMICFPS include OpenGL include GLU - attr_reader :bounding_boxes + attr_reader :bounding_boxes, :vertex_count def initialize - @bounding_boxes = {normals: [], colors: [], vertices: []} + @bounding_boxes = {} + @vertex_count = 0 end def handleGlError @@ -16,15 +17,25 @@ class IMICFPS end end - def create_bounding_box(object, box, color = nil) + def create_bounding_box(object, box, color = nil, mesh_object_id) color ||= object.debug_color + + if @bounding_boxes[mesh_object_id] + if @bounding_boxes[mesh_object_id][:color] != color + update_mesh_colors(mesh_object_id, color) + return + else + return + end + end + @bounding_boxes[mesh_object_id] = {} + @bounding_boxes[mesh_object_id] = {object: object, box: box, color: color} + box = object.normalize_bounding_box(box) - @bounding_boxes[:normals] ||= [] - @bounding_boxes[:colors] ||= [] - @bounding_boxes[:vertices] ||= [] + update_mesh_colors(mesh_object_id, color) - @bounding_boxes[:normals] << [ + normals = [ 0,1,0, 0,1,0, 0,1,0, @@ -68,45 +79,7 @@ class IMICFPS -1,0,0, -1,0,0 ] - @bounding_boxes[:colors] << [ - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue, - color.red, color.green, color.blue - ] - @bounding_boxes[:vertices] << [ + vertices = [ box.min_x, box.max_y, box.max_z, box.min_x, box.max_y, box.min_z, box.max_x, box.max_y, box.min_z, @@ -155,25 +128,83 @@ class IMICFPS box.min_x, box.max_y, box.min_z, box.max_x, box.max_y, box.min_z ] + + @vertex_count+=vertices.size + + @bounding_boxes[mesh_object_id][:vertices_size] = vertices.size + @bounding_boxes[mesh_object_id][:vertices] = vertices.pack("f*") + @bounding_boxes[mesh_object_id][:normals] = normals.pack("f*") + end + + def update_mesh_colors(mesh_object_id, color) + @bounding_boxes[mesh_object_id][:colors] = [ + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue, + color.red, color.green, color.blue + ].pack("f*") + + @bounding_boxes[mesh_object_id][:color] = color end def draw_bounding_boxes + @bounding_boxes.each do |key, bounding_box| + glPushMatrix + + glTranslatef(bounding_box[:object].x, bounding_box[:object].y, bounding_box[:object].z) + draw_bounding_box(bounding_box) + + glPopMatrix + + found = ObjectManager.objects.detect { |o| o == bounding_box[:object] } + @bounding_boxes.delete(key) unless found + end + end + + def draw_bounding_box(bounding_box) glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_COLOR_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) - _normals = @bounding_boxes[:normals].flatten.pack("f*") - _colors = @bounding_boxes[:colors].flatten.pack("f*") - _vertices_size = @bounding_boxes[:vertices].size - _vertices = @bounding_boxes[:vertices].flatten.pack("f*") - - glVertexPointer(3, GL_FLOAT, 0, _vertices) - glColorPointer(3, GL_FLOAT, 0, _colors) - glNormalPointer(GL_FLOAT, 0, _normals) + glVertexPointer(3, GL_FLOAT, 0, bounding_box[:vertices]) + glColorPointer(3, GL_FLOAT, 0, bounding_box[:colors]) + glNormalPointer(GL_FLOAT, 0, bounding_box[:normals]) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glDisable(GL_LIGHTING) - glDrawArrays(GL_TRIANGLES, 0, _vertices_size/3) + glDrawArrays(GL_TRIANGLES, 0, bounding_box[:vertices_size]/3) glEnable(GL_LIGHTING) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) @@ -182,4 +213,4 @@ class IMICFPS glDisableClientState(GL_NORMAL_ARRAY) end end -end \ No newline at end of file +end diff --git a/lib/renderer/opengl_renderer.rb b/lib/renderer/opengl_renderer.rb index 2179535..2d30296 100644 --- a/lib/renderer/opengl_renderer.rb +++ b/lib/renderer/opengl_renderer.rb @@ -19,9 +19,6 @@ class IMICFPS glEnable(GL_NORMALIZE) glPushMatrix - # Render bounding boxes before transformation is applied - create_bounding_box(object, object.model.bounding_box) if $debug - object.model.objects.each {|o| create_bounding_box(object, o.bounding_box, o.debug_color)} if $debug glTranslatef(object.x, object.y, object.z) glRotatef(object.x_rotation,1.0, 0, 0) @@ -59,9 +56,7 @@ class IMICFPS glColorPointer(3, GL_FLOAT, 0, o.flattened_materials) glNormalPointer(GL_FLOAT, 0, o.flattened_normals) - glDrawArrays(GL_TRIANGLES, 0, o.flattened_vertices_size/4) - - if $debug + if $debug # This is kinda expensive glDisable(GL_LIGHTING) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glPolygonOffset(2, 0.5) @@ -71,6 +66,9 @@ class IMICFPS glPolygonOffset(0, 0) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glEnable(GL_LIGHTING) + glDrawArrays(GL_TRIANGLES, 0, o.flattened_vertices_size/4) + else + glDrawArrays(GL_TRIANGLES, 0, o.flattened_vertices_size/4) end glDisableClientState(GL_VERTEX_ARRAY) diff --git a/lib/renderer/renderer.rb b/lib/renderer/renderer.rb index 249cccd..9ad480b 100644 --- a/lib/renderer/renderer.rb +++ b/lib/renderer/renderer.rb @@ -11,16 +11,20 @@ class IMICFPS end def draw - @bounding_box_renderer.draw_bounding_boxes if $debug - $window.number_of_faces+=@bounding_box_renderer.bounding_boxes[:vertices].size/3 if $debug - @bounding_box_renderer.bounding_boxes.clear - - ObjectManager.objects.each do |object| if object.visible && object.renderable + # Render bounding boxes before transformation is applied + @bounding_box_renderer.create_bounding_box(object, object.model.bounding_box, object.debug_color, object.object_id) if $debug + object.model.objects.each {|o| @bounding_box_renderer.create_bounding_box(object, o.bounding_box, o.debug_color, o.object_id)} if $debug + @opengl_renderer.draw_object(object) end end + + @bounding_box_renderer.draw_bounding_boxes if $debug + $window.number_of_faces+=$window.number_of_faces if $debug + $window.number_of_faces+=@bounding_box_renderer.vertex_count/3 if $debug + # @bounding_box_renderer.bounding_boxes.clear end def handleGlError @@ -34,4 +38,4 @@ class IMICFPS def finalize # cleanup end end -end \ No newline at end of file +end diff --git a/lib/states/game_states/game.rb b/lib/states/game_states/game.rb index 0d51c74..82f2be2 100644 --- a/lib/states/game_states/game.rb +++ b/lib/states/game_states/game.rb @@ -100,15 +100,25 @@ eos end @text.text = string - # ObjectManager.objects.each do |object| - # ObjectManager.objects.each do |b| - # next if b == object - # if object.intersect(object, b) - # # puts "#{object} is intersecting #{b}" - # end - # end - # object.update - # end + ObjectManager.objects.each do |object| + ObjectManager.objects.each do |b| + next if b == object + next if object.is_a?(Terrain) + next if b.is_a?(Terrain) + + if object.intersect(object, b) + object.debug_color = Color.new(1.0,0.0,0.0) + b.debug_color = Color.new(1.0,0.0,0.0) + + # ObjectManager.objects.delete(object) + # puts "#{object} is intersecting #{b}" if object.is_a?(Player) + else + object.debug_color = Color.new(0,1,0) + b.debug_color = Color.new(0,1,0) + end + end + end + ObjectManager.objects.each(&:update) @skydome.update if @skydome.renderable diff --git a/lib/wavefront/model.rb b/lib/wavefront/model.rb index 107597c..77bdc51 100644 --- a/lib/wavefront/model.rb +++ b/lib/wavefront/model.rb @@ -13,6 +13,7 @@ class IMICFPS attr_accessor :objects, :materials, :vertices, :texures, :normals, :faces attr_accessor :x, :y, :z, :scale, :game_object attr_reader :bounding_box, :model_has_texture, :textured_material + attr_reader :normals_buffer, :colors_buffer, :vertices_buffer def initialize(file_path:, game_object: nil) @game_object = game_object @@ -31,11 +32,27 @@ class IMICFPS @faces = [] @smoothing= 0 + # Allocate buffers for future use + @normals_buffer, @colors_buffer, @vertices_buffer = nil + buffer = " " * 4 + glGenBuffers(1, buffer) + @normals_buffer = buffer.unpack('L2').first + + buffer = " " * 4 + glGenBuffers(1, buffer) + @colors_buffer = buffer.unpack('L2').first + + buffer = " " * 4 + glGenBuffers(1, buffer) + @vertices_buffer = buffer.unpack('L2').first + @bounding_box = BoundingBox.new(0,0,0, 0,0,0) start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) parse puts "#{@file_path.split('/').last} took #{((Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)-start_time)/1000.0).round(2)} seconds to parse" + # populate_buffers + face_count = 0 @objects.each {|o| face_count+=o.faces.size} @objects.each_with_index do |o, i| @@ -51,6 +68,15 @@ class IMICFPS end end + def populate_buffers + glBindBuffer(GL_ARRAY_BUFFER, @normals_buffer) + glBufferData(GL_ARRAY_BUFFER, @vertices.size, @vertices.flatten.pack("f*"), GL_STATIC_DRAW) + + glBindBuffer(GL_ARRAY_BUFFER, @colors_buffer) + glBindBuffer(GL_ARRAY_BUFFER, @vertices_buffer) + + end + def update @x, @y, @z = @game_object.x, @game_object.y, @game_object.z @scale = @game_object.scale diff --git a/lib/wavefront/object.rb b/lib/wavefront/object.rb index de203d5..2d46b74 100644 --- a/lib/wavefront/object.rb +++ b/lib/wavefront/object.rb @@ -38,7 +38,7 @@ class IMICFPS def at_same_position? if @x == @parent.x - if @x == @parent.x + if @y == @parent.y if @z == @parent.z true end