Raycast As A Shape

Hey It’s me again. So I’m having another small problem and I’m not even sure what to call it. I would like to cast a ray, with the ray having the shape of an object. Don’t worry, I brought a couple of crude diagrams to show what I mean!
The Blue object represents the shape I would like to cast, which is a model in my game.
The Red object represents the ray being cast
The Green object represents obstacles that would be returned when the shaped-ray hits them. I wanted this in order to raycast between objects and register hits with what’s behind them.
Here’s another example:
If you need a more practical example, consider raycasted throwing stones against an armored foe with open weak points. I’d like larger stones to be raycasted in the shape of the stone to bounce off the armor, while stones smaller than the openings in the armor (the weak points) are able to pass through.

As always, thanks in advance for your feedback!
(PS if there is some other way to achieve this with some measure of accuracy, maybe with collisions or something, feel free to share alternate solutions!)

Hmm… Depending on the degree of accuracy that you want, you could perhaps emulate this via multiple ordinary raycasts. More raycasts, better fitted to the model, would produce more-accurate results–but you’d have to test the method to see how well it performed. Fewer raycasts would be less accurate, but should perform well on modern hardware, I imagine.

Otherwise, this looks a lot like a “sweep test”–roughly speaking, the desired object is “extruded” in the desired direction, and the test is made against this extrusion.

Panda’s internal collision system has an approach that achieves more or less the effect of this, via moving the object to be tested multiple times per update and testing with each move, if I’m not much mistaken. You can read more about this in this manual page, I believe.

Bullet has a method to do this in the “BulletWorld” class–see the API here. Note that it apparently requires a convex shape, which your example above isn’t, if I’m not much mistaken.

All that said, in your practical example I think that I’d likely just use ordinary collision, with the stone likely represented by a simple collision-shape–a sphere if it’s slow, and a raycast or tube/cylinder if it’s fast. (Or a sweep-test if the tube solution proves too slow in the latter case.) I might then use standard non-physics logic to test the size of the stone against the size of the weak point. If the “stone size” is larger than the “weak point size”, I might have the stone bounce off harmlessly; if not, I might register a hit, instead.

Thank you for the reply! These are definitely good ideas that I’m going to be looking into. I didn’t realize quite how fully-featured the Panda3D Collision System was. Out of curiosity, is there a collision shape that uses the geometry of a model instead of a preset shape? A lot of my models are low-poly, but are are quite unusually shaped(Like the T up there). Unfortunately, the weak point sizes are dynamic, and their size depends on things like armor design and eventually player-modded parts.

There’s the “CollisionPolygon” shape, which can be used to build up a shape by hand, or constructed in the background for you from an imported 3D model as with normal geometry, I believe.

However, note that I don’t think that you can use a “CollisionPoly” object as a “from” collision-object, only an “into” collision object.

See here for more information.

If a close match to the object’s shape is important, then one possible workaround is to approximate your object using multiple simpler shapes. For example, your “T”-shaped object above might be approximated with two cylinders, or two boxes.

If simpler approximations won’t work, then you might want to look into Bullet–I’m not sure of whether it handles arbitrary shapes, but it’s possible that it does, and it seems worth checking.

That should work perfectly well with the size-comparison that I mentioned above, I would imagine! After all, the size of the weak-point, even if generated dynamically, is likely known or calculable, and can thus be used in comparisons within your logic.

Eureka! Bullet collisions does, in fact, have triangle-mesh collision shapes! That’s exactly what I’m looking for… But now I’m having another issue. (I’m unsure if I should bring it up here or start a new thread). How does one parent a collision node to an actor joint? As far as I can tell, I think you’re supposed to:
Load object
Get object geoms
Add geoms to shape
Add shape to CollisionNode
Add CollisionNode to BulletWorld node.
But I would like to, say, put a weapon in my Actor’s hand-joint and give that collisions. Does that mean I need to add the whole actor to the world node? On another note, whenever I try to parent the CollisionNode to the actor join it returns an error. Any thoughts on this?
PS, sorry if this seems rushed. My internet might go out at any moment.

Just a quick note: if I recall correctly–and I may be misremembering–if you’re using Bullet, you shouldn’t be using CollisionNodes, but rather BulletBodyNodes. CollisionNodes are used by Panda’s internal collision system, not Bullet.

