Place objects when loading the map
by Alfio Saitta · in Torque 3D Professional · 05/01/2010 (7:16 pm) · 9 replies
With Blender, i have exported as nodes, the position and rotation of certain objects in the scene. With an scripts, I extract very simply the values. But now I can not to read those values to create and move in the correct place the new objects, directly when loading the map.
I do not get anything with:
But it works if i load the dts file in the ShapeEditor. From log:
I do not get anything with:
datablock TSShapeConstructor(TestLoaderDts)
{
baseShape = "./TestLoader.dts";
};
function TestLoaderDts::onLoad(%this)
{
echo("---------------------------------------------------");
echo("-- Dump all ChildNodes with WorldSpace Transform --");
echo("---------------------------------------------------");
%nodeName = "LightsNodes";
%count = %this.getNodeChildCount(%nodeName);
for (%i = 0; %i < %count; %i++)
{
%childName = %this.getNodeChildName(%nodeName, %i);
%pos = %this.getNodePosition(%childName, true);
%rot = %this.getNodeRotation(%childName, true);
echo(" *) " @ %childName @ ": POS= (" @ %pos @ ") - ROT= (" @ %rot @ ")");
}
echo("---------------------------------------------------");
}But it works if i load the dts file in the ShapeEditor. From log:
--------------------------------------------------- -- Dump all ChildNodes with WorldSpace Transform -- --------------------------------------------------- *) Lamp_001: POS= -7.70346 -7.56811 2.60694 - ROT= 1 0 0 0 *) Spot_001: POS= 0 -5.41756 2.60694 - ROT= -1 0 0 0.163453 *) Spot_002: POS= -5.21938 2.42546 2.60694 - ROT= 0 1 0 0.280033 ---------------------------------------------------
About the author
Recent Threads
#2
What's wrong?
This is the model in ShapeEditor:

And this is the result:
05/02/2010 (6:09 pm)
As I wrote above, I solved the problem of the script execution. But is normal, I stumbled upon another problem. With the script, I can read the values of the nodes in WorldSpace, but do not match the actual positions.What's wrong?
function TestLoaderDts::onLoad(%this)
{
....
%nodeName = "LightsNodes";
%count = %this.getNodeChildCount(%nodeName);
for (%i = 0; %i < %count; %i++)
{
%childName = %this.getNodeChildName(%nodeName, %i);
%trans = %this.getNodeTransform(%childName, true);
%pos = getWords(%trans, 0, 2);
%rot = getWords(%trans, 3, 6);
echo(" *) " @ %childName @ ": POS= " @ %pos @ " - ROT= " @ %rot);
%NewLight = new PointLight(%childName) {
....
position = %pos;
rotation = %rot;
....
};
MissionCleanup.add(%NewLight);
}
....
}This is the model in ShapeEditor:

