object->GetMg() sometimes fail..



  • On 15/06/2013 at 15:14, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R13-R14 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    I have a NULL object sitting on another objects, which rotates in 3D space.
    I read the global rotation from the NULL using object->GetMg()
    For most of the rotation, all is fine. But at one part of the circle, in which the NULL's parent rotates, I get weird results using object->GetMg(). 
    As a matter of fact, the Roations data (World) shown in the C4D user interface, also shows these "false" data. But the NULL sits just fine on its parent, it does not move at all.

    I find it interesting that the NULL just behaves normal, and sits nicely on its parent object, and at the same time both I in my code, and C4D in the Rotation window, these erroneous data exist.

    I need to get correct rotation data from the NULL.
    Can I use a Quaternion  here? Or is there another way?
    And is there some source code somewhere that will show me how to do this?



  • On 15/06/2013 at 23:20, xxxxxxxx wrote:

    Remember that the object's global matrix considers not only the object itself but all of its parent's local matrices (transforms) up to the root.  Put simply, if a parent is changing PSR it will affect the global matrix of the object.

    Global matrix of object = local.ParentA * local.ParentB * ... * local.object

    There are ways to counteract this but they require some fancy transformational footwork.  One 'trick' would be to remove the object and put it back in the root, apply the rotation, and then put it back under its direct parent.  But you would need let C4D do the local PSR corrections or work out the transforms in both directions the way C4D does.



  • On 16/06/2013 at 02:30, xxxxxxxx wrote:

    Thanks, I understand what you write, but am absolutely confused about how C4D works.
    I have this NULL, a child in a hierarchy.

    > Put simply, if a parent is changing PSR it will affect 
    > the global matrix of the object.
    This I understand.

    So what do I do, I add a free standing cube to the scene. This cube has no parent
    I add a PSR constraint tag to the cube, and use the NULL as the target.
    What happens now?
    Yes, as the NULL sits like glued to its parent, the new freestanding Cube also moves steady as a rock, following the movement of the NULL. However, If I read out the global position of the new freestanding Cube,  from the data window in C4D, I also get these weird movements!!!
    Now - to inspect this further, I bake the constrained cube's keyframes. And then remove the constraint tag.

    Now we come to the point where my head cannot follow anything in C4D anymore.
    When looking at the curve, I get this:

    One would expect the cube to make big jumps around frame 240, right?
    But it does not. Why on earth does the cube move smoothly, when the curves look like this? BTW, the P and B curves (red and blue) are identical.
    Only when I programmatically use the rotation data and apply them to some object, then it wont work, I get, as expected, weird  movements around frame 240.

    I realize I am a beginner and that there are things I need to get to grips with.. but this is beyond my ability at the moment..



  • On 16/06/2013 at 03:34, xxxxxxxx wrote:

    Part of this is standard hierarchical transformations as expected with 3D matrix maths.  The other part which may be confusing you is that C4D uses a 'strange' (for lack of a better word) rotational system.  The HPB rotation system is based on a system that avoids so-called Gimbal Lock incurred by ordered Euler rotation systems (XYZ, YXZ, and so on).  But for that advantage (and it is a very good one), you must give up on orderly three axis rotations that are linear in each axial rotation component.

    Check out this thread (to which I posted) at CGTalk for some more explanation:

    http://forums.cgsociety.org/showthread.php?t=667471

    The big jumps while the actual rotational motion remains smooth is part of the way the HPB system works to avoid gimbal lock.



  • On 16/06/2013 at 04:40, xxxxxxxx wrote:

    Hi Robert and thanks a lot for this! 
    I have read the entire thread you linked in, and I realize that this topic is very complicated, indeed. PhD in 3D animation.. I see..
    It is impressing what you guys know about this, I believe one needs a 3D head to really get it..
    Well, for me now, I just would like an advice on how to do this:

    We see two Nulls. The outer pink Null has object_Parent as parent, and the inner Null has object_Child as parent. As the name indicates, object_Child is a child of object_Parent. These two are currently invisible in my image here, to not clutter up.

    In my animation, object_Parent and object_Child are both rotating.
    The reason I have used Nulls, is that object_Parent and object_Child have "weird", and different axis directions, so I just insert Nulls with the C4D normal x,y,z axis.  
    **
    **
    It is the relative rotation of  object_Child I am after.
    And I believe that this relative rotation is the same as the difference between the two nulls, right?

    Now, both those nulls will during the animation get  this "strange behavior" (in lack of a better word) which stems from their parents.
    What I want to do, and which I cannot do right yet, is to rotate the Cube in correspondence with the **relative rotation of  ** object_Child , which in this case ought to be the  difference between the two Nulls (?).  
    I have tried Matrices, Vectors - and the Cube follows the rotation nicely, until it is time to do the "strange hops".

            Matrix mNullOfParent = NullOfParent->GetMg();
            Matrix mNullOfChild = NullOfChild->GetMg();
            Vector vNullOfParent = MatrixToHPB(mNullOfParent, ROTATIONORDER_HPB);
            Vector vNullOfChild = MatrixToHPB(mNullOfChild, ROTATIONORDER_HPB);
            Vector vDifference = vNullOfChild - vNullOfParent;
            MyCube->SetRelRot(vDifference);
    


  • On 16/06/2013 at 06:26, xxxxxxxx wrote:

    The thing that is most important here is the 'space' in which you do transformations.  To do certain things, you must treat the object space as a global space and then conform it to another local space or a global space (as the space of interest) afterwards.  In your mind, you must see how the interactions of spaces (where the object's origin is the coordinate origin or the world origin is the object's origin) achieves the results that you desire and how to then change those interactions back into the space which exists for the situation.

    For instance, in global space, the origin of the object is typically transformed from the global origin scalarly, rotationally, and transitionally. But in object space, the transformational origin is this: 0,0,0 (no translation, no scale, no rotation) because these are factors 'outside' of the object space but imparted by its relationship to global space.  More precisely, the points of a polygonal object exist as relationships to the object's origin - and that is final. No matter the transformations, their values remain unchanged unless the user moves the points in space relative to the object.  But the local transformations change this relationship in the overall global space (where is the object, what scalar values warp it, how is it rotated).  And other objects (parents) change those factors even further.

    Think of it like this.  The object has its own coordinate system centered at its origin and the vertices are distances from that origin in 3D space.  When you place the object into a 3D global environment, there are transforms that modify these vertices to adapt to changes in the relationship of the object coordinate system with respect to the global system (such as the object being rotated, scaled, or translated therein).  If you move the object away from the global origin (0,0,0) then its properties are no longer simply a matter of it having vertices at the proscribed positions (locally). For them to be respond to the upper system, they muset be modified to have values with respect to the global system by modification (typically transitory and not direct).



  • On 16/06/2013 at 07:18, xxxxxxxx wrote:

    Thanks for this comprehensive reply! I do think I understand it now, I have some sort of seen the light.

    My challenge now is to do the same as the built in constraint tag does.
    Because that tag has no problems transforming the rotation. Yes, in the curve editor it looks strange, but who cares as long as its movement is correct. I don't care either if the algorithm I am trying to write looks weird in the curve editor, if its movement will be correct.

    But I have no idea how the built in constraint tag operates.
    Perhaps there would be possible, using the built in functions in the SDK, to invert the captured "parent space" rotations, and then apply this inverted space to the other "object space" for so to say nullify (balance out) the unwanted rotation I otherwise get in the separate object's space?



  • On 16/06/2013 at 08:17, xxxxxxxx wrote:

    I've been watching you struggle with trying to write your own parent tag in various threads. And I must say that I would also like to know how to write that kind of code.
    I don't have an example of that one in my notes.

    I've got lots of code that changes the axis independent of the object's points.  And the points independent of the object's axis.
    But all of those code examples I have result in changing the child's matrix(axis) to match the parent.
    Where the parent tag does not seem to do this. It seems to be doing some kind of special trick where it's creating a virtual null object that we don't see. Allowing the child's matrix to stay untouched.
    I'd really love to know how it's doing this too.

    -ScottA



  • On 16/06/2013 at 08:57, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    I've been watching you struggle with trying to write your own parent tag in various threads.

    Since I started with C++ in C4D one month ago, I have really made progress. I have written several plugins already, mostly because I need them for my own use, but later I might want to publish them.
    All has been smooth, I am now familiar with a lot of C++ stuff and a lot of C4D methods and properties in the SDK. The other plugins, I write in a day or two, and they really are time savers, and both let me save time and also do things that I couldn't do before in C4D. Using Visual Studio is fantastic. And my plugins work like magic.

    There is only one place where I have hit the wall - real hard - and that is regarding this rotation stuff. It is almost driving me nuts. The main challenge, is to understand how things in C4D works, why the Z axis suddenly points in absolutely the wrong direction when I have made no attempts to make it do so, etc.
    And also how to ask questions here in the forum because sometimes I have the feeling I do not know enough to ask an adequate question.

    Originally posted by xxxxxxxx

    It seems to be doing some kind of special trick where it's creating a virtual null object that we don't see

    Yes, there certainly is a lot of things going on behind the scenes.
    Currently, I have two approaches:
    a) Try to understand what goes on in depth, and write corresponding code to lure out the data I am after
    b) Insert Nulls with the standard axis orientation and just read the world coordinates from them

    The case I have been struggling with now for almost two weeks, is to detect the relative rotation between two objects whose axis are pointing in all kinds of directions.
    I tried
    a) To calculate the difference and
    b) To add Nulls as child objects and detect the difference between them. 
    Could not get a) to work at all. Basically because I am a novice in this field.
    Does b) work? Yes, it works fantastic when using this approach on built in primitives like the cube and stuff in C4D. Does it work with objects that are imported and have a quite different axis orientation? No! I getr these weird bumps and hops at certain angles.
    But Cinema 4D itself has no problems with it, otherwise the Nulls would not sit on the objects like glued to them. Or?
    I would be happy to share any solution that works.



  • On 18/06/2013 at 23:47, xxxxxxxx wrote:

    Ok, finally I have found something that works, after weeks of fighting this.
    It is obvious, very obvious, that I am a beginner in this field, because I do not know what to ask, actually. Yes, I know what I want as the final result, but taking it from there and formulate good questions has been difficult.
    The main fault has been that I have been occupied with the relative rotation. Here is something that so far seems to work perfect:

            Matrix mObject_A_Null = object_A_Null->GetMg();
            Matrix mObject_B = object_B->GetMg();
            Matrix mResult = mObject_A_Null; // This added for clarity
    	mResult.off = mObject_B.off; // Maintain position 
          	mObject_B->SetMg(mResult );
    

    So as you see, instead of using the relative rotation, I use the global world data.
    It can be even simpler, I wrote it this way for clarity. What a relief! Everything works. And I do not see the strange 180º "hops" either, when I bake out the keyframes.
    If I should take it one step further, it would be to omit the Null. The Null sits there just because objectA and its parents have their axis pointing in all possible directions, and I insert the Null in the C4D upright xyz standard position. So for pure interest, I would like to find out how D4D does it and emulate the Null.


Log in to reply