bulldog_physics 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,18 +29,18 @@ module BulldogPhysics
29
29
  end
30
30
 
31
31
  def calculate_separating_velocity
32
- relative_velocity = @particle1.velocity
32
+ relative_velocity = @particle1.velocity.dup
33
33
  unless @particle2.nil?
34
34
  relative_velocity -= @particle2.velocity
35
35
  end
36
- return relative_velocity.scalarProduct(@contact_normal)
36
+ return relative_velocity * @contact_normal
37
37
  end
38
38
 
39
39
 
40
40
  private
41
41
 
42
42
  def resolve_velocity(duration)
43
-
43
+
44
44
  #Find the velocity in the direction of the contact.
45
45
  separating_velocity = calculate_separating_velocity()
46
46
 
@@ -49,19 +49,32 @@ module BulldogPhysics
49
49
  # The contact is either separating, or stationary; there’s no impulse required.
50
50
  return
51
51
  end
52
+
52
53
  new_sep_velocity = -separating_velocity * @restitution
54
+
55
+
56
+ acc_caused_velocity = @particle1.acceleration.dup
57
+
58
+ unless @particle2.nil?
59
+ acc_caused_velocity -= @particle2.acceleration
60
+ end
61
+
62
+ acc_caused_velocity = acc_caused_velocity * @contact_normal * duration;
63
+
64
+ if acc_caused_velocity < 0
65
+ new_sep_velocity += @restitution * acc_caused_velocity
66
+ new_sep_velocity = 0 if new_sep_velocity < 0
67
+ end
68
+
53
69
  delta_velocity = new_sep_velocity - separating_velocity
54
-
55
70
  total_inverse_mass = @particle1.inverse_mass
56
-
57
-
71
+
72
+
58
73
  unless( @particle2.nil? )
59
74
  total_inverse_mass += @particle2.inverse_mass
60
75
  end
61
76
 
62
- if( total_inverse_mass <= 0)
63
- return
64
- end
77
+ return if( total_inverse_mass <= 0)
65
78
 
66
79
  impulse = delta_velocity / total_inverse_mass
67
80
 
@@ -76,9 +89,9 @@ module BulldogPhysics
76
89
  end
77
90
 
78
91
  def resolve_interpenetration(duration)
79
- if(@penetration <= 0)
80
- return
81
- end
92
+
93
+ return if(@penetration <= 0)
94
+
82
95
 
83
96
  total_inverse_mass = @particle1.inverse_mass
84
97
  unless( @particle2.nil? )
@@ -24,15 +24,15 @@ module BulldogPhysics
24
24
 
25
25
  contact_array.each_with_index do |contact, i|
26
26
  sep_vel = contact.calculate_separating_velocity
27
- if( sep_vel < max and ( sep_vel < 0 or contact.penetration > 0) )
27
+ if( sep_vel < max && ( sep_vel < 0 || contact.penetration > 0) )
28
28
  max = sep_vel
29
29
  max_index = i
30
30
  end
31
31
  end
32
32
 
33
- if( max_index.eql? num_contacts)
34
- break
35
- end
33
+
34
+ break if( max_index.eql? num_contacts)
35
+
36
36
 
37
37
  contact_array[max_index].resolve(duration)
38
38
 
@@ -13,7 +13,7 @@ module BulldogPhysics
13
13
  end
14
14
 
15
15
  def update_force(particle, duration)
16
- force = particle.velocity
16
+ force = particle.velocity.dup
17
17
 
18
18
  dragCoeff = force.magnitude
19
19
 
@@ -1,4 +1,4 @@
1
- module BulldogPhysics
1
+ module BulldogPhysics
2
2
  module Particles
3
3
  module Collisions
4
4
 
@@ -19,8 +19,8 @@ module BulldogPhysics
19
19
 
20
20
  # * Fills the given contact structure with the contact needed to keep the rod from extending or compressing.
21
21
  def add_contact(contactArray, limit)
22
- current_len = (@particle1.position - @particle2.position).magnitude
23
-
22
+ current_len = current_length
23
+
24
24
  if( current_len == @length)
25
25
  return 0
26
26
  end
@@ -28,18 +28,19 @@ module BulldogPhysics
28
28
 
29
29
  contact = ParticleContact.new(@particle1, @particle2)
30
30
 
31
-
31
+ normal = @particle2.position - @particle1.position
32
+ normal.normalize
32
33
  # The contact normal depends on whether we’re extending or compressing.
33
34
 
35
+ contact.contact_normal = normal
36
+
34
37
  if( current_len > @length)
35
38
  contact.penetration = (current_len - @length)
36
- #contact.penetration = -1
37
39
  else
38
40
  contact.contact_normal *= -1
39
41
  contact.penetration = @length - current_len
40
- #contact.penetration = 1
41
42
  end
42
-
43
+
43
44
  contact.restitution = 0
44
45
  contactArray << contact
45
46
 
@@ -29,6 +29,7 @@ module BulldogPhysics
29
29
  # give a number of contact-resolution iterations to use. If you * don’t give a number of iterations, then twice the number of
30
30
  # contacts will be used.
31
31
  def initialize(max_contacts = 100, iterations = 1)
32
+ puts "INIT WORLD"
32
33
  @max_contacts = max_contacts
33
34
  @calculate_iterations = iterations
34
35
  @particles = Array.new
@@ -0,0 +1,18 @@
1
+ module BulldogPhysics
2
+ class Gravity < ForceGenerator
3
+
4
+ attr :gravity # vector3 accel do to gravity
5
+
6
+ def initialize(grav)
7
+ @gravity = grav
8
+ end
9
+
10
+ def update_force(body, duration)
11
+ #return if body.hasFiniteMass
12
+
13
+ body.add_force(gravity * body.mass)
14
+ end
15
+
16
+
17
+ end
18
+ end
@@ -0,0 +1,32 @@
1
+ module BulldogPhysics
2
+ class Buoyancy < ForceGenerator
3
+
4
+ attr_accessor :max_depth, :volume, :water_height, :liquid_density, :center_of_buoyancy
5
+
6
+ def initialize(c_of_b, max_depth, volume, water_height, liquid_density = 1000.0)
7
+ @center_of_buoyancy, @max_depth, @volume, @water_height, @liquid_density =
8
+ c_of_b, max_depth, volume, water_height, liquid_density
9
+ end
10
+
11
+ def update_force(body, duration)
12
+ point_in_world = body.get_point_in_world_space(@center_of_buoyancy)
13
+ depth = point_in_world.y
14
+
15
+ if(depth >= @water_height + @max_depth)
16
+ return
17
+ end
18
+
19
+ force = Vector3.new
20
+
21
+ if depth <= @water_height - @max_depth
22
+ force.y = @liquid_density * @volume
23
+ body.add_force_at_point(force, @center_of_buoyancy)
24
+ return
25
+ end
26
+
27
+ force.y = @liquid_density * @volume * (depth - @max_depth - @water_height) / (2 * @max_depth)
28
+ body.add_force_at_point(force, @center_of_buoyancy)
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,256 @@
1
+ module BulldogPhysics
2
+
3
+ class CollisionPrimitive
4
+
5
+ attr_accessor :body, :offset
6
+
7
+
8
+ def initialize()
9
+ #puts "INIT"
10
+ @body = RigidBody.new
11
+ @offset = Matrix4.new
12
+ @transform = Matrix4.new
13
+ end
14
+
15
+ attr :transform
16
+
17
+ def calculate_internals()
18
+ #puts "OFFSET #{@offset}"
19
+ @transform = @body.transform_matrix * @offset
20
+ end
21
+
22
+ def get_axis(index)
23
+ @transform.getAxisVector(index)
24
+ end
25
+
26
+ def get_transform
27
+ @transform
28
+ end
29
+ end
30
+
31
+
32
+ class CollisionSphere < CollisionPrimitive
33
+ attr_accessor :radius
34
+
35
+ def initialize()
36
+ super()
37
+ @radius = 1
38
+ end
39
+ end
40
+
41
+
42
+ class CollisionPlane
43
+ attr_accessor :direction, :offset
44
+
45
+ def initialize(direction = Vector3.new, offset = 0.0)
46
+ @direction = direction
47
+ @offset = offset
48
+ end
49
+ end
50
+
51
+ class CollisionBox < CollisionPrimitive
52
+
53
+ attr_accessor :half_size
54
+
55
+ def initialize(half_size = Vector3.new)
56
+ super()
57
+ @half_size = half_size
58
+ end
59
+ end
60
+
61
+
62
+ class CollisionData
63
+ attr_accessor :contacts, :current_contact, :contacts_count, :friction, :restitution, :tolerance, :contacts_left
64
+
65
+ def initialize()
66
+ @contacts = Array.new
67
+ @current_contact = @contacts_count = @contacts_left = 0
68
+ @friction = @restitution = @tolerance = 0.0
69
+ end
70
+
71
+ def has_more_contacts()
72
+ @contacts_left > 0
73
+ end
74
+
75
+ def reset(max_contacts)
76
+ @contacts_left = max_contacts
77
+ @contacts_count = 0
78
+ @current_contact = 0
79
+ end
80
+
81
+ def add_contacts(count)
82
+ @contacts_left -= count
83
+ @contacts_count += count
84
+
85
+ @current_contact += count
86
+ end
87
+
88
+ end
89
+
90
+ def transform_to_axis(box, axis)
91
+ return box.half_size.x * (axis * box.get_axis(0)).abs + \
92
+ box.half_size.y * (axis * box.get_axis(1)).abs + \
93
+ box.half_size.z * (axis * box.get_axis(2)).abs
94
+ end
95
+
96
+ def overlap_on_axis(one, two, axis, to_centre)
97
+ one_project = transform_to_axis(one, axis)
98
+ two_project = transform_to_axis(two, axis)
99
+
100
+ distance = (to_centre * axis).abs
101
+
102
+ distance < one_project + two_project
103
+ end
104
+
105
+ class IntersectionTests
106
+
107
+ def self.sphere_and_half_space(sphere, plane)
108
+
109
+ ball_distance = plane.direction * sphere.get_axis(3) - sphere.radius
110
+
111
+ ball_distance <= plane.offset
112
+ end
113
+
114
+ def self.sphere_and_sphere(one, two)
115
+
116
+ mid_line = one.get_axis(3) - two.get_axis(3)
117
+
118
+ return mid_line.sqaureMagnitude < (one.radius + two.radius) * (one.radius + two.radius)
119
+ end
120
+
121
+ def self.box_and_box(one, two)
122
+
123
+ to_center = two.get_axis(3) - one.get_axis(3)
124
+
125
+ return overlap_on_axis(one,two,one.getAxis(0), to_center) && \
126
+ overlap_on_axis(one,two,one.getAxis(1), to_center) && \
127
+ overlap_on_axis(one,two,one.getAxis(2), to_center) && \
128
+ overlap_on_axis(one,two,two.getAxis(0), to_center) && \
129
+ overlap_on_axis(one,two,two.getAxis(1), to_center) && \
130
+ overlap_on_axis(one,two,two.getAxis(2), to_center) && \
131
+ overlap_on_axis(one,two,one.getAxis(0) % two.getAxis(0), to_center) && \
132
+ overlap_on_axis(one,two,one.getAxis(0) % two.getAxis(1), to_center) && \
133
+ overlap_on_axis(one,two,one.getAxis(0) % two.getAxis(2), to_center) && \
134
+ overlap_on_axis(one,two,one.getAxis(1) % two.getAxis(0), to_center) && \
135
+ overlap_on_axis(one,two,one.getAxis(1) % two.getAxis(1), to_center) && \
136
+ overlap_on_axis(one,two,one.getAxis(1) % two.getAxis(2), to_center) && \
137
+ overlap_on_axis(one,two,one.getAxis(2) % two.getAxis(0), to_center) && \
138
+ overlap_on_axis(one,two,one.getAxis(2) % two.getAxis(1), to_center) && \
139
+ overlap_on_axis(one,two,one.getAxis(2) % two.getAxis(2), to_center)
140
+ end
141
+
142
+ def self.box_and_half_space(box, plane)
143
+ projection_radius = transform_to_axis( box, plane.direction)
144
+ box_distance = plane.direction * box.get_axis(3) - projection_radius
145
+ box_distance < plane.offset
146
+ end
147
+
148
+ end
149
+
150
+ class CollisionDetector
151
+
152
+ def self.sphere_and_half_space(sphere, plane, contacts)
153
+ #eturn 0 if(data.contacts_left <= 0)
154
+
155
+ position = sphere.get_axis(3)
156
+
157
+ ball_distance = plane.direction * position - sphere.radius - plane.offset
158
+
159
+ puts "ball distance"
160
+ return 0 if ball_distance >= 0
161
+
162
+ contact = Contact.new
163
+ contact.contact_normal = plane.direction
164
+ contact.penetration = -ball_distance
165
+ contact.contact_point = position - plane.direction * (ball_distance + sphere.radius)
166
+ contact.set_body_data(sphere.body, nil, 0.9, 0.6)
167
+ contacts << contact
168
+ return 1
169
+ end
170
+
171
+ def self.sphere_and_sphere(one, two, contatcs)
172
+
173
+ positionOne = one.get_axis(3)
174
+ positionTwo = two.get_axis(3)
175
+
176
+ midline = positionOne - positionTwo
177
+
178
+ size = midline.magnitude
179
+
180
+ if size <= 0.0 || size >= one.radius + two.radius
181
+ return 0
182
+ end
183
+
184
+ normal = midline * (1.0/size)
185
+
186
+ contact = Contact.new
187
+ contact.normal = normal
188
+ contact.contact_point = positionOne + midline * 0.5
189
+ contact.penetration = one.radius + two.radius - size
190
+ contact.set_body_data( one.body, two.body, 0.9, 0.6)
191
+ contatcs << contact
192
+ return 1
193
+ end
194
+
195
+ def self.box_and_box(one, two, data)
196
+
197
+ to_center = two.get_axis(3) - one.get_axis(3)
198
+ puts "NOT DONE YET"
199
+ return overlap_on_axis(one,two,one.getAxis(0), to_center) && \
200
+ overlap_on_axis(one,two,one.getAxis(1), to_center) && \
201
+ overlap_on_axis(one,two,one.getAxis(2), to_center) && \
202
+ overlap_on_axis(one,two,two.getAxis(0), to_center) && \
203
+ overlap_on_axis(one,two,two.getAxis(1), to_center) && \
204
+ overlap_on_axis(one,two,two.getAxis(2), to_center) && \
205
+ overlap_on_axis(one,two,one.getAxis(0) % two.getAxis(0), to_center) && \
206
+ overlap_on_axis(one,two,one.getAxis(0) % two.getAxis(1), to_center) && \
207
+ overlap_on_axis(one,two,one.getAxis(0) % two.getAxis(2), to_center) && \
208
+ overlap_on_axis(one,two,one.getAxis(1) % two.getAxis(0), to_center) && \
209
+ overlap_on_axis(one,two,one.getAxis(1) % two.getAxis(1), to_center) && \
210
+ overlap_on_axis(one,two,one.getAxis(1) % two.getAxis(2), to_center) && \
211
+ overlap_on_axis(one,two,one.getAxis(2) % two.getAxis(0), to_center) && \
212
+ overlap_on_axis(one,two,one.getAxis(2) % two.getAxis(1), to_center) && \
213
+ overlap_on_axis(one,two,one.getAxis(2) % two.getAxis(2), to_center)
214
+ end
215
+
216
+ def self.box_and_half_space(box, plane, contacts)
217
+ #return 0 if data.contacts_left <= 0
218
+
219
+ #return 0 unless IntersectionTests.box_and_half_space(box,plane)
220
+
221
+ mults = [ [1,1,1] , [-1,1,1] , [1,-1,1] , [-1,-1,1] , \
222
+ [1,1,-1] , [-1,1,-1], [1,-1,-1] , [-1,-1,-1]]
223
+
224
+ contacts_used = 0
225
+
226
+ #contact = contacts[contacts_used]
227
+
228
+ for i in 0..7
229
+ vertexPos = Vector3.new(mults[i][0], mults[i][1], mults[i][2]);
230
+ vertexPos.componentProductUpdate(box.half_size);
231
+ vertexPos = box.transform.transform(vertexPos);
232
+ vertexDistance = vertexPos * plane.direction;
233
+
234
+ if(vertexDistance <= plane.offset)
235
+ puts "test"
236
+ contact = Contact.new
237
+ contact.contact_point = plane.direction
238
+ contact.contact_point *= (vertexDistance - plane.offset)
239
+ contact.contact_point = vertexPos # ??????
240
+ contact.contact_normal = plane.direction
241
+ contact.penetration = plane.offset - vertexDistance
242
+
243
+ contacts_used+=1
244
+ contact.set_body_data(box.body, nil, 0.9, 0.6)
245
+ contacts << contact
246
+ #contact = data.contacts[contacts_used]
247
+ #return contacts_used if contacts_used == data.contacts_left
248
+ end
249
+ end
250
+
251
+ #data.add_contacts(contacts_used)
252
+ return contacts_used
253
+ end
254
+
255
+ end
256
+ end