Scale in local coordinates?

Problems building or running the engine, queries about how to use features etc.
User avatar
abacus
Gnoblar
Posts: 4
Joined: Wed Jul 23, 2008 2:48 pm

Scale in local coordinates?

Post by abacus »

Hi,

I have a Mesh that I load into an Entity, which lives in a SceneNode. This SceneNode has a SceneNode parent, which in turn has another SceneNodeParent (i.e. SceneNode --> SceneNode --> SceneNode --> Entity --> Mesh).

Now, I do several transformations in the SceneNodes, and for rotation and translation everything works fine. But when I try to scale my object non-uniformly (in the x-direction), it always seems to scale relative to the Mesh's original orientation, not relative to the orientation of the SceneNode.

After searching the forum, I found one person saying that SceneNode::scale() is always "global" (which is what I am seeing). But to me it would be more practical (and in my opinion logical) to scale my object "locally". Is there a way of doing this (apart from getting the derived transformation from the SceneNode and doing the inverse transformation on my scale vector)?
ladzin
Gnoblar
Posts: 7
Joined: Sun May 11, 2008 5:14 pm

Re: Scale in local coordinates?

Post by ladzin »

Hey,
I've had a similar problem recently. Looking into the OGRE source code, I realized the problem is OGRE doesn't handle scaling right when composing transformations. It basically treats scale as if it was commutative with rotations, but it is not (unless the scaling is uniform). So, I suppose it's best practice to assume that OGRE does not support non-uniform scales at all (even though in certain special cases it does work).

I was thinking on how to fix this, but it's quite tricky if we also want to use quaternions to represent rotation. I can only think of a solution requiring polar decomposition during every transformation concatenation (which is quite impractical). Anyone knows a better way (apart from abandoning quaternions and going matrices)?
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Wait, what? You guys need to explain better, scaling (non-uniform) works completely fine and as expected here.
nbeato
Gnome
Posts: 372
Joined: Thu Dec 20, 2007 1:00 am
Location: Florida
x 3

Post by nbeato »

R * S != S * R.

For a quick solution, make an object node, use it to rotate/translate the object. Attach a scale node as a child, use it only for scaling. Then attach your mesh to the scale node.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

nbeato wrote:R * S != S * R.

For a quick solution, make an object node, use it to rotate/translate the object. Attach a scale node as a child, use it only for scaling. Then attach your mesh to the scale node.
That's my confusion, I do rotation/translation/non-uniform scaling all on one node and it works completely as expected :|
User avatar
haffax
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 4823
Joined: Fri Jun 18, 2004 1:40 pm
Location: Berlin, Germany
x 8

Post by haffax »

Ogre applies node transforms in SRT order, scale, rotate, translate, thus scale is applied before rotation which is the most useful way for most application.

In the odd exception, there is the possiblity nbeato explained: using a helper node. Another more light-weight approach is to "pre-rotate" the scale vector. Apply node's rotation to the scale vector and that then to the node.
team-pantheon programmer
creators of Rastullahs Lockenpracht
ladzin
Gnoblar
Posts: 7
Joined: Sun May 11, 2008 5:14 pm

Post by ladzin »

OK I admit I didn't have time to test it out but based on what I see in the OGRE source code, specifically,

Code: Select all

    void Node::updateFromParentImpl(void) const
    {
        if (mParent)
        {
            // Update orientation
            const Quaternion& parentOrientation = mParent->_getDerivedOrientation();
            if (mInheritOrientation)
            {
                // Combine orientation with that of parent
                mDerivedOrientation = parentOrientation * mOrientation;
            }
			else
            {
                // No inheritence
                mDerivedOrientation = mOrientation;
            }

            // Update scale
            const Vector3& parentScale = mParent->_getDerivedScale();
            if (mInheritScale)
            {
                // Scale own position by parent scale, NB just combine
                // as equivalent axes, no shearing
                mDerivedScale = parentScale * mScale;
            }
            else
            {
                // No inheritence
                mDerivedScale = mScale;
            }

            // Change position vector based on parent's orientation & scale
            mDerivedPosition = parentOrientation * (parentScale * mPosition);

            // Add altered position vector to parents
            mDerivedPosition += mParent->_getDerivedPosition();
        }
        else
        {
            // Root node, no parent
            mDerivedOrientation = mOrientation;
            mDerivedPosition = mPosition;
            mDerivedScale = mScale;
        }

		mCachedTransformOutOfDate = true;
		mNeedParentUpdate = false;

    }
I conclude that OGRE never combines rotation with scale and therefore can only do scaling in world coordinates, no matter how many helper nodes you use. Pre-rotating scaling vector also can't possibly produce scale with respect to rotated coordinate axes (2D example: imagine a square that you want to scale in direction (1,1) but leave alone in direction (-1,1)).

I'd be very happy if you proved me wrong though, and local scale somehow worked in OGRE.
User avatar
abacus
Gnoblar
Posts: 4
Joined: Wed Jul 23, 2008 2:48 pm

