-
-
Notifications
You must be signed in to change notification settings - Fork 21.7k
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
Add indirect draw functionality to MultiMesh
#99455
Add indirect draw functionality to MultiMesh
#99455
Conversation
Awesome, though could this bring a significant improvement upon instancing thousands of say blade of grass like some unity video had? Aside, making it more frustrum culling friendly would be a cool thing to investigate, maybe internally partition the multimesh in chunks? Not sure. |
Oh to be fair, the frustum culling not working is entirely my bad xD I just never implemented frustum culling and I failed at it, this system should work just fine with frustum culling, it's entirely user error in it not working in the test project. And using it for grass is exactly what I'll be doing, this is mostly to help with grass not being used but still needing to be in memory when you are in a location that doesn't have any grass. |
688ae8b
to
4b3b570
Compare
To fix the error see https://docs.godotengine.org/en/latest/contributing/development/handling_compatibility_breakages.html#id3 |
4b3b570
to
5eba36c
Compare
5eba36c
to
cc5f18c
Compare
Unfortunately I figured that out as well, and it has not resolved the error, not sure why, maybe I added it incorrectly? |
Looks like the error says |
cc5f18c
to
214dbdc
Compare
I don't think I could sigh any louder. |
214dbdc
to
711e352
Compare
e8abf8a
to
e546ae2
Compare
Mickeons change implemented, they worded it way better than me lol, thank you! |
e237dae
to
8ba50d5
Compare
Resolved both those issues and pushed out the stride count to an enum to resolve just having a magic number 5 everywhere xD |
Does this allow the multi mesh to use transforms computed by a compute shader? ie: can the mesh instances be moved/rotated/scaled by a compute shader? |
That is already possible! This PR takes it one step further and allows you to change the instance count via compute shader so you can generate or cull instances fully from compute |
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 feel like there used to be code that handled the case where a mesh had a new surface added? Was I just imagining that?
In either case, this is going to fail if a mesh has a surface added after being assigned to the MultiMesh
I was thinking before that maybe I should push out the actual generation of a command buffer to another function just within the mesh_storage.cpp and have it called when a mesh is added or changed, but was unsure if that would be ideal/if I should be adding new functions to something for specifically that, but it would prevent duplicated code, what do you think? Edit: Actually that might not be a good idea, I am very unsure how I would actually update a multimesh if it's mesh surface count changed, and yes that would break this, but the only thing I can think of is a rebuild command buffer function which could be called to refresh it. |
8ba50d5
to
783350c
Compare
No, I don't think it will occur often, but I do think it is something we have to account for. Currently if someone adds a surface to a mesh they will get a nasty Vulkan error message at best, at worst, they may get a crash due to an out of bounds memory read. |
Update doc/classes/RenderingServer.xml Co-Authored-By: Micky <[email protected]>
783350c
to
e6daec9
Compare
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 would really like to include this in 4.4 so I am approving it despite having two changes I would like to make. Overall the code is great and the feature is amazing, so these nitpicks shouldn't stand in the way
- We need to update the command buffer when a new surface is added or removed
- We can improve how we set the vertex count in the command buffer in
_multimesh_set_mesh
newVector.set(i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE, static_cast<uint8_t>(count)); | ||
newVector.set(i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE + 1, static_cast<uint8_t>(count >> 8)); | ||
newVector.set(i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE + 2, static_cast<uint8_t>(count >> 16)); | ||
newVector.set(i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE + 3, static_cast<uint8_t>(count >> 24)); |
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.
There is an easier way to do this. But let's leave it for a follow up PR so we can sneak this in to 4.4
Thanks! |
Didn't get a chance to add my style review (was busy and added a request for it) maybe I can do some of that in a follow-up |
Yeah Clay made it clear he wanted this merged before beta1, i.e. right now. Style improvements can be done in a follow-up and merged any time. |
Wondering if this could be used for multimesh batching (appears the answer is no): godotengine/godot-proposals#9673 I might be missing something here in the implementation, but I'm not getting a reduction in draw calls according to the runtime statistics (I haven't tried RenderDoc yet): @fire Built from latest master. 2025-02-09.14-30-46.mp4
Any ideas what I'm doing wrong? Maybe I need to set the mesh using the Edit: just noticed I am getting this error.
|
Can you move Like use one multimesh rather than many multimeshes. Like have all the meshes in the multimesh but per each instance hide the vertices using trickery. |
My bad, I don't think you can use it as a batch api. I'm assuming that each call to indirect draw is a call. |
No worries, I assume this PR has more to do with being able to control instances uniquely within the multimesh (maybe I'm wrong, haven't dug into it too far). |
That is correct, this lets you modify the number of instances in a multimesh from within compute shader. As for batching, that's an interesting concept, what you could do is take all the multimeshes with the same base mesh, instantiate a new one that is the target, and use a compute shader to merge all the buffers and set the count for the target as the total count, then you could even theoretically do frustum culling on that compute shader, while this exact thought was not talked about, the subject of having a toggle on multimeshes to make them automatically cull almost like particles but just based on frustum using the command buffer was floated in one of the rendering team meetings, and I think they both have similar objectives, I'm thinking about revisiting this with the purpose of implementing at least frustum culling. Not sure if all that helps any, as it's mostly just my musings on the subject, but I hope it at least gave some clarification. We do need more documentation though for sure. |
Frustum culling would be great. There's a proposal here for it. I'm investigating it today. I think for most users, being able to batch multimeshes finds the best usecase with chunked/cell based systems, and even if there were frustum culling on the broader chunk, that would be good enough. |
Currently has errors with the automated tests, not sure how to solve this, if anyone with experience could have a look and tell me what I'm missing, I'd be very grateful.
Implements a new indirect mode to MultiMeshes, when allocating data a "use_indirect" Boolean can be set to true, initiating generation of a command buffer, this will be updated whenever a new mesh is added, and works with multiple surfaces, or theoretically non-indexed meshes, this hasn't been tested however.
The command buffer can be used to allow multimeshes, or any buffer alteration function, directly alter the number of instances drawn, in the example project is a C# implementation, as well as a GDScript test, which is much less robust.
NEW example project:
Contains working frustum culling using compute shaders, and a simple grass model with implementation.
ZIP: newindirectdrawmultimeshexample.zip
Video: https://www.youtube.com/watch?v=NPtDSJaN3cQ
New project Gifs for eye candy purposes:
![CommandBufferTests8](https://private-user-images.githubusercontent.com/11287274/401388853-a7b57cb9-e380-4a12-964a-a9271616fa3c.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk3NDYzNTcsIm5iZiI6MTczOTc0NjA1NywicGF0aCI6Ii8xMTI4NzI3NC80MDEzODg4NTMtYTdiNTdjYjktZTM4MC00YTEyLTk2NGEtYTkyNzE2MTZmYTNjLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjE2VDIyNDczN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWI5MWY3N2VjMGMzNTdiYjk0OWVkYTk4MjcxNGM1MWUxNTI5ZjNiNGIzZDMzMmY2ZWIwOWMzMmZlMDg1ZjY2NTUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.bFhSNkOoK95mE_Y8Rx9Ja1vROKT-W-dpDJhYVEOhZQk)
Also some Examples of pausing the updating of the frustum culling, to show exactly what is being rendered by the gpu, with this method you can have an extreme amount of objects on screen with very good performance.
![CommandBufferTests7](https://private-user-images.githubusercontent.com/11287274/401388851-55ee8dd9-3208-4a01-bcdb-c448014619dc.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk3NDYzNTcsIm5iZiI6MTczOTc0NjA1NywicGF0aCI6Ii8xMTI4NzI3NC80MDEzODg4NTEtNTVlZThkZDktMzIwOC00YTAxLWJjZGItYzQ0ODAxNDYxOWRjLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjE2VDIyNDczN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWE4OTkyMGJmNzVhNDExNjYwMTUxOGFjMmQzZTNlYzI2ZTQ5MzRmYTFiNTJlNTM4MDkxZDZjODU4YThjYTk0YzImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.q1znMzKnPOrm1B_Pdm97M0TtblLYnTH9gZ9NjZcs4f4)
![CommandBufferTests9](https://private-user-images.githubusercontent.com/11287274/401388856-63427e3d-1616-45d3-b581-f7d2451027af.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk3NDYzNTcsIm5iZiI6MTczOTc0NjA1NywicGF0aCI6Ii8xMTI4NzI3NC80MDEzODg4NTYtNjM0MjdlM2QtMTYxNi00NWQzLWI1ODEtZjdkMjQ1MTAyN2FmLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjE2VDIyNDczN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTU4OTgyZWE5ZjQyZTRhYWMzZWM0MjlmOGRiZWY2ODM1NzBmYjJiODcxYWI4ZTBlNWEyMmY0NThmNWJkZTI5N2QmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.45qUqi1XftPdr_2-L7DqAw_nSkGx2PkCjkzGpP14UTo)
OLD:
Example Project:
IndirectDrawMultimeshExample.zip
The C# example in the project, 32k instances being enabled and disabled using a sine wave controlled through a compute shader with the command buffer bound to one of it's uniforms:
![IndirectRenderingexample](https://private-user-images.githubusercontent.com/11287274/387912368-819f760c-d8f9-477a-a3bf-f2a24295b4eb.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk3NDYzNTcsIm5iZiI6MTczOTc0NjA1NywicGF0aCI6Ii8xMTI4NzI3NC8zODc5MTIzNjgtODE5Zjc2MGMtZDhmOS00NzdhLWEzYmYtZjJhMjQyOTViNGViLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjE2VDIyNDczN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTRlMTZhZTg1NzFiZmRjMTY5Y2I2ZDI3NzQ1Njg0NzA3OWRlZjU0YzVkOGU3OTQ5NWNiMzQyNGIyMWE1ZWYxM2MmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.9QmqScNmXCtNmeJ2Ggcftlgx431S08jQUocSSYsr86A)
There's also a very ham-handed attempt at frustum culling in here which does not work, just an evening of me messing around with it.
Things that may be able to be improved, the method by which I composite the data into the command buffer within the mesh_storage could be improved, I am inexperienced in handling vectors in c++ and as such ended up with a somewhat clumsy struct method of building the data. Every other attempt I had to just write to a single entry in the command buffer (for example to directly update the number of instances without touching anything else) resulted in errors, and even crashing my computer several times, so for now I figured I would go ahead and put out what I have, and see what you all think.