Shape rotation
by Alex Moran · in Torque Game Builder · 10/22/2006 (2:41 pm) · 13 replies
Can anyone say why this line works:
%newSpeedX = %this.getLinearVelocityX() - getWord(%this.getShapeRotation(), 1) * %impulse;
and not any of these lines:
%newSpeedY = %this.getLinearVelocityY() + getWord(%this.getShapeRotation(), 0) * %impulse;
%newSpeedY = %this.getLinearVelocityY() + getWord(%this.getShapeRotation(), 2) * %impulse;
%newAngVel = getWord(%this.getShapeAngularVelocity(), 2) + %moment;
when manipulating a 3D object in TGB? Also, why does index 1 in getWord() point to X component, shouldn't index 0 be the X component, 1 be the Y component and 2 be the Z component of the vector? Finally, how can I find out what values getShapeRotation() is returning?
Description: %newSpeedX sets the speed in the X-direction based on rotation of object. %newSpeedY should set the speed in the Y-direction but no movement takes place for the first 90 degrees of rotation in either direction. For rotation > 90 degrees, speed is not based on rotation, but should be.
thanks!
TGB 1.1.2
OS X 10.4.8
PB G4
Alex
%newSpeedX = %this.getLinearVelocityX() - getWord(%this.getShapeRotation(), 1) * %impulse;
and not any of these lines:
%newSpeedY = %this.getLinearVelocityY() + getWord(%this.getShapeRotation(), 0) * %impulse;
%newSpeedY = %this.getLinearVelocityY() + getWord(%this.getShapeRotation(), 2) * %impulse;
%newAngVel = getWord(%this.getShapeAngularVelocity(), 2) + %moment;
when manipulating a 3D object in TGB? Also, why does index 1 in getWord() point to X component, shouldn't index 0 be the X component, 1 be the Y component and 2 be the Z component of the vector? Finally, how can I find out what values getShapeRotation() is returning?
Description: %newSpeedX sets the speed in the X-direction based on rotation of object. %newSpeedY should set the speed in the Y-direction but no movement takes place for the first 90 degrees of rotation in either direction. For rotation > 90 degrees, speed is not based on rotation, but should be.
thanks!
TGB 1.1.2
OS X 10.4.8
PB G4
Alex
About the author
#2
echo(%this.getShapeRotation());
it only returned 3 values. I assume they were (x,y,z), but I'm not sure.
Beyond that I'm scripting the inputs to contol a paddle boat. I need the boat to be able to move in the direction it is pointing, thats why I'm using getShapeRotation(). I tried using setForwardSpeed() but that didn't work on the shape. I don't know why.
Something I just noticed:
when I use this script on my shape:
%this.setShapeAngularVelocity(0,0,%newAngVel);
echo(%this.getShapeRotation());
this is the result in the console:
-0.000000 -0.174533 -0.000000
setShapeAngularVelocity(%x,%y,%z) is taking a %z argument (and the boat is rotating about the Z-axis), but the console is returning a Y-axis rotation.
???
10/23/2006 (1:10 pm)
Thanks for responding. However when I used the echo command:echo(%this.getShapeRotation());
it only returned 3 values. I assume they were (x,y,z), but I'm not sure.
Beyond that I'm scripting the inputs to contol a paddle boat. I need the boat to be able to move in the direction it is pointing, thats why I'm using getShapeRotation(). I tried using setForwardSpeed() but that didn't work on the shape. I don't know why.
Something I just noticed:
when I use this script on my shape:
%this.setShapeAngularVelocity(0,0,%newAngVel);
echo(%this.getShapeRotation());
this is the result in the console:
-0.000000 -0.174533 -0.000000
setShapeAngularVelocity(%x,%y,%z) is taking a %z argument (and the boat is rotating about the Z-axis), but the console is returning a Y-axis rotation.
???
#3
I guess if you were doing some crazy rotations on the boat before these rotations, you could run into gimbal lock, but that seems pretty unlikely with just a boat. Have you tried making a really simple test model? Perhaps it's a bug. I haven't seen very many people using getShapeRotation()
Maybe one of the elders will step in and lift the veil.
10/23/2006 (1:25 pm)
Yeah - my bad. The angles aren't quaternions at all - should have checked the docs first ;)I guess if you were doing some crazy rotations on the boat before these rotations, you could run into gimbal lock, but that seems pretty unlikely with just a boat. Have you tried making a really simple test model? Perhaps it's a bug. I haven't seen very many people using getShapeRotation()
Maybe one of the elders will step in and lift the veil.
#4
Thanks for responding.
10/23/2006 (2:32 pm)
Wow!!! Echo() is my new best friend! Problems solved.Thanks for responding.
#5
I'm curious what you did. I haven't fiddled with 3D yet, but if you figured out how rotating a 3D object works, would you mind posting your solution here? I'm going to be fiddling with 3D asteroids soon and could use any headstart you can provide. :D
10/23/2006 (5:41 pm)
@AlexI'm curious what you did. I haven't fiddled with 3D yet, but if you figured out how rotating a 3D object works, would you mind posting your solution here? I'm going to be fiddling with 3D asteroids soon and could use any headstart you can provide. :D
#6
To begin I would like to make a few comments about Maya 7 and the DTS exporter. In all the instructions I found the order for exporting started with creating the bounding box. I tried this but when I got to export I got the error message "no bounds found." The order for exporting that worked for me was:
1. Embed Shape
2. Renumber Selection (just type a number, like "2")
3. Register Details
4. Create (and lock) Bounding Box
5. Export
That exported the object however, the default bounding box was too small and only a section of the object appeared in TGB. So I went back to Maya, increased the bounding box size (in the Channel Tab), and hit the export button again. Thats enough of dts and maya, the next post will be about scripting a 3D object in TGB 1.1.2.
10/23/2006 (6:07 pm)
Ok, here goes. I'm using Maya 7 on a Powerbook G4 running OS X 10.4.8.To begin I would like to make a few comments about Maya 7 and the DTS exporter. In all the instructions I found the order for exporting started with creating the bounding box. I tried this but when I got to export I got the error message "no bounds found." The order for exporting that worked for me was:
1. Embed Shape
2. Renumber Selection (just type a number, like "2")
3. Register Details
4. Create (and lock) Bounding Box
5. Export
That exported the object however, the default bounding box was too small and only a section of the object appeared in TGB. So I went back to Maya, increased the bounding box size (in the Channel Tab), and hit the export button again. Thats enough of dts and maya, the next post will be about scripting a 3D object in TGB 1.1.2.
#7
A 3D object in TGB has 3 axes about which it can rotate, X, Y, and Z. X and Y form the 2 dimensional plane in which the game takes place, and Z points out of the game/screen. There are four functions that deal with Shape (as in a 3D shape) Rotation as listed in the TGB Reference PDF: getShapeRotation(), setShapeRotation(), getShapeAngularVelocity, and setShapeAngularVelocity(). Both the ShapeRotation and ShapeAngularVelocity functions carry three arguments referring to the X, Y, and Z axes. You can get and set these arguments with getWord() and an index, for example:
%rotationZ = getWord(%this.getShapeRotation(), 1); //gets the Rotation of the object about the Z-axis
or
%this.setShapeAngularVelocity(0,0,%newAngVel); //sets the Angular Velocity about the Z-axis
Let me talk about ShapeRotation for a minute. As you can see in my first example index 1 refers to the Z-axis for the rotation functions. You can check for yourself to find out what indices 0 and 2 point to. The getShapeRotation() function returns a radian value, or at least it should. What actually happens is this: as an object rotates (counter clockwise about the Z-axis) it begins counting down radians (from zero) until it gets to negative pi/4 (-90 degrees), then it begins counting back up to zero. At pi/4 indices 0 and 2 flip from -0 to -pi radians. If you are following me then you should be saying to yourself right now, "WTF?!?!"
To continue, at pi/2 (180 degrees) index 1 gets to zero radians and begins counting up (not down) to pi/4, and index 2 flips from negative pi to positive pi. (If a GG developer is reading this please tell me why don't the ShapeRotation values go from 0 to 2pi like they do in all the physics books I read in the five years I spent getting my bachelors in physics?) Finally, at 3/2 pi (270 degrees) index 0 flips from negative pi to -0 (what in the name of god is negative zero?????) and index 2 flips from pi to 0. I am scripting a boat not an asteroid so my solutions will be different than yours, but this is how I took control of the boat:
if (getWord(%this.getShapeRotation(), 0) == -3.141593)
{
%newSpeedY = %this.getLinearVelocityY() - mCos(getWord(%this.getShapeRotation(), 1)) * %impulse;
%newSpeedX = %this.getLinearVelocityX() - mSin(getWord(%this.getShapeRotation(), 1)) * %impulse;
}
else if (getWord(%this.getShapeRotation(), 0) == 3.141593)
{
%newSpeedY = %this.getLinearVelocityY() - mCos(getWord(%this.getShapeRotation(), 1)) * %impulse;
%newSpeedX = %this.getLinearVelocityX() - mSin(getWord(%this.getShapeRotation(), 1)) * %impulse;
}
else
{
%newSpeedY = %this.getLinearVelocityY() + mCos(getWord(%this.getShapeRotation(), 1)) * %impulse;
%newSpeedX = %this.getLinearVelocityX() - mSin(getWord(%this.getShapeRotation(), 1)) * %impulse;
}
%newAngVel = getWord(%this.getShapeAngularVelocity(),1) * 50 + %moment;
%this.setLinearVelocityX(%newSpeedX);
%this.setLinearVelocityY(%newSpeedY);
%this.setShapeAngularVelocity(0,0,%newAngVel);
Next posting: ShapeAngularVelocity
10/23/2006 (7:11 pm)
What I found out by carefully watching echo() as my 3D object spun around was this:A 3D object in TGB has 3 axes about which it can rotate, X, Y, and Z. X and Y form the 2 dimensional plane in which the game takes place, and Z points out of the game/screen. There are four functions that deal with Shape (as in a 3D shape) Rotation as listed in the TGB Reference PDF: getShapeRotation(), setShapeRotation(), getShapeAngularVelocity, and setShapeAngularVelocity(). Both the ShapeRotation and ShapeAngularVelocity functions carry three arguments referring to the X, Y, and Z axes. You can get and set these arguments with getWord() and an index, for example:
%rotationZ = getWord(%this.getShapeRotation(), 1); //gets the Rotation of the object about the Z-axis
or
%this.setShapeAngularVelocity(0,0,%newAngVel); //sets the Angular Velocity about the Z-axis
Let me talk about ShapeRotation for a minute. As you can see in my first example index 1 refers to the Z-axis for the rotation functions. You can check for yourself to find out what indices 0 and 2 point to. The getShapeRotation() function returns a radian value, or at least it should. What actually happens is this: as an object rotates (counter clockwise about the Z-axis) it begins counting down radians (from zero) until it gets to negative pi/4 (-90 degrees), then it begins counting back up to zero. At pi/4 indices 0 and 2 flip from -0 to -pi radians. If you are following me then you should be saying to yourself right now, "WTF?!?!"
To continue, at pi/2 (180 degrees) index 1 gets to zero radians and begins counting up (not down) to pi/4, and index 2 flips from negative pi to positive pi. (If a GG developer is reading this please tell me why don't the ShapeRotation values go from 0 to 2pi like they do in all the physics books I read in the five years I spent getting my bachelors in physics?) Finally, at 3/2 pi (270 degrees) index 0 flips from negative pi to -0 (what in the name of god is negative zero?????) and index 2 flips from pi to 0. I am scripting a boat not an asteroid so my solutions will be different than yours, but this is how I took control of the boat:
if (getWord(%this.getShapeRotation(), 0) == -3.141593)
{
%newSpeedY = %this.getLinearVelocityY() - mCos(getWord(%this.getShapeRotation(), 1)) * %impulse;
%newSpeedX = %this.getLinearVelocityX() - mSin(getWord(%this.getShapeRotation(), 1)) * %impulse;
}
else if (getWord(%this.getShapeRotation(), 0) == 3.141593)
{
%newSpeedY = %this.getLinearVelocityY() - mCos(getWord(%this.getShapeRotation(), 1)) * %impulse;
%newSpeedX = %this.getLinearVelocityX() - mSin(getWord(%this.getShapeRotation(), 1)) * %impulse;
}
else
{
%newSpeedY = %this.getLinearVelocityY() + mCos(getWord(%this.getShapeRotation(), 1)) * %impulse;
%newSpeedX = %this.getLinearVelocityX() - mSin(getWord(%this.getShapeRotation(), 1)) * %impulse;
}
%newAngVel = getWord(%this.getShapeAngularVelocity(),1) * 50 + %moment;
%this.setLinearVelocityX(%newSpeedX);
%this.setLinearVelocityY(%newSpeedY);
%this.setShapeAngularVelocity(0,0,%newAngVel);
Next posting: ShapeAngularVelocity
#8
Your asteroids probably won't have rockets on them so you probably won't have to worry about this. Maybe there is a reason for it, I don't know. I hope this helps. If you need me to clarify anything I will try.
10/23/2006 (7:23 pm)
Now for ShapeAngularVelocity. The only thing I really want to say is that getShapeAngularVelocity() and setShapeAngularVelocity don't play well together. If you notice in my last post when I set the new Angular Velocity I have to multiply getWord(%this.getShapeAngularVelocity(),1) by 50. The function getShapeAngularVelocity() returns a tiny number, which, if you put back into setShapeAngularVelocity(), will kill the movement of your object.Your asteroids probably won't have rockets on them so you probably won't have to worry about this. Maybe there is a reason for it, I don't know. I hope this helps. If you need me to clarify anything I will try.
#9
That makes me immediately guess that getShapeAngularVelocity is returning radians whereas setShapeAngularVelocity uses degrees. The conversion faction is 180/pi, which is about 57.29
Perhaps that's the problem there.
If I get a chance, I'll throw together some test cases and report back here.
10/23/2006 (8:23 pm)
Quote:If you notice in my last post when I set the new Angular Velocity I have to multiply getWord(%this.getShapeAngularVelocity(),1) by 50.
That makes me immediately guess that getShapeAngularVelocity is returning radians whereas setShapeAngularVelocity uses degrees. The conversion faction is 180/pi, which is about 57.29
Perhaps that's the problem there.
If I get a chance, I'll throw together some test cases and report back here.
#10
10/23/2006 (10:30 pm)
I thought it might be radians but I couldn't tell from echo(). I think you're right. Good call.
#11
Thanks for the input. I'm almost at the point where I'll be working on the 3D asteroids. Your posts should help a lot! I'm actually curious how to make a 3D object rotate on collision as well (obviously), so it will be cool to see what you come up with. I'll have to post my results as well when I get to it. :)
10/24/2006 (4:17 pm)
@AlexThanks for the input. I'm almost at the point where I'll be working on the 3D asteroids. Your posts should help a lot! I'm actually curious how to make a 3D object rotate on collision as well (obviously), so it will be cool to see what you come up with. I'll have to post my results as well when I get to it. :)
#12
I think conservation of angular momentum is handled in 2D by the Rigid body response, and I found reference to a RigidShape class for TGE but not for TGB. Therefore, it would seem there is no code written to transfer angular momentum for Shapes in TGB. I might be wrong but it would seem this is the case.
So I'm going to write my own RigidShape response for TGB in script, and post it here in a few days. Stay tuned if you care to find out how this turns out.
10/25/2006 (3:02 am)
OK, so I can control my 3D shape. Great! But how do I make it respond to collisions realistically? Giving the shape a datablock config and making its collision response to Rigid makes it bounce properly but not spin. Linear momentum is conserved but what about angular momentum?I think conservation of angular momentum is handled in 2D by the Rigid body response, and I found reference to a RigidShape class for TGE but not for TGB. Therefore, it would seem there is no code written to transfer angular momentum for Shapes in TGB. I might be wrong but it would seem this is the case.
So I'm going to write my own RigidShape response for TGB in script, and post it here in a few days. Stay tuned if you care to find out how this turns out.
#13
function playerboat::onCollision(%srcObj, %dstObj, %srcRef, %dstRef, %time, %normal, %contacts, %points)
{
// set variables
%omegaA = mRadToDeg(getWord(%dstObj.getAngularVelocity(),1));
%omegaB = mRadToDeg(getWord(%srcObj.getShapeAngularVelocity(),1));
%velA = %dstObj.getLinearVelocity();
%velB = %srcObj.getLinearVelocity();
%inertiaA = %dstObj.getInertialMoment();
%inertiaBoat = %srcObj.getInertialMoment();
%mA = 1 / %dstObj.getMass();
%mBoat = 1 / %srcObj.getMass();
%e = -1 - %srcObj.getRestitution();
%rAP = t2dVectorSub(%points, %dstObj.getPosition());
%rBP = t2dVectorSub(%points, %srcObj.getPosition());
// compute cross product of the angular velocity and the point of impact vector
// for the OTHER object
%x3A = %omegaA;
%y1A = getWord(%rAP, 0);
%y2A = getWord(%rAP, 1);
%compXap = -%x3A * %y2A;
%compYap = -%x3A * %y1A;
%omegaCrossRAP = %rAP;
%omegaCrossRAP = setWord(%omegaCrossRAP, 0, %compXap);
%omegaCrossRAP = setWord(%omegaCrossRAP, 1, %compYap);
// compute cross product of the angular velocity and the point of impact vector
// for the THIS object
%x3B = %omegaB;
%y1B = getWord(%rBP, 0);
%y2B = getWord(%rBP, 1);
%compXbp = -%x3B * %y2B;
%compYbp = -%x3B * %y1B;
%omegaCrossRBP = %rBP;
%omegaCrossRBP = setWord(%omegaCrossRBP, 0, %compXbp);
%omegaCrossRBP = setWord(%omegaCrossRBP, 1, %compXbp);
// compute the relative velocities of the two points of impact on each object
// and take the dot product with the normal vector
%velAB = t2dVectorSub(t2dVectorAdd(%velA, %omegaCrossRAP), t2dVectorSub(%velB, %omegaCrossRBP));
%velABdotN = t2dVectorLength(%velAB) * mCos(t2dAngleBetween(%velAB, %normal));
// compute cross products of point of impact vectors with the normal vector
%rAPnormAngle = mSin(mRadToDeg(t2dVectorNormalise(%rAP)) - mRadToDeg(%normal));
%rBPnormAngle = mSin(mRadToDeg(t2dVectorNormalise(%rBP)) - mRadToDeg(%normal));
%rAPcrossN = t2dVectorLength(%rAP) * %rAPnormAngle;
%rBPcrossN = t2dVectorLength(%rBP) * %rBPnormAngle;
// compute the impulse
%numJ = %e * %velABdotN;
%denJ = %mA + %mBoat + mPow(%rAPcrossN, 2) / %inertiaA + mPow(%rBPcrossN, 2) / %inertiaBoat;
%J = %numJ / %denJ;
// get the new angular velocity
%newOmegaZ = %omegaB + %rBPcrossN * %J / %inertiaBoat;
%newOmegaX = mRadToDeg(getWord(%srcObj.getShapeAngularVelocity(),2));
%newOmegaY = mRadToDeg(getWord(%srcObj.getShapeAngularVelocity(),0));
// set the new angular velocity
%srcObj.setShapeAngularVelocity(%newOmegaX,%newOmegaY,%newOmegaZ);
}
Thats it. I hope someone finds this useful. If you find any problems let me know.
thanks
Alex Moran
10/31/2006 (4:24 pm)
Here it is, I've only spent a few minutes testing it but it seems to work great:function playerboat::onCollision(%srcObj, %dstObj, %srcRef, %dstRef, %time, %normal, %contacts, %points)
{
// set variables
%omegaA = mRadToDeg(getWord(%dstObj.getAngularVelocity(),1));
%omegaB = mRadToDeg(getWord(%srcObj.getShapeAngularVelocity(),1));
%velA = %dstObj.getLinearVelocity();
%velB = %srcObj.getLinearVelocity();
%inertiaA = %dstObj.getInertialMoment();
%inertiaBoat = %srcObj.getInertialMoment();
%mA = 1 / %dstObj.getMass();
%mBoat = 1 / %srcObj.getMass();
%e = -1 - %srcObj.getRestitution();
%rAP = t2dVectorSub(%points, %dstObj.getPosition());
%rBP = t2dVectorSub(%points, %srcObj.getPosition());
// compute cross product of the angular velocity and the point of impact vector
// for the OTHER object
%x3A = %omegaA;
%y1A = getWord(%rAP, 0);
%y2A = getWord(%rAP, 1);
%compXap = -%x3A * %y2A;
%compYap = -%x3A * %y1A;
%omegaCrossRAP = %rAP;
%omegaCrossRAP = setWord(%omegaCrossRAP, 0, %compXap);
%omegaCrossRAP = setWord(%omegaCrossRAP, 1, %compYap);
// compute cross product of the angular velocity and the point of impact vector
// for the THIS object
%x3B = %omegaB;
%y1B = getWord(%rBP, 0);
%y2B = getWord(%rBP, 1);
%compXbp = -%x3B * %y2B;
%compYbp = -%x3B * %y1B;
%omegaCrossRBP = %rBP;
%omegaCrossRBP = setWord(%omegaCrossRBP, 0, %compXbp);
%omegaCrossRBP = setWord(%omegaCrossRBP, 1, %compXbp);
// compute the relative velocities of the two points of impact on each object
// and take the dot product with the normal vector
%velAB = t2dVectorSub(t2dVectorAdd(%velA, %omegaCrossRAP), t2dVectorSub(%velB, %omegaCrossRBP));
%velABdotN = t2dVectorLength(%velAB) * mCos(t2dAngleBetween(%velAB, %normal));
// compute cross products of point of impact vectors with the normal vector
%rAPnormAngle = mSin(mRadToDeg(t2dVectorNormalise(%rAP)) - mRadToDeg(%normal));
%rBPnormAngle = mSin(mRadToDeg(t2dVectorNormalise(%rBP)) - mRadToDeg(%normal));
%rAPcrossN = t2dVectorLength(%rAP) * %rAPnormAngle;
%rBPcrossN = t2dVectorLength(%rBP) * %rBPnormAngle;
// compute the impulse
%numJ = %e * %velABdotN;
%denJ = %mA + %mBoat + mPow(%rAPcrossN, 2) / %inertiaA + mPow(%rBPcrossN, 2) / %inertiaBoat;
%J = %numJ / %denJ;
// get the new angular velocity
%newOmegaZ = %omegaB + %rBPcrossN * %J / %inertiaBoat;
%newOmegaX = mRadToDeg(getWord(%srcObj.getShapeAngularVelocity(),2));
%newOmegaY = mRadToDeg(getWord(%srcObj.getShapeAngularVelocity(),0));
// set the new angular velocity
%srcObj.setShapeAngularVelocity(%newOmegaX,%newOmegaY,%newOmegaZ);
}
Thats it. I hope someone finds this useful. If you find any problems let me know.
thanks
Alex Moran
Associate Tom Eastman (Eastbeast314)
I haven't played with 3D shapes in TGB yet, but I'm going to assume (given your question) that getShapeRotation returns a quaternion in the form (w, x, y, z), where w is the angle around the xyz vector. To get the values it's returning, you could use
I don't understand what you're doing beyond that, so hopefully that'll help a bit ;)