Jump to content

Component: efficient world intersection with Landscape?


photo

Recommended Posts

Hi,

We have a C++ Component in a IG node that does a World::getIntersection every frame (required). Currently, this is done is the update() of the component.

With TerrainGlobal (2.13.1) I didn't note any critical performance hit, but with Landscape (2.14.1.1) very frequently this query leads to a visible stutter. In microprofile, I can see that the WorldIntersection sometimes have to wait for the async thread to complete, and the latter may take a while to complete.

image.png.6885f135c34fef745f574e1306477bec.png

Is it normal? How can I fix this behavior? Can the worldIntersection be called asynchronously from within a component?

Thanks!

Edited by Amerio.Stephane
Link to comment

Hi Stephane,

This happens mostly when LandscapeTerrain is doing background streamin at the same time the intersection request occurs. We do have similar issue in our internal project, however, no proper solution has been found yet. To confirm if this the same issue or not, could you please do the intersection tests when main camera is not moving (so no LT streaming is being done in background)?

As a temporary solution (and if you don't need a very precise readings) you can export LT as a grid of low-poly meshes and use them for intersections. I think devs will have more time to debug this behavior in Q1 2022.

Thanks!

How to submit a good bug report
---
FTP server for test scenes and user uploads:

Link to comment

This is bad news. Indeed, if the camera is not moving, then we don't have this stutter, but our HC is always moving, turning around, firing... (hence the intersection queries).

I fear this might be more critical though: do CIGI HAT/LOS queries suffer from the same issue? (we do a lot of those...)

Link to comment

One thing that bothers us is that you have stable 8-9ms destroy image running in async threads. That operation usually should take some kind of .01ms, but in your case for some reason it's not.

If it's possible to get your current code and content for additional testing - it would be just great. We can find out what happens and fix this. In our tests we never get such high numbers on image destroy tasks, so we can't really find out what's going on. 

Alternative approach right now is to use async intersection requests for terrain (there will be 100% no spikes or whatsoever), but you will have a delay in getting the results back. In best case scenario you can expect 0-1 frame delay, in worst (when you casting almost parallel to terrain surfaces rays) it may take much more frames (2+).

Even In the provided scenario (with current strange destroy image behavior) you can easily get only +2-3ms on CPU executime time if you will do an async intersection tests at the beginning of the frame. Something like that:

// super pseudo code
// begin frame
intersectionAsync()               
intersectionAsync()
intersectionAsync()

// your code goes here
  
// end frame
wait() and get the intersection resuls

Since your GPU time is already 6ms, and intersection takes up to 9 ms, with async approach your whole CPU execution time would roughly equals the intersection request time. Also, as you can see in my pseudo-code snippet all the intersection requests are executed at once and not split across the whole body of the function. That's specifically made on purpose, since in that case LT object can additionally group the requests internally and do less streaming from disc, therefore you can get optimized latency and better execution time.

That async stuff requires a slightly different approach for writing a code, so it may be hard to switch to this paradigm, but only using async requests can guarantee that no spikes will happen in main thread. There will be more async operations in the future versions of the engine (and of course, more async intersections), so current practice with LT will be help a lot in the future :)

We will try to prepare some code samples to show how to do a proper async requests for terrain and how to combine them with regular intersections for other world objects (I think it may take couple of days or something closer to a week).

Also for even faster intersections we can keep the whole terrain heights data in RAM, but this feature is not yet being developed. Right now you can only tune CPU cache size and set it big enough to keep all the lmaps in it). Compressed LT data from disk will not be kept compressed in RAM, so you need to keep that in mind. But even so, if you will have very bad ray that goes from one corner to another almost in parallel with terrain surface (with 0.1cm/pixel density) you would need to process a lot of data and this process can't run immediately.

Thanks!

  • Thanks 1

How to submit a good bug report
---
FTP server for test scenes and user uploads:

Link to comment

Having a small delay (1-2 frames) between a request and a response is acceptable. I can wait a few days for a code sample, than you!

I'll also try to tune the LT an see its effect on microprofile. But at the moment, even with no manual intersection request, I still have a lot of stutter when flying the IG, so I'm still wondering if CIGI HAT/LOS have a negative impact (which is absolutely critical!)

 

Link to comment

Yes, we will also do an IG intersections revision and if it's possible will do a migration to async model as well (but that could take a bit more time and more likely will slit to Q1 2022).

If you will be able to get rid of strange slow destroy image it would be nice to understand what was causing it. So we are still open to test it on your project on our side :)

Thanks!

How to submit a good bug report
---
FTP server for test scenes and user uploads:

Link to comment

You can try using the Intersections class from the attached files. It is a wrapper over World::getIntersection() and LandscapeFetch::intersectionAsync() with asynchronous support. The simplest way to use it is shown below:

Intersections::getAsync(p0, p1, 1, [](IntersectionRequest *r)
{
	if (r->isIntersection())
	{
		Vec3 point = r->getPoint();
		vec3 normal = r->getNormal();
	}
});

After this call, an asynchronous intersection search will be triggered, and upon completion, a callback will be called on the main thread. All the necessary results can be obtained in it.

Intersections.cpp Intersections.h

  • Like 2
Link to comment
×
×
  • Create New...