[1.1b2] SetTransform() no longer supports setting only the position - RESOLVED
by Manoel Neto · in Torque 3D Professional · 08/27/2010 (1:49 pm) · 12 replies
In the past, calling setTransform() and passing a 3-word argument (ex: "0.2 10 0") would update the object's position and preserve its rotation. In 1.1 beta 2, doing so resets the rotation, due to the way the new console methods work.
Writing directly to %object.position works in most cases, but doing so skips any additional code that might happen to be inside the object's setTransform() method since it writes directly to the object's matrix.
The proper way to "fix" this is to expose SceneObject::setPosition() to script, since it goes through setTransform() (and also looks less hack-ish than calling setTransform() to set positions):
In sceneObject.cpp, add:
Writing directly to %object.position works in most cases, but doing so skips any additional code that might happen to be inside the object's setTransform() method since it writes directly to the object's matrix.
The proper way to "fix" this is to expose SceneObject::setPosition() to script, since it goes through setTransform() (and also looks less hack-ish than calling setTransform() to set positions):
In sceneObject.cpp, add:
DefineEngineMethod( SceneObject, setPosition, void, ( Point3F pos ),,
"Set the object's position."
"@param pos object position to set" )
{
object->setPosition(pos);
}About the author
Recent Threads
#3
08/27/2010 (4:27 pm)
Quote:Related to someone changing radians to degrees?Nope, I meant that when you do this:
linky
%object.setTransform("10 0 0");It clears the %object's rotation to as well as modifying the position. In previous versions it would update only the position.
#4
So in the new macro system for exposing C++ to TorqueScript TransformF became the real parameter to setTransform(). So the handler for converting a string to a TransformF does its work... and leaves the rotation to the default settings.
The problem then is that the actual function for setTransform() doesn't know that the user only specified the position part and just applies the whole transform.
If we supported overloaded methods it would be as simple as having both a Point3F and a TransformF version of setTransform(), but unfortunately that wouldn't be very simple to do with how TorqueScript works.
I'm not sure what the best fix is here. Ideally we would want to still have setTransform() take a TransformF and not return to string parsing, but maybe we have no choice here as we need to preserve backwards compatibility.
08/27/2010 (8:31 pm)
This is bad.So in the new macro system for exposing C++ to TorqueScript TransformF became the real parameter to setTransform(). So the handler for converting a string to a TransformF does its work... and leaves the rotation to the default settings.
The problem then is that the actual function for setTransform() doesn't know that the user only specified the position part and just applies the whole transform.
If we supported overloaded methods it would be as simple as having both a Point3F and a TransformF version of setTransform(), but unfortunately that wouldn't be very simple to do with how TorqueScript works.
I'm not sure what the best fix is here. Ideally we would want to still have setTransform() take a TransformF and not return to string parsing, but maybe we have no choice here as we need to preserve backwards compatibility.
#5
08/27/2010 (9:18 pm)
Bug confirmed.
#6
1) Add a flag to TransformF to specify if the transform contains rotation or not.
2) Set this flag to true or false in ConsoleSetType( TypeTransformF ) depending on the number of words in argv[0] (pretty much what the old function did).
3) In the body of the setTransform engine method, check if the transform contains rotation. If so, call object->setTransform(), otherwise call object->setPosition() and pass only the matrix position.
08/27/2010 (9:30 pm)
I have an idea:1) Add a flag to TransformF to specify if the transform contains rotation or not.
2) Set this flag to true or false in ConsoleSetType( TypeTransformF ) depending on the number of words in argv[0] (pretty much what the old function did).
3) In the body of the setTransform engine method, check if the transform contains rotation. If so, call object->setTransform(), otherwise call object->setPosition() and pass only the matrix position.
#7
In math\mTransform.h make the changes market with comments in the following code blocks:
Now in math\mathTypes.cpp, in the ConsoleSetType( TypeTransformF ) body, make these changes:
And finally, in sceneGraph\sceneObject.cpp:
08/27/2010 (10:02 pm)
Alright, I tested and it works like a charm. Here are the changes:In math\mTransform.h make the changes market with comments in the following code blocks:
Point3F mPosition; AngAxisF mOrientation; bool mHasRotation; //<-- ADDED
TransformF()
: mPosition( Point3F::Zero ),
mOrientation( Point3F( 0, 0, 1 ), 0 ),
mHasRotation(true) //<-- ADDED
{
}void set( const Point3F& position, const AngAxisF& orientation )
{
mPosition = position;
mOrientation = orientation;
mHasRotation = true; //<--- ADDED
}void set( const MatrixF& mat )
{
mPosition = mat.getPosition();
mOrientation.set( mat );
mHasRotation = true; //<---ADDED
}And add this method:const bool hasRotation() { return mHasRotation; }Now in math\mathTypes.cpp, in the ConsoleSetType( TypeTransformF ) body, make these changes:
if( argc == 1 )
{
U32 words = 1; //<--- ADDED
for (const char* ptr = argv[ 0 ]; *ptr; ptr++) //<--- ADDED
words += (*ptr == ' ') ? 1 : 0; //<--- ADDED
aa->mHasRotation = (words == 7); //<--- ADDED
dSscanf( argv[ 0 ], "%g %g %g %g %g %g %g",
&aa->mPosition.x, &aa->mPosition.y, &aa->mPosition.z,
&aa->mOrientation.axis.x, &aa->mOrientation.axis.y, &aa->mOrientation.axis.z, &aa->mOrientation.angle );
}And finally, in sceneGraph\sceneObject.cpp:
DefineEngineMethod( SceneObject, setTransform, void, ( TransformF txfm ),,
"Set the object's transform (orientation and position)."
"@param txfm object transform to set" )
{
if (!txfm.hasRotation()) //<--- ADDED
object->setPosition( txfm.getPosition() ); //<--- ADDED
else //<--- ADDED
object->setTransform( txfm.getMatrix() );
}
#9
BTW, the counting in ConsoleSetType can be optimized. dSscanf returns the number of elements it has successfully read so simply use that to determine whether an orientation was supplied. Saves you the trouble of the initial word counting pass.
08/28/2010 (8:27 am)
Yep, perfect. Thanks Manoel!BTW, the counting in ConsoleSetType can be optimized. dSscanf returns the number of elements it has successfully read so simply use that to determine whether an orientation was supplied. Saves you the trouble of the initial word counting pass.
#10
08/29/2010 (12:02 am)
Quote:dSscanf returns the number of elements it has successfully read so simply use that to determine whether an orientation was supplied. Saves you the trouble of the initial word counting pass.Heh, I never noticed it returned anything. This makes determining the existence of rotation essentially free.
#12
09/17/2010 (4:29 pm)
Fixed in 1.1 Beta 3.
Associate David Montgomery-Blake
David MontgomeryBlake