-
Notifications
You must be signed in to change notification settings - Fork 326
[enhancement#1658] mesh, material and tile loading callbacks #1669
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for opening this for review @GhisBntly ! Just looking at this from a high level, I had a few questions about some of the choices made. But I think this approach is promising 🤞
class UStaticMeshComponent; | ||
|
||
UINTERFACE() | ||
class UCesiumLoadedTileBase : public UInterface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer this interface over exposing CesiumGltfPrimitiveComponent
, so thanks for working on it! I might add more feedback later, but I think this approach works for now.
UPROPERTY(EditAnywhere, Category = "Rendering") | ||
FCustomDepthParameters CustomDepthParameters{}; | ||
|
||
Cesium3DTilesSelection::Tile* pTile = nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know why you did this, but I'm hesitant to give this component the power to modify the Native tile. I'm not sure if this could affect the tileset loading algorithm in some unexpected way... maybe @kring would know off the top of his head?
Can you explain when you would use SetRenderReady
for your use case? I'm hoping there's a better or equal way to achieve this without reaching into the Native tile state 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'm generally ok with the Tile
being accessible, so long as it's only accessible from the main thread. The public API of Tile
could definitely be better, to make it clear what sort of modifications are ok, but as an advanced API here I think it's fine for now.
I would like to understand better why the "render ready" concept is used, and why it's needed, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah adding this member made me uncomfortable too ;-) But I didn't see any other way, and at least UCesiumGltfComponent
is Private. The Public interface I added only gives access to the Tile ID and to the setter I needed (SetRenderReady
).
Now for the use case: it will be complex to explain, as we reached this solution after much trial and error...
Our app logic means we need to create textures for some of the mesh components. Initially, we were doing everything in OnMeshConstructed:
- discover per-vertex metadata to identify mesh subsets and map them to app domain data
- in tiles where it was needed, create property textures (with a size matching the max FeatureID found on vertices), initialized (
UTexture2D::UpdateTextureRegions
) with app-specific data used by our custom material's shaders - assign (
SetTextureParameterValueByInfo
) these textures to all materials of the tile's meshes
But we realized that, randomly, some textures were not coming through properly, ie. the render was showing as if the material was accessing garbage data, even though we had triple-checked that all data was correct and the right methods called on our side. We finally found that we had to wait for the render thread to process the render command enqueued by the UpdateTextureRegions
call to guarantee that the texture could be assigned to the materials :-/
So we added a synchronization mechanism through UpdateTextureRegions
's DataCleanupFunc
parameter: to avoid blocking the game thread while waiting for the RHI thread, we had to defer the finalization of our materials setup to the next tick which in turn meant we had to tell the tiles selection algorithm that the tile was not quite ready for render yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation @GhisBntly! I'm still a little confused as to why it's necessary to delay, though.
UpdateTextureRegions
enqueues a command to the renderer thread, that makes sense. But as long as any draw commands for that tile are executed by the render thread after that command enqueued by UpdateTextureRegions
, I don't think any particular synchronization or delay should be necessary. Certainly this is true when we create textures, at least.
Is it possible something else was happening here? Like the UpdateTextureRegions
wasn't invoked until after the tile was drawn with the non-updated texture somehow?
Or is there more going on in UpdateTextureRegions
than I expect?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree our problem and solution doesn't feel "right" ... but we have spent a fair amount of time debugging and didn't find anything so far that could be a bug in our code. Our assumption is that assigning the texture with SetTextureParameterValueByInfo
has immediate side effects on render commands already enqueued :-/
It was our early days with Unreal last year so maybe we missed something. If you think this is too intrusive a change to merge without a better understanding of what's happening, I can remove that part from the PR, and we'll open a new one with it later if need be, after we have had another look at it with the experience gained.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for opening this PR @GhisBntly! I have a bunch of small comments, but overall it looks great.
UPROPERTY(EditAnywhere, Category = "Rendering") | ||
FCustomDepthParameters CustomDepthParameters{}; | ||
|
||
Cesium3DTilesSelection::Tile* pTile = nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'm generally ok with the Tile
being accessible, so long as it's only accessible from the main thread. The public API of Tile
could definitely be better, to make it clear what sort of modifications are ok, but as an advanced API here I think it's fine for now.
I would like to understand better why the "render ready" concept is used, and why it's needed, though.
Left to do: * get rid of bNeedsCPUAccess * replace TileID by ... ? * decide about CustomizeGltfMaterial * adapt UCesium3DTilesetLifecycleEventReceiver's signatures to be implementable from a BP(??)
… sense of glTF vertices
Note: I had to add |
I mark this PR as ready for review, although I'm still unsure about |
About The method that does all that in our code already supports a time budget: even though I do not use it for this purpose at the moment, I may want to do so in the future to smooth out tile transitions, which may be a valid reason to include this feature? |
* give access to Tileset actor
Sadly, I was unable to reproduce the specific issue that led us to defer material texture assignments, but it doesn't mean the problem no longer happens, as it was witnessed only in rare circumstances, and the project data I had used to investigate it no longer exists :-( |
Sorry for the delay on these PRs @GhisBntly :( I'll take a look at this sometime this week! |
cesium-native already has (and cesium-unreal already uses) a main thread loading time limit: Also, if you can do any of the work in a worker thread, then that process is allowed to take place over multiple frames, with a Does the "render ready" mechanism satisfy a use-case that those two mechanisms don't already satisfy?
It makes me a little uneasy, because the use-case is unclear (at least to me) and its the sort of thing that has a moderately high potential for error by causing violation of assumptions in the tile selection algorithm. From what I can see, this PR doesn't actually use the "render ready" flag at all. So it should be pretty easy to extract that part into a separate PR, right? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lots of small comments here, but once again, it looks great overall!
Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h
Outdated
Show resolved
Hide resolved
Source/CesiumRuntime/Public/Cesium3DTilesetLifecycleEventReceiver.h
Outdated
Show resolved
Hide resolved
No you're right, my time budget use case doesn't add anything indeed.
I understand, I will remove it from this PR. I have started testing again our app without this deferred texture setup system, I guess if it proves stable and no longer show any bug like the one we had, we may remove it entirely on our side too in the future. |
0387394
to
8113a0a
Compare
Which was not possible with a TObjectPtr<ICesium3DTilesetLifecycleEventReceiver>: tried a TScriptInterface, but decided for a UObject after reading about caveats: see comments over UCesium3DTilesetLifecycleEventReceiver. Also flagged UCesium3DTilesetLifecycleEventReceiver with 'CannotImplementInterfaceInBlueprint'
This reverts commit 380fa13. I was supposed to remove the F from our version, not add it to the upstream... ;^^
and from SetGltfParameterValues, which it probably mimicked in the first place
@kring , I believe I have accounted for all comments so far - ready for next round ;^^ |
Proposed implementation for #1658