Aim Icon and Depth

I’m practicing a shooter mode look for the first time and wonder, what is the best way to get an Aim Point Icon on the screen, and have that Icon sit in front the the main character, but not fall behind enemies or walls when they come close?

Should the Icon be drawn 2D or can it be a 3D object? I have no knowledge of how to control depth with P3D.

I’d go with 2D. Create an OnscreenImage that loads your crosshair texture, move it to the center of the screen, and you’re good to go. All in all, around 3-4 lines of Python.

The thing is, my shooter mode is not first person. It’s a close up, over the shoulder look, as the Actor aims. I’m sure you’ve seen that look before in games and know what I’m talking about.

Would a 2D sprite sit over the character? That’s the issue. How can I get the cross-hair in front of the main Actor (always) and not fall behind enemies at the same time?

You can use either approach.

If you go with a 2-D approach, you need to find a way to map the 3-D location of your target to the corresponding 2-D position on the screen. One way to do this is with the function base.camLens.project(), which uses the lens transform to convert from 3-D to 2-D, but you also have to pre-transform the 3-D position into the coordinate space of the lens. There are examples of this being done elsewhere in the forums.

If you go with a 3-D approach, you need to tell the crosshairs to render on top of everything else. You can easily do this by disabling the depth test, and setting a bit so it renders last, like this:

crosshairs.setDepthTest(False)
crosshairs.setBin('fixed', 0)

You will probably also want to set a billboard effect so that the crosshairs rotates to face the camera, and turn on two-sided rendering so you don’t have to think about which way is forward:

crosshairs.setBillboardPointEye()
crosshairs.setTwoSided(True)

David

Can I just retrieve the depth of my Main Actor and set the Cross-Hair to the Actor’s depth, but with an offsetting value so the Cross-Hair falls in front of the Actor? Any enemies that get close to the Actor should not over lap the Cross-Hair (since the depths of the cross-hair and Actor will be so close), if this could be achieved with P3D APIs.

crosshairs.setDepthTest(False)
crosshairs.setBin('fixed', 0)

I’m guessing setDepthTest(False) is like telling P3D to stop setting Depths by yourself; and crosshairs.setBin(‘fixed’, 0) is assigning your own depth. Why the argument value of “fixed?”

Also, is there a call like getDepthTest()?

That’s why I love APIs that use all logical names for functions/methods…like setDepth2D(), setDepth3D(), getDepth(), etc…

I’m a long way from getting to the cross-hair coding still. P3D don’t have IK, so getting my character to do the things characters normal do with IK (in a shooter) is a bit more tricky. I think I have the logic though…so far so good.

There isn’t any getDepthTest() method, AFAIK, but I really don’t see the point of having one in the first place though.

Anyway, the method you suggested is far less efficient (not to mention less compact code-wise) than David’s method, mainly because with your method, it will either be hard or impossible to see the crosshair, or a close enemy could eclipse the crosshair. Neither statement is true for David’s method. Plus, his method is short - 4-5 lines of Python at most, and very simple, so I think his method is certainly worth a look.

The BillboardEffect has an advanced setting which will also slide the object it is billboarding directly towards the camera for a specified distance, so you can use this if you want. Since it only comes forward a certain distance, it means that things that are much closer to the camera than that will still obscure the crosshairs, and maybe that’s desirable (so that it doesn’t show through walls and stuff for avatars that are actually really far away).

This is a more advanced setting, though, and requires using the lower-level BillboardEffect directly, instead of using the higher-level NodePath.setBillboardPointEye() method.

Depending on the precise effect you’re going for, it may be better just to turn off the depth test.

For the record, there does exist a NodePath.getDepthTest() to balance NodePath.setDepthTest(), but as DOTR points out, it’s not necessarily a terribly useful method. It can query whether you have explicitly set the depth test on this particular node, but that doesn’t mean much–in the scene graph environment, usually the depth test setting is inherited from a parent node (along with almost all of the rest of the render state).

setDepthTest(false) disables the default behavior of consulting of the depth buffer for each pixel. This allows the object to render on top of objects that would otherwise be in front of it. For a complete understand of the OpenGL depth buffer and how it works, you should probably consult a tutorial on 3-D graphics techniques.

The argument value of ‘fixed’ names a particular bin, one of the default bins that happens to have a sort value higher than the standard bins. You can also create custom bins if you like. These are advanced rendering techniques, and they’re all documented in the manual and discussed frequently in the forums.

David