And this is the result:
#3
05/03/2010 (7:57 am)
I'm not familiar with TSShapeConstructor, but it looks like your lights are being created with the correct relative positions and orientations with respect to each other. I bet getNodeTransform() returns the node's position in object space, so the lights end up positioned around the origin rather than your object in world space. If so, you need to transfrom their positions by your object's world transform. So after the object has been created in the world (I'm assuming onLoad() is executed before actual instantiation), try something like this for each light: %worldTrans = myObject.getTransform(); %lightPos = myLight.getPosition(); %lightPos = MatrixMulPoint(%worldTrans, %lightPos); myLight.setTransform(%lightPos); myLight.setScale(myLight.getScale()); // Forces network update
#4
With that said, I think it would be much easier to modify the source code to accomplish your automatic placement of lights. For example, you could modify TSStatic::onAdd() to look for "LightsNodes" (if it's executing server-side). Here you have direct access to the TSShape and the object's world transform, so it should be easy to create the pointlights at the child node positions.
05/03/2010 (12:50 pm)
I've been researching what you're trying to do, and I'm not sure it can be done with the TSShapeConstructor. The reason being, the TSShapeConstructor executes before the object using the DTS is created; therefore, it does not have access to the world position of the nodes because the object has not been transformed into world space yet. Although the code snippet I posted above works after the object is created, there is no easy way (that I've found) to tie the lights created in the onLoad() method to the object for whom the TSShapeConstructor was called. With that said, I think it would be much easier to modify the source code to accomplish your automatic placement of lights. For example, you could modify TSStatic::onAdd() to look for "LightsNodes" (if it's executing server-side). Here you have direct access to the TSShape and the object's world transform, so it should be easy to create the pointlights at the child node positions.
#5
Nothing. I can not get out. And I find nothing in the documentation. :D
@Ryan: You're right, using the constructor is virtually impossible without changing the code.
05/05/2010 (8:42 am)
Now the coordinates returned by the main object is correct.Nothing. I can not get out. And I find nothing in the documentation. :D
@Ryan: You're right, using the constructor is virtually impossible without changing the code.
singleton TSShapeConstructor(TestLoaderDts)
{
baseShape = "./TestLoader.dts";
};function TestLoaderDts::onLoad(%this)
{
echo("---------------------------------------------------");
echo("-- Dump all ChildNodes with WorldSpace Transform --");
echo("---------------------------------------------------");
%nodeName = "LightsNodes";
$MapNodeCount = %this.getNodeChildCount(%nodeName);
for (%i = 0; %i < $MapNodeCount; %i++)
{
%childName = %this.getNodeChildName(%nodeName, %i);
%trans = %this.getNodeTransform(%childName, true);
$MapLightPos[%i] = getWords(%trans, 0, 2);
$MapLightRot[%i] = getWords(%trans, 3, 6);
echo(" *) " @ %childName @ ": POS= " @ $MapLightPos[%i] @ " - ROT= " @ $MapLightRot[%i]);
}
echo("---------------------------------------------------");
}function populateMap(%obj )
{
%RootPosition = %obj.getposition();
for (%i = 0; %i < $MapNodeCount; %i++)
{
%pos = MatrixMulPoint(%RootPosition, $MapLightPos[%i]);
%rot = $MapLightRot[%i];
echo ( "* MapLight_" @ %i @ ": POS = " @ %pos @ " ROT = " @ %rot);
%NewLight = new PointLight(MapLight_ @ %i) {
....
position = %pos;
rotation = %rot;
....
};
MissionGroup.add(%NewLight);
%NewLight.setTransform(%pos);
%NewLight.setScale(%NewLight.getScale());
}
}
#6
But there's no reason why you can't do something like this:
Disclaimer: example only; not tested for syntax/logic errors.
05/05/2010 (3:42 pm)
It may not be obvious from the TSShapeConstructor documentation, but TSShapeConstructor is just a normal SimObject, so you don't have to use the onLoad interface if that is not suitable for your purposes. The onLoad interface is useful for modifying the loaded shape before it is used by other game objects (Player, TSStatic, WheeledVehicle etc).But there's no reason why you can't do something like this:
function populateMap(%obj)
{
// Get a TSShapeConstructor for this object (use the ShapeEditor
// utility functions to create one if it does not already exist).
%shapePath = ShapeEditor.getObjectShapeFile(%obj);
%shape = ShapeEditor.findConstructor(%shapePath);
if (!isObject(%shape))
%shape = ShapeEditor.createConstructor(%shapePath);
if (!isObject(%shape))
{
echo("Failed to create TSShapeConstructor for " @ %obj.getId());
return;
}
%rootTxfm = %obj.getTransform();
%nodeName = "LightsNodes";
%count = %shape.getNodeChildCount(%nodeName);
for (%i = 0; %i < %count; %i++)
{
%childName = %shape.getNodeChildName(%nodeName, %i);
// get node transform in object space, then transform to world
// space
%trans = %shape.getNodeTransform(%childName, true);
%trans = MatrixMultiply(%rootTxfm, %trans);
%pos = getWords(%trans, 0, 2);
%rot = getWords(%trans, 3, 6);
echo(" *) " @ %childName @ ": POS= " @ %pos @ " - ROT= " @ %rot);
// create a new light at the desired transform
%light = new PointLight(MapLight_ @ %i) {
....
position = %pos;
rotation = %rot;
....
};
MissionGroup.add(%light);
}
}Disclaimer: example only; not tested for syntax/logic errors.
#7
05/07/2010 (11:27 am)
@Chris: Thank you very much, your code works fine. My error was in calculating the matrix. Unfortunately, I never find the proper documentation. At this point I have to call up the complete code at the appropriate time. Thank you again
#8
you could then do this in TS:
05/07/2010 (2:58 pm)
Why not just addCon::executef(this, "onAdd", Con::getIntArg(getId()));to the TSShapeConstructors onAdd method (not sure why it doesn't exist there already). Then you could add your lights after it has been loaded and added to the scene.
you could then do this in TS:
function TestLoaderDts::onadd(%obj){
// Get a TSShapeConstructor for this object (use the ShapeEditor
// utility functions to create one if it does not already exist).
%shapePath = ShapeEditor.getObjectShapeFile(%obj);
%shape = ShapeEditor.findConstructor(%shapePath);
if (!isObject(%shape))
%shape = ShapeEditor.createConstructor(%shapePath);
if (!isObject(%shape))
{
echo("Failed to create TSShapeConstructor for " @ %obj.getId());
return;
}
%rootTxfm = %obj.getTransform();
%nodeName = "LightsNodes";
%count = %shape.getNodeChildCount(%nodeName);
for (%i = 0; %i < %count; %i++)
{
%childName = %shape.getNodeChildName(%nodeName, %i);
// get node transform in object space, then transform to world
// space
%trans = %shape.getNodeTransform(%childName, true);
%trans = MatrixMultiply(%rootTxfm, %trans);
%pos = getWords(%trans, 0, 2);
%rot = getWords(%trans, 3, 6);
echo(" *) " @ %childName @ ": POS= " @ %pos @ " - ROT= " @ %rot);
// create a new light at the desired transform
%light = new PointLight(MapLight_ @ %i) {
....
position = %pos;
rotation = %rot;
....
};
MissionGroup.add(%light);
}
}
#9
TSShapeConstructor::onLoad is used to modify the 3D shape resource in-memory before it is used by other game objects. If you want to do game object specific actions (as in this case), you need to do it once that game object has been created.
05/07/2010 (8:10 pm)
@Ryan: This wouldn't work because the TSShapeConstructor object is tied to the 3D shape resource (DTS or DAE file) rather than a specific game object (TSStatic, Player, WheeledVehicle etc). When the TSShapeConstructor object's onLoad method is called, it doesn't know what object (may be more than 1!) is going to use the 3D shape resource.TSShapeConstructor::onLoad is used to modify the 3D shape resource in-memory before it is used by other game objects. If you want to do game object specific actions (as in this case), you need to do it once that game object has been created.
Torque Owner Alfio Saitta
Collateral Studios
singleton TSShapeConstructor(TestLoaderDts) { baseShape = "./TestLoader.dts"; };instead of:datablock TSShapeConstructor(TestLoaderDts) { baseShape = "./TestLoader.dts"; };