I'm trying to re-create an arcball example from a Nehe, where an object can be rotated in a more realistic way while floating in the air (in my game the object is attached to the player at a distance like for example the Physics Gun) however I'm having trouble getting this to work with UDK.
I have created an LGArcBall which follows the example from Nehe and I've compared outputs from this with the example code.
I think where my problem lies is what I do to the Quaternion that is returned from the LGArcBall.
Currently I am taking the returned Quaternion converting it to a rotation matrix. Getting the product of the last rotation (set when the object is first clicked) and then returning that into a Rotator and setting that to the objects rotation.
If you could point me in the right direction that would be great, my code can be found below.
class LGArcBall extends Object;
var Quat StartRotation;
var Vector StartVector;
var float AdjustWidth, AdjustHeight, Epsilon;
function SetBounds(float NewWidth, float NewHeight)
{
AdjustWidth = 1.0f / ((NewWidth - 1.0f) * 0.5f);
AdjustHeight = 1.0f / ((NewHeight - 1.0f) * 0.5f);
}
function StartDrag(Vector2D startPoint, Quat rotation)
{
StartVector = MapToSphere(startPoint);
}
function Quat Update(Vector2D currentPoint)
{
local Vector currentVector, perp;
local Quat newRot;
//Map the new point to the sphere
currentVector = MapToSphere(currentPoint);
//Compute the vector perpendicular to the start and current
perp = startVector cross currentVector;
//Make sure our length is larger than Epsilon
if (VSize(perp) > Epsilon)
{
//Return the perpendicular vector as the transform
newRot.X = perp.X;
newRot.Y = perp.Y;
newRot.Z = perp.Z;
//In the quaternion values, w is cosine (theta / 2), where
//theta is the rotation angle
newRot.W = startVector dot currentVector;
}
else
{
//The two vectors coincide, so return an identity transform
newRot.X = 0.0f;
newRot.Y = 0.0f;
newRot.Z = 0.0f;
newRot.W = 0.0f;
}
return newRot;
}
function Vector MapToSphere(Vector2D point)
{
local float x, y, length, norm;
local Vector result;
//Transform the mouse coords to [-1..1]
//and inverse the Y coord
x = (point.X * AdjustWidth) - 1.0f;
y = 1.0f - (point.Y * AdjustHeight);
length = (x * x) + (y * y);
//If the point is mapped outside of the sphere
//( length > radius squared)
if (length > 1.0f)
{
norm = 1.0f / Sqrt(length);
//Return the "normalized" vector, a point on the sphere
result.X = x * norm;
result.Y = y * norm;
result.Z = 0.0f;
}
else //It's inside of the sphere
{
//Return a vector to the point mapped inside the sphere
//sqrt(radius squared - length)
result.X = x;
result.Y = y;
result.Z = Sqrt(1.0f - length);
}
return result;
}
DefaultProperties
{
Epsilon = 0.000001f
}
I'm then attempting to rotate that object when the mouse is dragged, with the following update code in my PlayerController.
//Get Mouse Position
MousePosition.X = LGMouseInterfacePlayerInput(PlayerInput).MousePosition.X;
MousePosition.Y = LGMouseInterfacePlayerInput(PlayerInput).MousePosition.Y;
newQuat = ArcBall.Update(MousePosition);
rotMatrix = MakeRotationMatrix(QuatToRotator(newQuat));
rotMatrix = rotMatrix * LastRot;
LGMoveableActor(movingPawn.CurrentUseableObject).SetPhysics(EPhysics.PHYS_Rotating);
LGMoveableActor(movingPawn.CurrentUseableObject).SetRotation(MatrixGetRotator(rotMatrix));