That said, I think a basic workflow might be something like this:

  • Model your object with collision geometry, tagged as such
  • Import your model into Panda
  • Use the Bullet Helper to generate Bullet collision-objects from the collision geometry
  • Attach the nodes to the world
  • Parent the NodePaths associated with those BulletBodyNodes to the joints of your Actor.

(I may be missing a few steps there; I’m typing this up quickly, I’m afraid! My apologies if I am missing anything.)

The Actor wouldn’t be added to the world, no. You should be able to move a Bullet collision-object just as any normal NodePath, and thus attaching it to the relevant joint of the Actor in question should suffice, I think.

What error does it return?

Sorry for the lengthy delays. Internet has not been functioning lately.

Just a quick note: if I recall correctly–and I may be misremembering–if you’re using Bullet, you shouldn’t be using CollisionNodes, but rather BulletBodyNodes. CollisionNodes are used by Panda’s internal collision system, not Bullet.

Yeah sorry. I was in a bit of a rush last time and used the wrong terminology. I attempted to parent the BulletBodyNodes to joints, but after being parented the nodes do not respect the parent. I’ve since started a test file built from the 08_Contacts file. I am attempting to parent one collision-object to another, but have run into the same problem. The child object refuses to move with the parent, and it also has it’s own gravity.

What error does it return?

That BulletRigidBodyNode has no attribute reparentTo, though I think that might have been an error on my part.

Thanks again for the help!

Ah, yes–you should be reparenting the NodePath, not the Node. That is, “BulletRigidBodyNode”, like “CollisionNode”, is a sub-class of the base node-class in Panda3D, “PandaNode”.

However, operations like reparenting, while possible via nodes, I think, are generally done via NodePaths.

How are you setting up your Bullet-nodes?

Ah, fair enough!

Odd–although given the error that you reported, I’m surprised that the process is getting far enough to see that the joint isn’t being respected. Have you worked around the error, then?

Hmm… I’m not familiar enough with how that’s done in Bullet, offhand. I think that a Bullet constraint might do the job–see the manual here.

Also note that I think that you can disable Bullet’s handling of gravity. How that’s done should be in the manual or API somewhere, I think.

PS: I’m sorry to read about the internet troubles! I hope that it starts behaving itself soon, if it hasn’t already!

I don’t know if this is what you mean, but this is the current code for the test zone:

shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))

		np = self.worldNP.attachNewNode(BulletRigidBodyNode('Box'))
		#np.node().addShape(shape, TransformState.makePos(Point3(0, 1, 0)))
		np.setPos(1, 0, 1)


		visualNP = loader.loadModel('models/box.egg')

		self.box = np.node()
		self.boxnp = np

The second test zone box is exactly the same, except with _2 at the end of every variable. (such as self.box_2). I’ve tried:
and self.box_2.reparentTo(self.boxnp)
None of these variations work.

It is weird! It’s acting like the parent just doesn’t even exist. this is currently my primary problem.

I’ve also tried parenting the box_2’s collision-object to box_2’s model, but gravity and physics are still effecting it. If there was some way to disable bullet physics while still having access to bullet collisions, I think that would be best. Technically I don’t really even need to utilize the physics for this sort of game.

P.S.S: thank you! I’ve ordered a new internet card for my computer so that should fix it. (the one I currently have is almost 8 years old.)

Hmm… So you’re only using Bullet to detect complex shapes colliding with other objects? But without requiring a full physics response?

In that case… how likely is it that players are going to notice the inaccuracy of a simpler collision shape, as opposed to using complex-shape collision?

If you can get away with using simpler collision, then I suspect that you’ll save yourself a lot of trouble.

However, if it really is important, then let us continue!

You can disable physics by making a collider into a “kinematic” object, if I recall correctly. I think that such objects can be tested against other objects, but while they exert physical forces, they don’t experience such forces themselves. To make a BulletBodyNode kinematic, simply call “setKinematic” on it. (You may also want to set the object’s mass to 0; I’m not sure.)

Ah. Okay, in your example there, “self.box” is a “BulletRigidBodyNode”, while “self.boxnp” is a NodePath that points to that node. You should be able to reparent “self.boxnp” to a joint, but “self.box”–while not impossible, I think–might be awkward to work with (as PandaNodes don’t have a “reparentTo” method, I believe).

I suggest trying your collider as a kinematic object, parented beneath your intended joint; see whether that works.