Again Rotation question

Hi folks,

I’ve created a square dynamically by using GeomNodes and the corresponding functions. Works fine…

I’m trying to rotate the square around its own axis (take x, y or z - axis - doesn’t matter)… But the rotation setHpr sets the rotation point to the first corner of the square, not to the axis of the object itself.

I digged into various posts of rotation, and I have the feeling that quaterions maybe the way to go but before finding it out with hours of try and error and just ask the simple question: is there a easy way to rotate a object around its own x,y & z axis? (I tried node.setHpr(node,x,y,z)) but that didn’t work…

Regards,
Andrew

…what about node.setHpr(h,p,r) ? (without the “node” since you already call it on such)
well if your problem is that the rotation center is not the center of the object you can add a dummy node and reparent your geometry to it, move the geometry until it fits and rotate the dummy… or try to move the geometry itself (thought i dont know it this is easy)

I think if you create a object using the coordinates ((0,0,0), (0,0,1), (0,1,1)…) you will have the rotationpoint in the edge of the cube. Try creating your cube with ((-1,-1,-1), (-1,-1,1), (-1,1,1)…) it will probably rotated around the center of the cube. However i have not tried it, it is just a guess.

Hi,

thanks for the answers:

@Thomas: good idea, could be feasible for my dynamical created objects since I “own” the geometry. But it original issue “how to do this” is not solved by this approach. The setHpr(x,y,z) - method also doesn’t help - same effect. I saw the “node.SetHpr(node,…)” - approach in some forum topics as solution for a specific rotation question so I thoughed that would help.

@Hypnos: same answer as for Thomas: it solves my specific problem, but leaves open the general solution - how to rotate a object around it axises, especially if you don’t have my options with manipulating the geometry?

Thanks,
Andrew

Andrew, in general the axes of an object go through its origin not necessarily the center, so if you want to rotate through some other axis you generally need to do a translation (i.e. change the position of the object) in a way that compensates for the fact that the object’s center is offset from it’s origin. The steps are:

  1. find the vector v1 from the object’s origin to it’s center in world coordinates
  2. rotate the object
  3. find the new vector v2 from the object’s origin to it’s center in world coordinates
  4. move the object by the vector (v1 - v2)

This process must be performed for every rotation and requires know the coordinates of the model center (or at least a point along the intended axis of rotation).

But really, it you have control over the geometry then it’s much easier to find desired center or rotation and move the model mesh so that this point is at the origin.

Also, just FYI quaternions won’t help you here, they are just another form of representing rotations that is compact and makes it easy to combine rotations, but don’t have anything unique to offer to a single rotation around a fixed axis.

I’ve been asking the same question, here are some ugly workarounds:
https://discourse.panda3d.org/viewtopic.php?t=2256

Setting the center of an object is VERY simple in most 3D environments. I’ve been experimenting with transformation states, but I’ve only been able to make it work with HPR, not position.

How is it that nobody else has ever wanted to change the center of an object without having to redefine it’s geometry? It has to be possible since models I export from Blender do have a center I manually set (in Blender).

Hello, Andrew!

It appears I was previously full of s**t. :slight_smile:

I have been thinking low-level all this time, whereas Panda3D uses a more abstract model. The tree model is the key. Here is how you center a GeomNode using NodePaths:

# Card makers are used to create flat surfaces
cm = CardMaker("cm")
# Create a parent node path for positioning within render
parentNode = NodePath("parent")
parentNode.reparentTo(render)
# Generate the surface and attach it as a new node path
childNode = parentNode.attachNewNode(cm.generate())
# Get the center of the bounds for the surfnode
center = childNode.getBounds().getCenter()
# Make a local transformation on the child so it's in the center
childNode.setPos(-center.getX(), -center.getY(), -center.getZ())
# Now rotate the parentNode while the child keeps it's transformation
LerpHprInterval(parentNode, 4, Point3(0, 0, 360)).loop()

See how each transform is done from the top node out to it’s branches. Each branch, naturally, having it’s own set of transformations.

I hope the comments explain, to make a long story short, the rotation transform of parentNode is always done with it’s local 0, 0, 0 as center, thus all children will rotate around that point. Moving the children locally doesn’t really change the center, only where the children are rendered in reference to the parent.

I tried to mess with the transformations manually a la OpenGL, but as ThomasEgi so elegantly put it: Panda3D is not OpenGL.

Once you get over the idea of doing transformations in a tree model it even feels sort of “sweet” or at least a bit enlightening.

Hope this helps!

Yes that’s the way.
For simple models on complicated scene, you can simplify it like this (still using cards) :

def centerPivot(NP):
    pivot=NP.getBounds().getCenter()
    parent=NP.getParent()
    # create the new parent node under the original parent
    newNP=parent.attachNewNode('theName')
    # bring the new parent to the center
    newNP.setPos(pivot)
    # and relocate the node without changing any of it's transformation
    NP.wrtReparentTo(newNP)
    return newNP

cm = CardMaker("cm")

# card1
card1 = render.attachNewNode(cm.generate())
# replace the nodepath with the new parent, or
# you can declare the new parent here and keep the old node reference
card1 = centerPivot(card1)
# now you can move it around
card1.setPos(0,0,0)
LerpHprInterval(card1, 4, Point3(0, 0, -360)).loop()

# card2
card2 = render.attachNewNode(cm.generate())
card2 = centerPivot(card2)
card2.setPos(-1,0,1)
LerpHprInterval(card2, 4, Point3(0, 0, 360)).loop()

# card3
card3 = render.attachNewNode(cm.generate())
card3 = centerPivot(card3)
card3.setPos(1,0,1)
LerpHprInterval(card3, 4, Point3(0, 0, 360)).loop()

# card4
card4 = render.attachNewNode(cm.generate())
card4 = centerPivot(card4)
card4.setPos(-1,0,-1)
LerpHprInterval(card4, 4, Point3(0, 0, 360)).loop()

# card5
card5 = render.attachNewNode(cm.generate())
card5 = centerPivot(card5)
card5.setPos(1,0,-1)
LerpHprInterval(card5, 4, Point3(0, 0, 360)).loop()

base.cam.setY(-8)

If you don’t keep the nodepath reference, just make sure to set the center pivot directly after model loading or generation, before changing any render states on that node.

1 Like