bulldog_physics 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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