Stop rotation on collision [CLOSED]



  • On 07/01/2015 at 11:08, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R16 
    Platform:      Mac OSX  ; 
    Language(s) :      XPRESSO  ;

    ---------
    Hi,

    Since I'm very sure there isn't something wrong with my code, I put the post in here.

    So, I have a file with 2 objects, one who is going to rotate, and a static object.
    I have some simple code for if the two objects collide, object A's rotation should go to the previous (captured) rotation. Because of this, the two objects should never be able to collide, when object A is rotating.

    Because I can't upload my file, I'll tell how it is constructed:

    Two editable objects (A and B). Object A should be able to ratote, and because of that get collision with object B.

    In object A there is an Xpresso tag containing the following:
    A node for object A, with an output port "Object" connected to the first input port of a collision node.
    A node for object B, with an output port "Object" connected to the second input port of the collision node.
    The output port of the collision node is connected to a python node with the custom input port "isColliding", an integer.
    The second input port of the python node is a vector, "newRotation" which gets its value from a node for object A (the same node or a new one, with an output port "Rotation").
    The first output port of the python node also is a vector, "lastRotationOutput", which is not connected with anything.
    The second and last output port of the python node again is a vector, "newRotationOutput", which is connected with again a node for object A (note: this cannot be the same node you used at the first or second time), the input port set to "Rotation".

    Finally, the code inside my python node:

      
    import c4d  
    #Welcome to the world of Python  
      
      
    def main() :  
        global isColliding  
      global newRotation  
      global lastRotationOutput  
      global newRotationOutput  
      
      if isColliding == False:  
          lastRotationOutput = newRotation  
          newRotationOutput = newRotation  
      else:  
          newRotationOutput = lastRotationOutput  
      
    #end Python code  
    

    The code does the following:
    For each new position, the python node checks whether there is collision or not.
    If there is no collision, the rotation value gets inside both the lastRotationOutput and newRotationOutput. The object behaves as normal.
    If there IS collision, the newRotationOutput (the rotation value that goes back to object A) will be replaced by the lastRotationOutput (the last rotation in which there was no collision), and object A will go back to it's previous state before collision.

    My problem now, is that, although they never collide, they also never come near to each other, due to some bug in Cinema 4D, I guess. Even worse, sometimes object A stops rotating a few degrees before colliding, sometimes more, sometimes less. (For example, sometimes it's 24.5°, sometimes it's 12.34°, sometimes 28.67°)

    What could be the problem here?

    Thanks in advance for your help and time!
    Greetings,

    Casimir

    Andreas: added code tag



  • On 08/01/2015 at 08:16, xxxxxxxx wrote:

    Hello Casimir,

    to be honest, I had never thought of using Python and Xpresso in this way, but instead had probably used the dynamics system. This is not meant derogatory at all, instead I'm thankful for every new idea.

    Anyway, let's get to your problem:

    One problem (I'm quite sure you know about this already) could be a wrong configuration of the collision node's mode. By default this is set to bounding box. And this will, depending on your object's shape, probably not work well.

    Before coming to the next point, I'm wondering how you test, if this is working?

    Probably the main problem is the last rotation value (which is the rotation of the object one frame before the collision happens). Depending on the speed of the rotation, this value may be light years away from the point of collision. Your script (and the entire Xpresso setup) only get's executed once per frame. So you have all the problems, one has to expect when working with discrete values (time is not continuous in this case, but jumps from frame to frame). The correct achieve this, would be to calculate the "collision rotation" and use that in instead of lastRotation.
    Check it yourself: Just rotate Object A slowly enough and it will seem to work. The faster Object A rotates the larger the errors will get.

    Now, that we talked about that, I'd like to add, that an object node in Xpresso has a "Previous Rotation" output. Personally I regard "open output to store data" a bit hacky. I know, this works and sometimes such a workaround is needed (by the way a similar approach can be done with user data to store arbitrary values in Xpresso (not only the Python node) for later use), but in this case you can get away easier.

    And lastly one small note on the Python node:
    Inputs don't need to be declared global. This is only necessary for outputs.

    The last one after the last one: I don't think, we are talking about a bug in C4D here. And having this said, I'd like to move and rename this thread, if that's ok for you (move to PYTHON Development, rename to "Stop rotation on collision").



  • On 08/01/2015 at 10:23, xxxxxxxx wrote:

    Hi Andreas!

    Thanks for your answer!
    I shall definately look into it!

    And surely you can move and rename the thread, after reading your answer, this indeed seems the wrong place for my thread.

    Greetings,
    Casimir



  • On 12/01/2015 at 07:48, xxxxxxxx wrote:

    Hi,

    Well, the reason why I don't use the dynamics system is because the object I want to rotate simply isn't dynamic. I want to rotate it myself, and never use gravity on that object.

    All the rest is clear to me, except how to calculate the "collision rotation".
    I've searched on google for a while, but everything I found with collisions has dynamics.
    I'm quite sure I know what I need to calculate, just not how to do it.
    Are there helper-functions inside C4D that I can use?
    Or should I calculate it from nil?

    Thanks for looking into this!!

    Cheers,
    Casimir



  • On 13/01/2015 at 09:12, xxxxxxxx wrote:

    At least I'm not aware of any convenience function to calculate what you need.
    In C++ (not in Python) there's the GeColliderEngine, but even that does only help you to calculate, if there's a collision. And what you want, is quite the opposite.
    I'll leave this question open to the community for some time. I'm sure there are solutions in literature and surely also on the net for this problem.



  • On 13/01/2015 at 09:29, xxxxxxxx wrote:

    this can be easily solved, but I need to know how do you set the variable "global newRotation"



  • On 13/01/2015 at 10:06, xxxxxxxx wrote:

    Well,

    Andreas already pointed me on the fact that I don't need to declare it globally.
    I get the value from an object-node (the rotating object) which gives me the current rotation (normally even when it is or should be colliding).

    I hope this is what you needed?

    Greetings,
    Casimir



  • On 13/01/2015 at 10:14, xxxxxxxx wrote:

    what I wanted to know is:how does it rotate?
    depending on time? or mouse rotation action? or dynamics? specify whatever thing is rotating it.



  • On 13/01/2015 at 10:28, xxxxxxxx wrote:

    Oh yeah, sorry for that!
    I rotate it manually with my mouse, for animation.
    In this example it are just two static objects, but in my bigger file even those two objects move depending on other controls.

    Cheers,
    Casimir



  • On 13/01/2015 at 10:41, xxxxxxxx wrote:

    so when you rotate with the mouse, it stops at a certain rotation "before the collision" and get stuck, correct?



  • On 13/01/2015 at 11:34, xxxxxxxx wrote:

    Yes indeed, and that's kind of what I want, except that now it stops at random rotations.
    E.g. sometimes it stops at Pitching 8.45° and sometimes at 9.37°, while it should always be 12°.



  • On 13/01/2015 at 12:04, xxxxxxxx wrote:

    this code is not tested, test it and tell me if it works.

      
        
        
        import c4d  
        #Welcome to the world of Python  
          
        def main() :  
            global isColliding  
          global newRotation  
          global lastRotationOutput  
          global newRotationOutput  
          
          if isColliding == False:  
              lastRotationOutput = newRotation  
              newRotationOutput = newRotation  
          else:  
              newRotationOutput = lastRotationOutput + (2 * (lastRotationOutput - newRotation))
        
    


  • On 13/01/2015 at 12:07, xxxxxxxx wrote:

    This may make the error smaller. But the principal error stays the same.
    I'm sorry I need to stamp on the hopes.
    Mohamed, did you read my explanation?



  • On 13/01/2015 at 12:31, xxxxxxxx wrote:

    yea I totally understand where the problem lies, and I tested my code in a simple scene and it failed too "even worse".

    I guess a python tag may do it "because you will control the refresh" , but in xpresso it is horrible to do such things



  • On 14/01/2015 at 06:01, xxxxxxxx wrote:

    Yeah I'm looking into that.
    But, my problem is, how should I calculate the collision? On that level I have no helper functions to use, so I guess I have to code it whole from nil.


Log in to reply