Page 1 of 1

Transformation Error with Parent

Posted: Thu Mar 23, 2006 5:01 am
by nutpor
Hi all :) ,

I moved this thread from bugs report forum.

First, let me explain the situation.
Suppose I create 3 scenenodes, named nodeA, nodeB and nodeC which all of them are child of root scenenode.
Then I add node to nodeA, nodeB
Parent Children
----------------------------------------
nodeA nodeA1
nodeA nodeA2
nodeA nodeA3

nodeB nodeB1
nodeB nodeB1
nodeB nodeB1

I want to setParent of nodeA1-3 and nodeB1-3 to nodeC but
position, rotation and scaling of children node MUST NOT change so I needed to recalculate each position, rotation and scaling to relative with new parent which is nodeC but position and scaling are mess up!

Here is my code for grouping

Code: Select all

// nodeList : list of node to be group
// refIndex : index of node that will be a reference position, rotation, scaling of other node in group
irr::scene::ISceneNode* CSceneNodeFactory::groupSceneNode(std::vector<irr::scene::ISceneNode*>& nodeList, irr::s32 refIndex, irr::scene::ISceneManager* smgr)
{
	if (nodeList.size() == 0 || refIndex < 0 || !smgr)
	{
		return 0;
	}

	// Create a new groupSceneNode for all SceneNode in nodeList.
	ISceneNode* newGroup = CSceneNodeFactory::createGroupSceneNode(0, smgr);


	// Set position for the new groupSceneNode.
	ISceneNode* currentNode = nodeList.at(refIndex);
	newGroup->setPosition(currentNode->getPosition());
	newGroup->setRotation(currentNode->getRotation());
	//newGroup->setScale(currentSceneNode->getScale());


	irr::core::list<ISceneNode*>::Iterator itr;
	irr::core::list<ISceneNode*> newList;
	irr::core::list<ISceneNode*> children;

	for (u32 i = 0; i < nodeList.size(); ++i)
	{
		currentNode = nodeList.at(i);
	
		if (currentNode->getChildren().getSize() > 0)
		{
			// has children
			itr = currentNode->getChildren().begin();
			for (; itr != currentNode->getChildren().end(); ++itr)
			{
				irr::scene::ISceneNode* node = (*itr);
				vector3df newPos;
				vector3df newRot;
				vector3df newScl;

				vector3df myScale;
				vector3df parentScale;

				matrix4 mat;
				node->updateAbsolutePosition();
				mat = node->getAbsoluteTransformation();
				CLogger::print("before", mat.getTranslation());
				CLogger::print("mat", getScale(mat));

				newPos = (node->getPosition() + currentNode->getPosition()) - newGroup->getPosition();
				newRot = (node->getRotation() + currentNode->getRotation()) - newGroup->getRotation();
				myScale = node->getScale();
				parentScale = currentNode->getScale();
				newScl.X = myScale.X * parentScale.X;
				newScl.Y = myScale.Y * parentScale.Y;
				newScl.Z = myScale.Z * parentScale.Z;

				node->setPosition(newPos);
				node->setRotation(newRot);
				//node->setScale(newScl);
				newList.push_back(node);

				node->updateAbsolutePosition();
				mat = node->getAbsoluteTransformation();

			}
			deleteSceneNode(currentNode, smgr, 1);
			currentNode = 0;
		}
		else
		{
			irr::scene::ISceneNode* node = currentNode;
			vector3df newPos;
			vector3df newRot;
			vector3df newScl;

			newPos = node->getPosition() - newGroup->getPosition();
			newRot = node->getRotation() - newGroup->getRotation();
			newScl = node->getScale();

			node->setPosition(newPos);
			node->setRotation(newRot);
			node->setScale(newScl);
			newList.push_back(node);
		}
	}


	for (itr = newList.begin(); itr != newList.end(); ++itr)
	{
		(*itr)->setParent(newGroup);
	}

	return newGroup;
}
createGroupSceneNode() is creating empty scene node that doesn't do anything more than conthainer of scene node.

Code: Select all

virtual core::matrix4 getRelativeTransformation() const
	{
		core::matrix4 mat;

		mat.setRotationDegrees(RelativeRotation);	

		if (RelativeScale != core::vector3df(1,1,1))
		{
			core::matrix4 smat;
			smat.setScale(RelativeScale);
			mat *= smat;
		}

		mat.setTranslation(RelativeTranslation);

		return mat;
	}
Any help would by greatly appreciated. :)

Posted: Thu Mar 23, 2006 12:08 pm
by Acki
Yes that's normal...
If a node has for example a scale of 2 and you add another as child to it, the child will become the same scale as the parent added to his own scale !!!
So if node 2 has also a scale of 2 it will become a scale of 4...

So you have to recalculate the scale, position and rotation of the child...
Well, I didn't get this really to work this way...
I did it with a 3rd node (IEmptySceneNode) that becomes the parent of both...
The empty scene node has a position and rotation of (0, 0, 0) and scale of (1, 1, 1) so it doesn't affect the other nodes...

Well, it also should work the other way...

Code: Select all

child->setRotation(parent->getRotation() - child->getRotation());
child->setPosition(parent->getPosition() - child->getPosition());
child->setScale(parent->getScale() / child->getScale());
But there is something wrong, it doesn't work...
Maybe the code isn't correct, I wrote it out of remembrance... ;)

Posted: Thu Mar 23, 2006 4:50 pm
by nutpor
Suppose parent's scale is 2,2,2 and child's scale is 3,3,3.
If I create new empty node which scale is 1,1,1 and move child to this node I have to set child's scale to 6,6,6 right?
I've tried this but it still doesn't works.

Posted: Fri Mar 24, 2006 1:48 am
by Acki
Yes, that's right...

For position and rotation you can also try to set the parent to rot(0,0,0) and pos(0,0,0) than add the child and set the parent back to it's position...

For scale I don't know, maybe someone else knows how to calculate the new scale for a child node ???

Posted: Fri Mar 24, 2006 4:25 am
by nutpor
For Example:
nodeA :
parent = root
position(100,100,0)
rotation(0,0,0)
sscale(2,2,2)

nodeB :
parent = nodeA
position(50,50,50)
rotation(0,0,0)
scale(1,1,1)

if I new nodeC :
parent = root
position(50,50,50)
rotation(0,0,0)
scale(1,1,1)
And setParent of nodeB to nodeC
then nodeB become :
parent = nodeC
position(100,100,0)
rotation(0,0,0)
scale(2,2,2)
to make nodeC still rendered at same position and same scale
I print debug value of each node it print right but it render wrong!