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.
- data/lib/Particles/particle_contact.rb +25 -12
- data/lib/Particles/particle_contact_resolver.rb +4 -4
- data/lib/Particles/particle_drag.rb +1 -1
- data/lib/Particles/particle_rod.rb +8 -7
- data/lib/Particles/particle_world.rb +1 -0
- data/lib/RigidBodies/Gravity.rb +18 -0
- data/lib/RigidBodies/buoyancy.rb +32 -0
- data/lib/RigidBodies/collision_shapes.rb +256 -0
- data/lib/RigidBodies/contact.rb +362 -0
- data/lib/RigidBodies/contact_generator.rb +7 -0
- data/lib/RigidBodies/contact_resolver.rb +143 -0
- data/lib/RigidBodies/force_generator.rb +7 -0
- data/lib/RigidBodies/force_registration.rb +12 -0
- data/lib/RigidBodies/force_registry.rb +48 -0
- data/lib/RigidBodies/joint.rb +45 -0
- data/lib/RigidBodies/rigid_body.rb +261 -0
- data/lib/RigidBodies/rigid_collisions.rb +292 -0
- data/lib/RigidBodies/spring.rb +38 -0
- data/lib/RigidBodies/world.rb +97 -0
- data/lib/bulldog_physics.rb +6 -4
- data/lib/examples/GlStuff/gl_utility.rb +4 -0
- data/lib/examples/GlStuff/lighting.rb +1 -1
- data/lib/examples/GlStuff/material.rb +11 -11
- data/lib/examples/buoyancy_game.rb +189 -0
- data/lib/examples/simple_game.rb +79 -76
- data/lib/vector3.rb +8 -13
- metadata +92 -120
- data/.document +0 -5
- data/Gemfile +0 -13
- data/Gemfile.lock +0 -22
- data/Rakefile +0 -55
- data/VERSION +0 -1
- data/bulldog_physics.gemspec +0 -92
- data/test/helper.rb +0 -18
- data/test/test_bulldog_physics.rb +0 -7
@@ -0,0 +1,362 @@
|
|
1
|
+
module BulldogPhysics
|
2
|
+
class Contact
|
3
|
+
|
4
|
+
|
5
|
+
# Holds the bodies that are involved in the contact. The
|
6
|
+
# second of these can be NULL, for contacts with the scenery.
|
7
|
+
attr_accessor :body
|
8
|
+
|
9
|
+
# Holds the lateral friction coefficient at the contact.
|
10
|
+
attr_accessor :friction
|
11
|
+
|
12
|
+
# Holds the normal restitution coefficient at the contact.
|
13
|
+
attr_accessor :restitution
|
14
|
+
|
15
|
+
# Holds the position of the contact in world coordinates.
|
16
|
+
attr_accessor :contact_point
|
17
|
+
|
18
|
+
# Holds the direction of the contact in world coordinates.
|
19
|
+
attr_accessor :contact_normal
|
20
|
+
|
21
|
+
# Holds the depth of penetration at the contact point. If both
|
22
|
+
# bodies are specified then the contact point should be midway
|
23
|
+
# between the inter-penetrating points.
|
24
|
+
attr_accessor :penetration
|
25
|
+
|
26
|
+
|
27
|
+
# A transform matrix that converts co-ordinates in the contact's
|
28
|
+
# frame of reference to world co-ordinates. The columns of this
|
29
|
+
# matrix form an orthonormal set of vectors.
|
30
|
+
attr_accessor :contact_to_world
|
31
|
+
|
32
|
+
# Holds the closing velocity at the point of contact. This is set
|
33
|
+
# when the calculateInternals function is run.
|
34
|
+
attr_accessor :contact_velocity
|
35
|
+
|
36
|
+
# Holds the required change in velocity for this contact to be
|
37
|
+
# resolved.
|
38
|
+
attr_accessor :desired_delta_velocity
|
39
|
+
|
40
|
+
# Holds the world space position of the contact point relative to
|
41
|
+
# centre of each body. This is set when the calculateInternals
|
42
|
+
# function is run.
|
43
|
+
attr_accessor :relative_contact_position
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
def initialize()
|
48
|
+
@body = Array.new(2)
|
49
|
+
@contact_normal = Vector3.new
|
50
|
+
@contact_point = Vector3.new
|
51
|
+
@contact_to_world = Matrix3.new
|
52
|
+
@contact_velocity = Vector3.new
|
53
|
+
@desired_delta_velocity = Vector3.new
|
54
|
+
@relative_contact_position = [ Vector3.new, Vector3.new ]
|
55
|
+
@penetration = 0.0
|
56
|
+
set_body_data(RigidBody.new, RigidBody.new, 1.0, 0.96)
|
57
|
+
end
|
58
|
+
|
59
|
+
def set_body_data(one, two, friction, restitution)
|
60
|
+
@body[0] = one
|
61
|
+
@body[1] = two
|
62
|
+
@friction = friction
|
63
|
+
@restitution = restitution
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
# Calculates internal data from state data. This is called before
|
70
|
+
# the resolution algorithm tries to do any resolution. It should
|
71
|
+
# never need to be called manually.
|
72
|
+
def calculate_internals(duration)
|
73
|
+
swap_bodies if @body[0].nil?
|
74
|
+
|
75
|
+
calculate_contact_basis
|
76
|
+
|
77
|
+
@relative_contact_position[0] = @contact_point - @body[0].position
|
78
|
+
|
79
|
+
unless @body[1].nil?
|
80
|
+
@relative_contact_position[1] = @contact_point - @body[1].position
|
81
|
+
end
|
82
|
+
|
83
|
+
@contact_velocity = calculate_local_velocity(0, duration)
|
84
|
+
unless @body[1].nil?
|
85
|
+
@contact_velocity -= calculate_local_velocity(1, duration)
|
86
|
+
end
|
87
|
+
|
88
|
+
calculate_desired_delta_velocity(duration)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Reverses the contact. This involves swapping the two rigid bodies
|
92
|
+
# and reversing the contact normal. The internal values should then
|
93
|
+
# be recalculated using calculateInternals (this is not done
|
94
|
+
# automatically).
|
95
|
+
def swap_bodies
|
96
|
+
@contact_normal *= -1
|
97
|
+
temp = @body[0]
|
98
|
+
@body[0] = @body[1]
|
99
|
+
@body[1] = temp
|
100
|
+
end
|
101
|
+
|
102
|
+
def match_awake_state
|
103
|
+
|
104
|
+
return if @body[1].nil?
|
105
|
+
|
106
|
+
body0awake = @body[0].is_awake
|
107
|
+
body1awake = @body[1].is_awake
|
108
|
+
|
109
|
+
if(body0awake != body1awake)
|
110
|
+
if(body0awake)
|
111
|
+
@body[1].is_awake = true
|
112
|
+
else
|
113
|
+
@body[0].is_awake = true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def calculate_desired_delta_velocity(duration)
|
119
|
+
|
120
|
+
velocity_limit = 0.25
|
121
|
+
|
122
|
+
velocity_from_acc = 0.0
|
123
|
+
|
124
|
+
|
125
|
+
if @body[0].is_awake
|
126
|
+
velocity_from_acc = @body[0].last_frame_acceleration.scalarProduct(@contact_normal) * duration
|
127
|
+
#@body[0].last_frame_acceleration.componentProductUpdate(@contact_normal * duration)
|
128
|
+
end
|
129
|
+
|
130
|
+
if !@body[1].nil?
|
131
|
+
if @body[1].is_awake
|
132
|
+
#@body[1].last_frame_acceleration.componentProductUpdate(@contact_normal * duration)
|
133
|
+
velocity_from_acc -= @body[1].last_frame_acceleration.scalarProduct(@contact_normal) * duration
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
this_restitution = @restitution
|
138
|
+
if(@contact_velocity.x.abs < velocity_limit)
|
139
|
+
this_restitution = 0.0
|
140
|
+
end
|
141
|
+
|
142
|
+
@desired_delta_velocity = -@contact_velocity.x - (this_restitution * (@contact_velocity.x - velocity_from_acc))
|
143
|
+
end
|
144
|
+
|
145
|
+
def calculate_local_velocity(body_index, duration)
|
146
|
+
this_body = @body[body_index]
|
147
|
+
|
148
|
+
velocity = this_body.rotation % @relative_contact_position[body_index]
|
149
|
+
velocity += this_body.velocity
|
150
|
+
|
151
|
+
contact_velocity = @contact_to_world.transform_transpose(velocity)
|
152
|
+
|
153
|
+
#puts this_body.last_frame_acceleration
|
154
|
+
acc_velocity = this_body.last_frame_acceleration * duration
|
155
|
+
#puts acc_velocity
|
156
|
+
acc_velocity = @contact_to_world.transform_transpose(acc_velocity)
|
157
|
+
|
158
|
+
acc_velocity.x = 0
|
159
|
+
|
160
|
+
contact_velocity += acc_velocity
|
161
|
+
|
162
|
+
contact_velocity
|
163
|
+
end
|
164
|
+
|
165
|
+
def calculate_contact_basis
|
166
|
+
contact_tangent = [Vector3.new, Vector3.new]
|
167
|
+
if(@contact_normal.x.abs > @contact_normal.y.abs)
|
168
|
+
s = 1.0 / Math.sqrt( @contact_normal.z * @contact_normal.z + @contact_normal.x * @contact_normal.x)
|
169
|
+
contact_tangent[0].x = @contact_normal.z * s
|
170
|
+
contact_tangent[0].y = 0
|
171
|
+
contact_tangent[0].z = -@contact_normal.x * s
|
172
|
+
|
173
|
+
contact_tangent[1].x = @contact_normal.y * contact_tangent[0].x
|
174
|
+
contact_tangent[1].y = @contact_normal.z * contact_tangent[0].x - @contact_normal.x * contact_tangent[0].z
|
175
|
+
contact_tangent[1].z = -@contact_normal.y * contact_tangent[0].x
|
176
|
+
else
|
177
|
+
s = 1.0 / Math.sqrt( @contact_normal.z * @contact_normal.z + @contact_normal.y * @contact_normal.y)
|
178
|
+
contact_tangent[0].x = 0
|
179
|
+
contact_tangent[0].y = -@contact_normal.z * s
|
180
|
+
contact_tangent[0].z = @contact_normal.y * s
|
181
|
+
|
182
|
+
contact_tangent[1].x = @contact_normal.y * contact_tangent[0].z - @contact_normal.z * contact_tangent[0].y
|
183
|
+
contact_tangent[1].y = -@contact_normal.x * contact_tangent[0].z
|
184
|
+
contact_tangent[1].z = @contact_normal.x * contact_tangent[0].y
|
185
|
+
end
|
186
|
+
|
187
|
+
@contact_to_world.setComponents( @contact_normal, contact_tangent[0], contact_tangent[1])
|
188
|
+
end
|
189
|
+
|
190
|
+
def apply_impulse(impulse, body, velocity_change, rotation_change)
|
191
|
+
puts "not done yet"
|
192
|
+
end
|
193
|
+
|
194
|
+
def apply_velocity_change(velocity_change, rotation_change)
|
195
|
+
inverse_inertia_tensors = [Matrix3.new, Matrix3.new ]
|
196
|
+
|
197
|
+
inverse_inertia_tensors[0] = @body[0].inverse_inertia_tensor_world.dup
|
198
|
+
|
199
|
+
unless @body[1].nil?
|
200
|
+
inverse_inertia_tensors[1] = @body[1].inverse_inertia_tensor_world.dup
|
201
|
+
end
|
202
|
+
|
203
|
+
impulse_contact = Vector3.new
|
204
|
+
|
205
|
+
if( @friction == 0.0)
|
206
|
+
impulse_contact = calculate_frictionless_impulse(inverse_inertia_tensors)
|
207
|
+
else
|
208
|
+
impulse_contact = calculate_friction_impulse(inverse_inertia_tensors)
|
209
|
+
end
|
210
|
+
|
211
|
+
impulse = @contact_to_world.transform(impulse_contact)
|
212
|
+
|
213
|
+
impulsive_torque = @relative_contact_position[0] % impulse
|
214
|
+
rotation_change[0] = inverse_inertia_tensors[0].transform(impulsive_torque)
|
215
|
+
velocity_change[0].clear()
|
216
|
+
velocity_change[0].addScaledVector(impulse, @body[0].inverse_mass)
|
217
|
+
|
218
|
+
@body[0].velocity += velocity_change[0]
|
219
|
+
@body[0].rotation += rotation_change[0]
|
220
|
+
|
221
|
+
unless @body[1].nil?
|
222
|
+
impulsive_torque = impulse % @relative_contact_position[1]
|
223
|
+
rotation_change[1] = inverse_inertia_tensors[1].transform(impulsive_torque)
|
224
|
+
velocity_change[1].clear()
|
225
|
+
velocity_change[1].addScaledVector(impulse, -@body[1].inverse_mass)
|
226
|
+
|
227
|
+
@body[1].velocity += velocity_change[1]
|
228
|
+
@body[1].rotation += rotation_change[1]
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def apply_position_change(linear_change, angular_change, penetration)
|
233
|
+
|
234
|
+
angularLimit = 0.2;
|
235
|
+
angularMove = [0.0, 0.0]
|
236
|
+
linearMove = [0.0, 0.0];
|
237
|
+
|
238
|
+
totalInertia = 0.0;
|
239
|
+
linearInertia = [0.0, 0.0]
|
240
|
+
angularInertia = [0.0, 0.0]
|
241
|
+
|
242
|
+
for i in 0..1
|
243
|
+
|
244
|
+
break if @body[i].nil?
|
245
|
+
|
246
|
+
inverseInertiaTensor = @body[i].inverse_inertia_tensor_world.dup
|
247
|
+
angularInertiaWorld = @relative_contact_position[i] % @contact_normal
|
248
|
+
angularInertiaWorld = inverseInertiaTensor.transform(angularInertiaWorld)
|
249
|
+
angularInertiaWorld = angularInertiaWorld % @relative_contact_position[i]
|
250
|
+
angularInertia[i] = angularInertiaWorld * @contact_normal
|
251
|
+
|
252
|
+
linearInertia[i] = body[i].inverse_mass
|
253
|
+
totalInertia += linearInertia[i] + angularInertia[i]
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
for i in 0..1
|
258
|
+
|
259
|
+
return if @body[i].nil?
|
260
|
+
|
261
|
+
sign = i == 0 ? 1 : -1
|
262
|
+
|
263
|
+
angularMove[i] = sign * penetration * (angularInertia[i] / totalInertia)
|
264
|
+
linearMove[i] = sign * penetration * (linearInertia[i] / totalInertia)
|
265
|
+
|
266
|
+
projection = @relative_contact_position[i]
|
267
|
+
projection.addScaledVector( @contact_normal, -@relative_contact_position[i].scalarProduct(@contact_normal))
|
268
|
+
|
269
|
+
maxMagnitude = angularLimit * projection.magnitude
|
270
|
+
|
271
|
+
if(angularMove[i] < -maxMagnitude)
|
272
|
+
totalMove = angularMove[i] + linearMove[i]
|
273
|
+
angularMove[i] = -maxMagnitude
|
274
|
+
linearMove[i] = totalMove - angularMove[i]
|
275
|
+
elsif angularMove[i] > maxMagnitude
|
276
|
+
totalMove = angularMove[i] + linearMove[i]
|
277
|
+
angularMove[i] = maxMagnitude
|
278
|
+
linearMove[i] = totalMove - angularMove[i]
|
279
|
+
end
|
280
|
+
|
281
|
+
if(angularMove[i] == 0)
|
282
|
+
angular_change[i].clear
|
283
|
+
else
|
284
|
+
targetAngularDirection = @relative_contact_position[i].vector_product(@contact_normal)
|
285
|
+
inverse_inertia_tensor = @body[i].inverse_inertia_tensor_world.dup
|
286
|
+
|
287
|
+
angular_change[i] = inverse_inertia_tensor.transform(targetAngularDirection) * (angularMove[i] / angularInertia[i])
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
linear_change[i] = @contact_normal * linearMove[i]
|
292
|
+
@body[i].position.addScaledVector( @contact_normal, linearMove[i])
|
293
|
+
|
294
|
+
#puts "WORK"
|
295
|
+
@body[i].orientation.addScaledVector(angular_change[i], 1.0)
|
296
|
+
@body[i].orientation.normalize
|
297
|
+
|
298
|
+
@body[i].calculate_derived_data if !@body[i].is_awake
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
def calculate_friction_impulse(inverse_inertia_tensor)
|
304
|
+
|
305
|
+
impulse_contact = Vector3.new
|
306
|
+
inverse_mass = @body[0].inverse_mass
|
307
|
+
|
308
|
+
impulseToTorque = Matrix3.new
|
309
|
+
impulseToTorque.setSkewSymmetric(@relative_contact_position[0])
|
310
|
+
|
311
|
+
deltaVelWorld = impulseToTorque.dup
|
312
|
+
deltaVelWorld *= inverse_inertia_tensor[0]
|
313
|
+
deltaVelWorld *= impulseToTorque
|
314
|
+
deltaVelWorld *= -1.0
|
315
|
+
|
316
|
+
unless @body[1].nil?
|
317
|
+
impulseToTorque.setSkewSymmetric(@relative_contact_position[1])
|
318
|
+
deltaVelWorld2 = impulseToTorque.dup
|
319
|
+
deltaVelWorld2 *= inverse_inertia_tensor[1]
|
320
|
+
deltaVelWorld2 *= impulseToTorque
|
321
|
+
deltaVelWorld2 *= -1.0
|
322
|
+
|
323
|
+
deltaVelWorld += deltaVelWorld2
|
324
|
+
|
325
|
+
inverse_mass += @body[1].inverse_mass
|
326
|
+
end
|
327
|
+
|
328
|
+
deltaVelocity = @contact_to_world.transpose()
|
329
|
+
deltaVelocity *= deltaVelWorld
|
330
|
+
deltaVelocity *= @contact_to_world
|
331
|
+
|
332
|
+
deltaVelocity.data[0] += inverse_mass
|
333
|
+
deltaVelocity.data[4] += inverse_mass
|
334
|
+
deltaVelocity.data[4] += inverse_mass
|
335
|
+
|
336
|
+
impulse_matrix = deltaVelocity.inverse
|
337
|
+
|
338
|
+
velKill = Vector3.new( @desired_delta_velocity, -@contact_velocity.y, -@contact_velocity.z)
|
339
|
+
|
340
|
+
impulse_contact = impulse_matrix.transform(velKill)
|
341
|
+
|
342
|
+
planarImpulse = Math.sqrt( (impulse_contact.y * impulse_contact.y) + (impulse_contact.z * impulse_contact.z))
|
343
|
+
|
344
|
+
if planarImpulse > impulse_contact.x * @friction
|
345
|
+
impulse_contact.y /= planarImpulse
|
346
|
+
impulse_contact.z /= planarImpulse
|
347
|
+
|
348
|
+
impulse_contact.x = deltaVelocity.data[0] + ( deltaVelocity.data[1] * @friction * impulse_contact.y) + (deltaVelocity.data[2] * @friction * impulse_contact.z)
|
349
|
+
impulse_contact.x = @desired_delta_velocity / impulse_contact.z
|
350
|
+
impulse_contact.y *= @friction * impulse_contact.x;
|
351
|
+
impulse_contact.z *= @friction * impulse_contact.x
|
352
|
+
end
|
353
|
+
|
354
|
+
return impulse_contact
|
355
|
+
|
356
|
+
end
|
357
|
+
|
358
|
+
def calculate_frictionless_impulse(inverse_inertia_tensor)
|
359
|
+
puts "not implemented"
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module BulldogPhysics
|
2
|
+
class ContactResolver
|
3
|
+
|
4
|
+
attr :velocity_iterations, :position_iterations
|
5
|
+
|
6
|
+
attr :velocity_epsilon, :position_epsilon
|
7
|
+
|
8
|
+
attr_accessor :velocity_iterations_used, :position_iterations_used
|
9
|
+
|
10
|
+
attr :valid_settings
|
11
|
+
|
12
|
+
|
13
|
+
def initialize(iterations, velocity_epsilon = 0.01, position_epsilon = 0.01)
|
14
|
+
set_iterations(iterations, iterations)
|
15
|
+
set_epsilon(velocity_epsilon, position_epsilon)
|
16
|
+
end
|
17
|
+
|
18
|
+
def is_valid
|
19
|
+
@velocity_iterations > 0 && @position_iterations > 0 && @position_epsilon >= 0.0 && @velocity_epsilon >= 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_iterations(velocity_iterations, position_iterations)
|
23
|
+
@velocity_iterations = velocity_iterations
|
24
|
+
@position_iterations = position_iterations
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_epsilon(velocity_epsilon, position_epsilon)
|
28
|
+
@velocity_epsilon = velocity_epsilon
|
29
|
+
@position_epsilon = position_epsilon
|
30
|
+
end
|
31
|
+
|
32
|
+
def resolve_contacts(contact_array, num_contacts, duration)
|
33
|
+
return if num_contacts == 0
|
34
|
+
return unless is_valid
|
35
|
+
|
36
|
+
prepare_contacts(contact_array, num_contacts, duration)
|
37
|
+
adjust_positions(contact_array, num_contacts, duration)
|
38
|
+
adjust_velocities(contact_array, num_contacts, duration)
|
39
|
+
end
|
40
|
+
|
41
|
+
def prepare_contacts(contact_array, num_contacts, duration)
|
42
|
+
contact_array.each do |contact|
|
43
|
+
contact.calculate_internals(duration)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def adjust_velocities(contact_array, num_contacts, duration)
|
48
|
+
velocityChange = [Vector3.new, Vector3.new]
|
49
|
+
rotationChange = [Vector3.new, Vector3.new]
|
50
|
+
deltaVel = Vector3.new
|
51
|
+
|
52
|
+
@velocity_iterations_used = 0
|
53
|
+
|
54
|
+
while @velocity_iterations_used < @velocity_iterations do
|
55
|
+
|
56
|
+
max = @velocity_epsilon
|
57
|
+
index = num_contacts
|
58
|
+
for i in 0..num_contacts-1
|
59
|
+
if(contact_array[i].desired_delta_velocity > max)
|
60
|
+
max = contact_array[i].desired_delta_velocity
|
61
|
+
index = i
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
break if index == num_contacts
|
66
|
+
|
67
|
+
contact_array[index].match_awake_state
|
68
|
+
contact_array[index].apply_velocity_change(velocityChange, rotationChange)
|
69
|
+
|
70
|
+
for i in i..num_contacts-1
|
71
|
+
for b in 0..1
|
72
|
+
next if contact_array[i].body[b].nil?
|
73
|
+
for d in 0..1
|
74
|
+
if(contact_array[i].body[b] == contact_array[index].body[d])
|
75
|
+
deltaVel = velocityChange[d] + rotationChange[d].vector_product(contact_array[i].relative_contact_position[b]);
|
76
|
+
#puts "DELAT VEL #{deltaVel}"
|
77
|
+
#puts "CONTACT VELOCITY #{contact_array[i].contact_velocity}"
|
78
|
+
#puts "CONTACT TO WORLD "
|
79
|
+
|
80
|
+
change = contact_array[i].contact_to_world.transformTranspose(deltaVel)
|
81
|
+
if(b)
|
82
|
+
contact_array[i].contact_velocity -= change
|
83
|
+
else
|
84
|
+
contact_array[i].contact_velocity += change
|
85
|
+
end
|
86
|
+
|
87
|
+
contact_array[i].calculate_desired_delta_velocity(duration)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
@velocity_iterations_used += 1
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
#c is a contact array
|
98
|
+
def adjust_positions(c, num_contacts, duration)
|
99
|
+
linearChange = [Vector3.new, Vector3.new]
|
100
|
+
angularChange = [Vector3.new, Vector3.new]
|
101
|
+
#angularChange = Vector3.new
|
102
|
+
deltaPosition = Vector3.new
|
103
|
+
|
104
|
+
@position_iterations_used = 0
|
105
|
+
while @position_iterations_used < @position_iterations
|
106
|
+
|
107
|
+
max = @position_epsilon
|
108
|
+
index = num_contacts
|
109
|
+
|
110
|
+
for i in 0..num_contacts
|
111
|
+
if( c[i].penetration > max)
|
112
|
+
max = c[i].penetration
|
113
|
+
puts "MAX #{max}"
|
114
|
+
index = i
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
break if (index == num_contacts)
|
119
|
+
|
120
|
+
c[index].match_awake_state
|
121
|
+
c[index].apply_position_change( linearChange, angularChange, max)
|
122
|
+
|
123
|
+
for i in 0..num_contacts-1
|
124
|
+
for b in 0..1
|
125
|
+
#next if c[i].body[b].nil?
|
126
|
+
|
127
|
+
for d in 0..1
|
128
|
+
|
129
|
+
if(c[i].body[b] == c[index].body[d])
|
130
|
+
deltaPosition = linearChange[d] + angularChange[d].vector_product( c[i].relative_contact_position[b])
|
131
|
+
test = b == 1 ? 1 : -1
|
132
|
+
#puts test
|
133
|
+
c[i].penetration += deltaPosition.scalarProduct(c[i].contact_normal) * test
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
@position_iterations_used += 1
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|