diff options
Handle ObjectSpin* packets to spin physical prims on Ctrl+Shift+Drag
Addresses Mantis #3381
The current implementation works as expected if the object has no rotation or
only rotation around the Z axis; you can spin the object left or right (around
the world Z axis).
It works a little unexpectedly if the object has a non-Z-axis rotation; in this
case the body is spun about its local Z axis, not the world Z-axis. (But SL
also behaves oddly with a spin on an arbitrarily rotated object.)
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 1834215..4fdc71e 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -2299,6 +2299,106 @@ namespace OpenSim.Region.Framework.Scenes | |||
2299 | } | 2299 | } |
2300 | 2300 | ||
2301 | /// <summary> | 2301 | /// <summary> |
2302 | /// If object is physical, prepare for spinning torques (set flag to save old orientation) | ||
2303 | /// </summary> | ||
2304 | /// <param name="rotation">Rotation. We do the math here to turn it into a torque</param> | ||
2305 | /// <param name="remoteClient"></param> | ||
2306 | public void SpinStart(IClientAPI remoteClient) | ||
2307 | { | ||
2308 | if (m_scene.EventManager.TriggerGroupSpinStart(UUID)) | ||
2309 | { | ||
2310 | if (m_rootPart.PhysActor != null) | ||
2311 | { | ||
2312 | if (m_rootPart.PhysActor.IsPhysical) | ||
2313 | { | ||
2314 | m_rootPart.IsWaitingForFirstSpinUpdatePacket = true; | ||
2315 | } | ||
2316 | } | ||
2317 | } | ||
2318 | } | ||
2319 | |||
2320 | /// <summary> | ||
2321 | /// If object is physical, apply torque to spin it around | ||
2322 | /// </summary> | ||
2323 | /// <param name="rotation">Rotation. We do the math here to turn it into a torque</param> | ||
2324 | /// <param name="remoteClient"></param> | ||
2325 | public void SpinMovement(Quaternion newOrientation, IClientAPI remoteClient) | ||
2326 | { | ||
2327 | // The incoming newOrientation, sent by the client, "seems" to be the | ||
2328 | // desired target orientation. This needs further verification; in particular, | ||
2329 | // one would expect that the initial incoming newOrientation should be | ||
2330 | // fairly close to the original prim's physical orientation, | ||
2331 | // m_rootPart.PhysActor.Orientation. This however does not seem to be the | ||
2332 | // case (might just be an issue with different quaternions representing the | ||
2333 | // same rotation, or it might be a coordinate system issue). | ||
2334 | // | ||
2335 | // Since it's not clear what the relationship is between the PhysActor.Orientation | ||
2336 | // and the incoming orientations sent by the client, we take an alternative approach | ||
2337 | // of calculating the delta rotation between the orientations being sent by the | ||
2338 | // client. (Since a spin is invoked by ctrl+shift+drag in the client, we expect | ||
2339 | // a steady stream of several new orientations coming in from the client.) | ||
2340 | // This ensures that the delta rotations are being calculated from self-consistent | ||
2341 | // pairs of old/new rotations. Given the delta rotation, we apply a torque around | ||
2342 | // the delta rotation axis, scaled by the object mass times an arbitrary scaling | ||
2343 | // factor (to ensure the resulting torque is not "too strong" or "too weak"). | ||
2344 | // | ||
2345 | // Ideally we need to calculate (probably iteratively) the exact torque or series | ||
2346 | // of torques needed to arrive exactly at the destination orientation. However, since | ||
2347 | // it is not yet clear how to map the destination orientation (provided by the viewer) | ||
2348 | // into PhysActor orientations (needed by the physics engine), we omit this step. | ||
2349 | // This means that the resulting torque will at least be in the correct direction, | ||
2350 | // but it will result in over-shoot or under-shoot of the target orientation. | ||
2351 | // For the end user, this means that ctrl+shift+drag can be used for relative, | ||
2352 | // but not absolute, adjustments of orientation for physical prims. | ||
2353 | |||
2354 | if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation)) | ||
2355 | { | ||
2356 | if (m_rootPart.PhysActor != null) | ||
2357 | { | ||
2358 | if (m_rootPart.PhysActor.IsPhysical) | ||
2359 | { | ||
2360 | if(m_rootPart.IsWaitingForFirstSpinUpdatePacket) | ||
2361 | { | ||
2362 | // first time initialization of "old" orientation for calculation of delta rotations | ||
2363 | m_rootPart.SpinOldOrientation = newOrientation; | ||
2364 | m_rootPart.IsWaitingForFirstSpinUpdatePacket = false; | ||
2365 | } | ||
2366 | else | ||
2367 | { | ||
2368 | // save and update old orientation | ||
2369 | Quaternion old = m_rootPart.SpinOldOrientation; | ||
2370 | m_rootPart.SpinOldOrientation = newOrientation; | ||
2371 | //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old); | ||
2372 | //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation); | ||
2373 | |||
2374 | // compute difference between previous old rotation and new incoming rotation | ||
2375 | Quaternion minimalRotationFromQ1ToQ2 = Quaternion.Inverse(old) * newOrientation; | ||
2376 | |||
2377 | float rotationAngle; | ||
2378 | Vector3 rotationAxis; | ||
2379 | minimalRotationFromQ1ToQ2.GetAxisAngle(out rotationAxis, out rotationAngle); | ||
2380 | rotationAxis.Normalize(); | ||
2381 | |||
2382 | //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis); | ||
2383 | PhysicsVector spinforce = new PhysicsVector(rotationAxis.X, rotationAxis.Y, rotationAxis.Z); | ||
2384 | spinforce = (spinforce/8) * m_rootPart.PhysActor.Mass; // 8 is an arbitrary torque scaling factor | ||
2385 | m_rootPart.PhysActor.AddAngularForce(spinforce,true); | ||
2386 | m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); | ||
2387 | } | ||
2388 | } | ||
2389 | else | ||
2390 | { | ||
2391 | //NonPhysicalSpinMovement(pos); | ||
2392 | } | ||
2393 | } | ||
2394 | else | ||
2395 | { | ||
2396 | //NonPhysicalSpinMovement(pos); | ||
2397 | } | ||
2398 | } | ||
2399 | } | ||
2400 | |||
2401 | /// <summary> | ||
2302 | /// Return metadata about a prim (name, description, sale price, etc.) | 2402 | /// Return metadata about a prim (name, description, sale price, etc.) |
2303 | /// </summary> | 2403 | /// </summary> |
2304 | /// <param name="client"></param> | 2404 | /// <param name="client"></param> |