-
-
Notifications
You must be signed in to change notification settings - Fork 251
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
The ability for VoxelInstancer to choose an array of mesh or scenes to spawn using one VoxelInstanceGenerator #682
Comments
The way you're supposed to do this currently really is to create separate items in the library. If you want them to use the same generator, save it as a file and share it among those items. But indeed, that means it's harder to guarantee items won't overlap (though even if that feature existed, overlaps can still exist when points are close). One of the reasons it works that way is because the instancer was primarily designed to spawn lots of multimeshes, like grass, and multimeshes take only one mesh. Those also don't matter wheher they overlap with a rock or not.
I don't see how that requires a whole different library. A library is just a list of items. It's rather the items that seem to require changes. What you're asking for sounds like an item that contains sub-items, or multiple meshes or scenes (depending on the kind of rendering backend chosen). Note that not everyting requires a scene, and not everything uses a scene internally. I'm quite confused about how this ties up, it doesnt seem very intuitive. The main thing I take from this, is that you want some kind of way to make "what is spawned" part of what a generator decides, instead of a generator spawning all instances of a single thing. I vaguely thought whether a graph system should be used here, but never elaborated further as I had lots of other things to do. What you're asking for sounds simple on paper, but goes in a completely opposite way to how things works internally. Which means unfortunately that it requires quite a lot of work, and I can't tell whenever I'll look into that. |
Is there a way of spawning and handling things directly from a VoxelGeneratorGraph? I mean some way of supplying the information to a GDScript? like signals? or something that can be triggered and execute a function in a script? |
No, this is even more far away from it. That system has zero knowledge of the other and run at very different stages of the pipeline. Voxel generators work on voxels, while instance generators work on meshes.
This is not scriptable currently (because of performance mainly, and the fact the way things work is not really set in stone, especially with your request) so I dont know why GDScript would get involved already. Before things to even become scriptable, deeper changes have to happen.
No signals here. Signals for what? For every instance? Imagine that being called for every blade of grass... no way^^" Something else to note on top of all this, is that the instancer works at different LODs too. It might be workable to have a generator choose between exclusive models for each point it generates within a specific chunk, but that's only for one chunk of a specific LOD. Other chunks of different LOD (larger, or smaller) still generate independently and at different times, placing different kinds of models. What generates on them can still overlap with chunks of different LOD, and if you also dont want that, it's makes things even harder. Generally it's something I thought you'd have to live with, to some degree. Again what you're asking for requires to change a lot of things at once in order to work together properly. It's not going to happen quickly. |
My request is to have the ability of choose what to spawn on a resulted location, does not matter how it is done. I am not trying to bother you or something similar, don't get mad please. And what I want is a way of choosing one thing over other in the same location. Only that, I don't know exactly how it can be done efficiently. I have two workarounds that will work:
The 1) will be the expected behaviour as I am requesting. It will choose what to spawn as child of itself on the same location. And here the VoxelInstance dont need to provide anything but only spawn the empty scene in that location. Knowing the 3D position of the scene I can use a Noise to get a value and that value to decide what kind of what I will spawn as child of it. The 2) is more fast and because I use the same parameters in a variety of items but with different offset of the noise, it will ensure in some degree that no one will overlap over other. So for now I have something to get what I want. |
I'm not mad, just making it explicit that doing it efficiently is not a simple change (well, not exactly hard, but not something I can do in one evening), and that it could be a while before I look into it. Your idea 1) is good when you instance scenes. It's simpler than changing the system or even exposing some kind of scripting, because it just does the same thing through the scene system. Regarding your idea 2), I just wanted to highlight something the generator does:
For each specific item, a generator always starts by generating a point cloud over a mesh, with a certain density, which is filtered by noises afterwards. When two different items use the same generator with the same settings, they will still use a different seed to generate the initial points, because that seed is a combination of a hash of chunk position and the layer ID (aka the ID of the item). So in theory there is already something that makes overlap less likely. Not sure what kind of offset you're using though. However if you're using a low-quality emission mode, such as "vertices", it will tend to make points themselves overlap even for the same item. Using "emit from faces" would result in better spread. If I understand correctly, the change you might want would be, instead of each item running its own separate generator, have a way to associate one generator to multiple items (although they would have to be the same LOD). It turns out it might not matter whether things are a scene or multimesh. |
I still havent worked on the code for this, but I had some thinking. RefactoringThe changes I would make, is to rework items generation as a a list of "emitters". Each emitter has one generator and is attached to one LOD level of the terrain. Emitters would then have a list of items, and some configurable logic that decides how the list of items is dispatched on each point. Items would no longer have a generator attached to them. This change of structure has non-trivial implications under the hood when it comes to identifying layers of items, especially persistent ones (which get saved/loaded as the terrain streams in and out). Things like assigning the same item in multiple emitters, or multiple times the same item into one emitter are examples of edge cases that need to be solved. Because so far, items were a single dictionary under the hood, matching the data structure used by the instancer node internally, with the key being their unique ID. That no longer works with a hierarchy of resources. Of course such hierarchy could be flattened as two lists using IDs instead, but it sounds like that would lead to really poor UX. The difference it actually makesAssuming such refactoring is done. What do we actually get from this? However, regarding overlaps... think about what I mentionned here. It seems that refactoring won't really make a difference in the outcome. Without the change, 2 items with the same generator (using emission from Faces) will each generate their points independently. But because they have different IDs, they will use a different seed, leading to different points being generated for each. Therefore, they will already tend to not overlap. Also, it doesn't actually makes performance better. Real problem?So in light of all this, do you still think you need this change? It sounds to me that you want this change, because you think it would solve overlapping items.
However, maybe you have other reasons to request this change? I'm not really opposed to doing it, because it gets a bit more intuitive to configure other things maybe, but I'm not convinced that it help that much in terms of outcome. |
Hello, sorry for no reading before, I was busy and at the same time I though you are busy too so don't cared about it anymore. But I need to know how it actually works. Why you said there are no way of avoid overlapping? Really I don't understand how it works and why it is so complicated. I understand that it work in the mesh, but that is like Blender with particles. And in blender there are no overlap, so, I still don't understand why here can be an overlap if we have one generator but a list of items to spawn (like blender can actually do with a collection). Of course, if just a near vertex is choosen and then another vertex that is very near to the last one, it eventually will overlap some, or not, depends the scale, the rotation, etc. I don't mean that, I mean I don't want one tree overlap over other tree because I want to spawn a lot of different trees with the same "spawn logic". Then the generator choose one and only one item for that ID / location / vertex / face result, whathever the location is. Like Blender does. In Blender I put a particles generator and a Collection as spawn objects. Blender choose one, and only one object from the collection for a desired particle. That is what I want. And for the nature of that, it will not overlap. You don't need to force not overlaping because it will not. And please don't get me wrong, I'm talking more to myself than to you, because I really don't understand how that can be so difficult to do. Maybe it is difficult and I'm not realizing it. But I'm a little surprised haha. That's why I wrote so directly, but it's not with you. I really appreciate your project, all the effort you've put in, and it's very well optimized and I wouldn't like to lose that quality. If what I'm asking for is very complicated, I think it would be a good idea to look at it more calmly. |
In theory that's not impossible of course. It's just hard to do in every case, in the context of this terrain system.
You can, but keep in mind this terrain system has LODs. There are multiple layers of meshes at different sizes and different geometry, and their triangles are used to spawn instances in the same areas (you could choose not to, of course. But could be constraining). So picking a "place" is a bit of a challenge, because geometry is different across LODs, and unless your world is flat, triangles don't even have regular sizes (check wireframe view):
What you say would work within a chunk, but there are neighbor chunks too. And parent chunks. And child chunks. They all generate at different times, different threads, and points can end up in the same spot (maybe not exactly, depending on emission mode, but very close).
Right now a face can be picked multiple times if it is large enough, for the same reason you could have two points close to each other when generating points in something as simple as a rectangle. You could have a whole chunk that is just two large triangles (for example if you crank up mesh simplification), so they have to be covered more to maintain the same density. It really just picks N random points on the mesh, and that point could be anywhere. Even if one point per face was chosen maximum, look again at what wireframe looks like. Some triangles are small enough that you could end up with two points very close even if they use different faces.
I'm not sure of that, or you'd have to tell me where you saw this. For particles, they do overlap, and suggestions are the same as what I do: https://blender.stackexchange.com/questions/43485/how-can-i-emit-particles-without-them-overlapping-each-other?rq=1. It depends also on the geometry, if you have it very regular then of course it might contribute, and if you dont randomize them then of course it also contributes, though you get grid-like patterns. And voxel meshes are not like that.
The first cause you mention is often what will lead stuff to overlap (if you emit from faces), so what you say here is a bit contradictory. Here are some details:
You can see the code for each mode here:
Already said earlier why that won't work as reliably here; assuming you mean "it chooses one object per triangle/vertex", look at the wireframe of voxel meshes. They are not like what you'd model in Blender. Overall, there might be some tweaks to improve the situation, maybe by using a combination of your proposal and different emission modes, it's just not easy to do it very reliably. Note: if you'd like to discuss more details in voice/screenshare I'm available on the Discord today 26/018/2024 (or later days, but only after 6pm UTC). |
Hello, how are you? I have an idea that would be more useful to me. Something I want to clarify is that I'm developing video games and that's why I need something practical and that works. I'm not here to ask for tastes, these are things I need for my next projects. I don't care if it's perfect, if it fails a little and some overlaps occur, but what I do care about is that it's not so obvious. Suggestion: New Emit Mode: "OneByFaces" -> #695 Edit note: I implemented it by myself so don't worry it is already implemented. A question is if you want to see it I can make a fork and put that code there. |
Hi there, a possible solution (at least it would work for me for the moment) is that we could add a property called "group", where we can put a text to group the different items. Instead of creating a system with multiple items in the same generator, this idea would only add a property to the already existing items. How would it work? For now I don't have a better idea than to have a global internal list for each group that the user has defined, in which the index of the triangle would be stored only if an item has been generated from it. Then when the next generator is executed, it would check if the index of the corresponding triangle is contained in that list and if not then it would skip the generation for that triangle. Of course if an item has to generate from vertices this would not work (although the index of the vertex could be used). But I think the idea is not bad to start creating a solution. On the other hand, if the user does not create any group, the behavior and the form remains the same as until now. Which guarantees compatibility and doesn't require too many code modifications. I'm not in a hurry to implement this, so don't worry, I'm just trying to see if I can find a practical solution that can be applied to this particular case. Remember that here my intention is to be able to choose from among several an item to instantiate from the same location. Which doesn't matter if it's with an additional list, as long as there's a way to be able to choose one from a group, it's enough. Note: I'm leaving this written here for reference because I still have to evaluate if I couldn't get the same result in another way. |
The thing is, it doesn't matter how you put it, internally there has to be a heavy refactoring on how things happen just because of the possibility.
Now that becomes quite a huge entanglement between this big refactoring and that single emit mode you want to use (it wouldn't work with any other mode!). It also doesn't sound efficient at all. |
Is your feature request related to a problem? Please describe.
I want to spawn a variety of objects (mesh or scenes) on the same spawn point choosing one kind over other in a deterministic manner.
Describe the solution you'd like
An array of scenes or mesh with a min / max configuration to trigger the spawning of it.
Describe alternatives you've considered
Creating a lot of items with params that hopefully does not overlap with another one.
Additional context
Maybe a solution can be implement a new VoxelInstanceLibraryItem class.
It can contain an array of "Scene" and an array of "Manual settings" that includes a min and a max value to take in account some output coming from VoxelInstancerGenerator, instead of a boolean value it can return a float between -1.0 and 1.0 just like the noise generators do and we can use that value to trigger the spawning of a kind of instance from the arrays.
Each instance will have a user setteable value of min and max. For example -1.0 as min and -0.5 as max for a kind of tree, and next -0.5 to 0.0 for other kind of tree, and 0.0 to 0.5 for another one and so.
That will instantiate different kind of trees but on the same density point as configured in the VoxelInstanceGenerator.
Actually I only can spawn one type / kind of object on the resulting location and is hard to mix for example a lot of trees because they can spawn overlaping. With this method only one will spawn on a same resulting location.
The text was updated successfully, but these errors were encountered: