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.
- 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
|