Post by abacus »

Ok, here is a simple example.

I create a node and a childNode, and attach a "robot.mesh"-entity to the childNode. Then I try the following 2 cases:
a) only scale the (parent) node (500,100,100)
b) rotate the childNode 90 degrees around the Z-axis, and scale the (parent) node (500,100,100)

Here is the code for case (a):

Code: Select all

    Ogre::Entity* entity = sceneMgr->createEntity("robot", "robot.mesh");
    Ogre::SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode("LevelNode");
    node->scale(500,100,100);
    Ogre::SceneNode* childNode = node->createChildSceneNode("childnode");
    childNode->attachObject(entity);
And here is the code for case (b):

Code: Select all

    Ogre::Entity* entity = sceneMgr->createEntity("robot", "robot.mesh");
    Ogre::SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode("LevelNode");
    node->scale(500,100,100);
    Ogre::SceneNode* childNode = node->createChildSceneNode("childnode");
    childNode->rotate(Ogre::Quaternion(Ogre::Degree(90), Ogre::Vector3::UNIT_Z));
    childNode->attachObject(entity);
In case (a), the robot should become fat along the x-axis.
In case (b), the robot should rotate 90 degrees, and then become TALLER along the x-axis (since the robot has rotated). But what happens, is that the robot becomes fat along the y-axis (which is the mesh's x-axis).

I have included pictures below of case (a) and case (b) (the camera is pointing towards negative Z).

Case (a):
Image

Case (b):
Image

Case (a) is of course correct.
Case (b) is wrong; it behaves as if the scaling was done before the rotation.
ladzin
Gnoblar
Posts: 7
Joined: Sun May 11, 2008 5:14 pm

Post by ladzin »

Thanks for working out an example, Abacus, that's exactly what I meant too. I've a problem with this in skeletal animation where I wanted to non-uniformly scale some bones to make some body parts more fat or thin, but it just wouldn't work correctly.

I wonder if other popular 3D engines have the same issue...
Brainshack
Greenskin
Posts: 118
Joined: Tue Feb 19, 2008 1:01 pm

Post by Brainshack »

I cant see why b) in your example should be wrong. You first scale it the same way you do in a) and then scale it. So the result is imho absolutely correct. It looks like when you would rotate a, what in fact is what your code does...
Image
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 535

Post by Kojack »

Yep, basically Ogre doesn't treat scales the same way a chain of matrices would work. It multiplies each scale by it's parent's scale, without using the orientation relative to the parent. This means the local axes of a node will always be orthogonal after transforming.

One possibility would be to handle the matrices manually, then pass them to the entity as a shader parameter. Of course then ogre's scene culling isn't going to exactly match.

Most people don't notice since they only scale uniformly or not at all (preferable, so no renormalising of the surface normals is needed).
nbeato
Gnome
Posts: 372
Joined: Thu Dec 20, 2007 1:00 am
Location: Florida
x 3

Post by nbeato »

Kojack wrote:Yep, basically Ogre doesn't treat scales the same way a chain of matrices would work. It multiplies each scale by it's parent's scale, without using the orientation relative to the parent. This means the local axes of a node will always be orthogonal after transforming.
Considering Ogre is a rendering scene graph, isn't this a bug? The scale axes should be in the local or parent coordinate frame, not global. How much stuff would this break? I can probably code a fix, but I don't want to step on toes.
JDX_John
Gnome
Posts: 397
Joined: Sat Nov 08, 2008 1:59 pm
x 2

Re: Scale in local coordinates?

Post by JDX_John »

[REMOVED - posted in wrong thread]
Last edited by JDX_John on Sat Feb 14, 2009 10:15 am, edited 1 time in total.
User avatar
haffax
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 4823
Joined: Fri Jun 18, 2004 1:40 pm
Location: Berlin, Germany
x 8

Re: Scale in local coordinates?

Post by haffax »

Completely different issues. This thread is about non-uniform scaling of nodes.
The other thread is about an export problem, as far as I can see. Morphing is done in a different manner.

JDXSolutions, what is the problem you actually want to have solved?
team-pantheon programmer
creators of Rastullahs Lockenpracht
JDX_John
Gnome
Posts: 397
Joined: Sat Nov 08, 2008 1:59 pm
x 2

Re: Scale in local coordinates?

Post by JDX_John »

haffax wrote:Completely different issues. This thread is about non-uniform scaling of nodes.
The other thread is about an export problem, as far as I can see. Morphing is done in a different manner.

JDXSolutions, what is the problem you actually want to have solved?
Sorry I was meaning to post in the other thread... we think the problem may not be the exporter after all but Ogre's scaling - I was going to post this thread to the other one and got mixed up :)
User avatar
iloseall
Gremlin
Posts: 156
Joined: Sun Sep 14, 2003 3:54 am
Location: Beijing China

Re: Scale in local coordinates?

Post by iloseall »

what's about non-uniform scaling now(1.7 trunk) in ogre's bone/node?