How can I get all actors in a camera's view frustum?


How can I get all actors in a camera’s view frustum?

At the bottom of this page, there are Shape Traces. Maybe they help you (:
I don’t know if there is a way to simply get the view frustum and trace from there. Using shape traces with the “camera position” as starting point and the “forwardvector * distance” of the camera + “position of the camera” as endpoint should be enough i guess.

There seems to be no view frustum shape available? Feels like that must exist somewhere or how do they perform view frustum culling when rendering.

It would be very expensive to get all actors that are in the view frustum in the current frame (you would need to cull the frame a additional time). If you can provide some details what you are trying to accomplish, then I can maybe help you find a way that’s way cheaper than just fetching all actors in the frustum in a single call.

Okay, I though there were some collision cache. If not it may still be faster with my current implementation.

I’m working on an RTS game and have implemented a “box selection” feature. I.e. while holding down the mouse a box will be drawn, selecting all “units” under the box. At the moment I just iterate through all actors of a specific interface and check if they are inside or not.

Thought I should improve that solution by not checking against “units” off the screen, which impossibly could be selected.

I guess I probably will stick to my current implementation unless performance problems arises when the number of “units” increases.

Hm, i just thought about using a box that you scale and position with your mouse clicks. After you release the mouse button again, you activate the collision for that box and get the actors inside…

But maybe a simple box trace, like i posted you above, from start point (mouse click) to end point (mouse release) would be enough. That’s the easiest thing to do and won’t hurt your game performance.

Maybe you will need to use a “multi box trace” instead of single one.

If you are using blueprints, I would recommend using the Box Overlap Actors node (see documentation: Box Overlap Actors | Unreal Engine Documentation). If not, check the implementation of that node in C++ and see how it’s implemented and do the same thing (I’m at work right now so I can’t give you any more details without checking up the implementation. But it most certain uses the collision query functions in UWorld). This is basically the same thing as eXi says, a “multi box trace”.

This would use the collision octree to make sure that you query a minimal amount of actors within the engines collision system.

Since the camera is using some perspective the box shape would need to be skewed, i.e. like a view frustum shape. Guess I could use an AABB to perform some culling and then iterating through all actors in that shape with my current code. That would probably be good enough and I guess the view frustum culling would probably use an AABB as a first step anyway to reduce the cost.

I answered to eXi’s comment above instead of copying it here also.

Could you just copy the post or something and submit it as an answer for tracking purposes? So I can mark the question as resolved.

Thanks for all help! Think I have an idea of how to continue now.

I hope you meant this post. If not just tell me. I will mark this question as resolved then.

You could just make a box of your selection area and trace using that. That should get a even tighter fit.

I noticed right now that commenting to a answer, removed it’s status as answered. Sorry for that.

The box wouldn’t look like a frustrum, as it’s a box in the physics world and not in the camera perspective.

If you just make a box with the upper left corner where you started dragging, and the lower right corner where you stopped dragging, then you would get a box in the world.

If you multi box trace this with a filter on the actor class of your unit type, then you would just directly get all “Units” from this query without needing to do your current “selection logic”

But can you do that with the box shape? That box would look like a view frustum then because there is fov on the camera?

That’s exactly what i told him in the answer above. :smiley:

The problem is as you said “The box wouldn’t look like a frustum”. Maybe we are taking about different things here. I mean if you drag a box on top of the HUD, as in this picture link. With a box created from the start point to the end point in world coordinates, the box would potentially cover more “units” than the box displayed on the HUD. This is since my camera isn’t orthogonal. The greater the FOV is, the greater error. The 3D representation of the HUD box would indeed look like some frustum shape, unless we use an orthogonal perspective.

eXi: Yes, just wanted to clarify why it isn’t needed to use it just as a frustrum-culling, and use it to for actual impelemtation.

undercover: You are about right… BUT, if implemented correctly, you won’t have that problem.

Implement the algorithm by:

  1. Find your upper left of your selection in screenspace (pixels)
  2. Find lower right of your selection in screenspace (pixels)
  3. Use canvas to deproject your upper left hud location, then you get a world location on your near plane, and the direction to the backplane that the pixel maps to. This will adjusted for your aspect ratio and FoV
  4. Trace from this location in the direction until you hit world geometry. This will be your upper left world location where you start using your box
  5. Do step 3 and 4 with your lower right location of your box.
  6. Now you have the upper left, and lower right location in world locations.
  7. Now you can get all units between these points by doing a boxtrace without beeing afraid that it will be distorted by the perspective.

Ofcourse, this is just a optimized version for a smaller area than how you have done it. You can still do it the way you have done.

I hope this explanation was somewhat manageable to follow now that I had more time to write, rather than write while compiling at office :wink: