Convert World Location to Rotated Object Location

Hi! Panda3D newbie over here. I’m working on a quaternion-based voxel dogfighting game and have run into a bit of a problem. Bullets have a world location X, Y, and Z. And I’d like to figure out what voxel those bullets hit on a ship that’s been rotated. I figure the best way to do that is to calculate the location of the bullet in the ship’s local space based on it’s world location and rotation. I thought about parenting the bullet to the ship, setting the ship’s rotation to 0, and then getting the bullet’s coordinates… but considering there’s probably going to be dozens if not hundreds of bullets flying around, a mathematical solution I believe would be faster.

I hope this makes sense! If someone out there has a better idea, please feel free to post it!

Hi and welcome to the community :slight_smile: !

In Panda3D this is very simple to do by calling bullet.get_pos(ship). The argument passed into get_pos is assumed to be a NodePath which you want the position to be relative to.

Calling bullet.reparent_to(ship) wouldn’t work, as this would leave the transformation (which is always applied relative to the parent) on the bullet unchanged, but it would alter its location and rotation in world space, because of the reparenting.
What would work is a call to bullet.wrt_reparent_to(ship), which would make the bullet retain its transformation in world space, so you could then retrieve its position relative to the ship through a call to bullet.get_pos(). But indeed, doing this would not be very efficient.

Thanks for the reply, Epihaius!

There are a few more options that might work with this. If wrt_reparent_to is exposed in python in Panda3D’s engine, then I might be able to analyze the math behind it and streamline it just for my purposes. The test could also only trigger if the bullet collides with the voxel mesh or is inside a bounding box(assuming collision meshes can be created from geoms). Or the test only occurs if the bullet is a distance away from the ship smaller than it’s largest dimension.

Just some ideas, but if anyone else has any more ideas please feel free to share! I’m willing to try just about anything.

I stand to be corrected, but could you not get this by finding the ship’s transform matrix, inverting that, and applying the inverted matrix to the bullet’s world-space position?

Something like this:

# Once per update:
matrix = ship.nodePath.getNetTransform().getMat()
matrix.invertInPlace()

# Then, for each applicable bullet:
bulletPos = bullet.getPos()
bulletPosRelativeToShip = matrix.xform(bulletPos)

Note that this is untested, and may well contain mistakes!

Excellent! I was looking for something like this! Thank you, Thaumaturge!

There is a similar code in Blender Python to do that exact same thing, but I couldn’t figure out how to translate Blender Python’s functions to Panda3D functions. I’ll create a test bed for this code and see how it goes!

It’s my pleasure; I’m glad if I’ve helped! :slight_smile:

Why so complicated? To convert a given point from absolute coordinates to a ship’s local coordinate system:

ship.get_relative_point(render, (x, y, z))

To return a bullet’s position relative to a ship object:

bullet.get_pos(ship)
1 Like

Will this also work if the ship is quaternion rotated, Rdb? :open_mouth:

Sure, it will work regardless of how the ship is rotated, whether via a matrix, hpr tuple or quaternion. Panda abstracts away the differences between the different types of transformation.

Good point! The methods that you give are likely a better way of doing it. :slight_smile:

Hmm… I suppose that, for a very large number of bullets, getting the matrix once and just applying it multiple times might, perhaps, be a little bit more efficient–but with that many bullets, running the code in Python might not be ideal.

In short, rdb’s approach is likely better than the one that I gave, I think!

1 Like

I’ll try all the ways! Though I’m sure there are some optimizations to be had. I realized earlier today that bullet positions also only need to be calculated if the bullet or it’s raycast intersects a chunk of a vessel. The reason why the game needs so many bullets though is because the gameplay is very fast. Alarmingly fast. some 80% of the bullets you fire will never hit a target, and it only takes a handful of good shots to disable your enemy.