From 8e6c20b27fdb95b9008614eb36678508407a4d19 Mon Sep 17 00:00:00 2001 From: nlin Date: Fri, 10 Apr 2009 06:39:52 +0000 Subject: 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.) --- .../Region/Framework/Scenes/SceneObjectGroup.cs | 100 +++++++++++++++++++++ 1 file changed, 100 insertions(+) (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs') 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 } /// + /// If object is physical, prepare for spinning torques (set flag to save old orientation) + /// + /// Rotation. We do the math here to turn it into a torque + /// + public void SpinStart(IClientAPI remoteClient) + { + if (m_scene.EventManager.TriggerGroupSpinStart(UUID)) + { + if (m_rootPart.PhysActor != null) + { + if (m_rootPart.PhysActor.IsPhysical) + { + m_rootPart.IsWaitingForFirstSpinUpdatePacket = true; + } + } + } + } + + /// + /// If object is physical, apply torque to spin it around + /// + /// Rotation. We do the math here to turn it into a torque + /// + public void SpinMovement(Quaternion newOrientation, IClientAPI remoteClient) + { + // The incoming newOrientation, sent by the client, "seems" to be the + // desired target orientation. This needs further verification; in particular, + // one would expect that the initial incoming newOrientation should be + // fairly close to the original prim's physical orientation, + // m_rootPart.PhysActor.Orientation. This however does not seem to be the + // case (might just be an issue with different quaternions representing the + // same rotation, or it might be a coordinate system issue). + // + // Since it's not clear what the relationship is between the PhysActor.Orientation + // and the incoming orientations sent by the client, we take an alternative approach + // of calculating the delta rotation between the orientations being sent by the + // client. (Since a spin is invoked by ctrl+shift+drag in the client, we expect + // a steady stream of several new orientations coming in from the client.) + // This ensures that the delta rotations are being calculated from self-consistent + // pairs of old/new rotations. Given the delta rotation, we apply a torque around + // the delta rotation axis, scaled by the object mass times an arbitrary scaling + // factor (to ensure the resulting torque is not "too strong" or "too weak"). + // + // Ideally we need to calculate (probably iteratively) the exact torque or series + // of torques needed to arrive exactly at the destination orientation. However, since + // it is not yet clear how to map the destination orientation (provided by the viewer) + // into PhysActor orientations (needed by the physics engine), we omit this step. + // This means that the resulting torque will at least be in the correct direction, + // but it will result in over-shoot or under-shoot of the target orientation. + // For the end user, this means that ctrl+shift+drag can be used for relative, + // but not absolute, adjustments of orientation for physical prims. + + if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation)) + { + if (m_rootPart.PhysActor != null) + { + if (m_rootPart.PhysActor.IsPhysical) + { + if(m_rootPart.IsWaitingForFirstSpinUpdatePacket) + { + // first time initialization of "old" orientation for calculation of delta rotations + m_rootPart.SpinOldOrientation = newOrientation; + m_rootPart.IsWaitingForFirstSpinUpdatePacket = false; + } + else + { + // save and update old orientation + Quaternion old = m_rootPart.SpinOldOrientation; + m_rootPart.SpinOldOrientation = newOrientation; + //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old); + //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation); + + // compute difference between previous old rotation and new incoming rotation + Quaternion minimalRotationFromQ1ToQ2 = Quaternion.Inverse(old) * newOrientation; + + float rotationAngle; + Vector3 rotationAxis; + minimalRotationFromQ1ToQ2.GetAxisAngle(out rotationAxis, out rotationAngle); + rotationAxis.Normalize(); + + //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis); + PhysicsVector spinforce = new PhysicsVector(rotationAxis.X, rotationAxis.Y, rotationAxis.Z); + spinforce = (spinforce/8) * m_rootPart.PhysActor.Mass; // 8 is an arbitrary torque scaling factor + m_rootPart.PhysActor.AddAngularForce(spinforce,true); + m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); + } + } + else + { + //NonPhysicalSpinMovement(pos); + } + } + else + { + //NonPhysicalSpinMovement(pos); + } + } + } + + /// /// Return metadata about a prim (name, description, sale price, etc.) /// /// -- cgit v1.1