yurisizov / godot-pathways Goto Github PK
View Code? Open in Web Editor NEWMake a network of roads with ease and creativity in the Godot engine!
License: MIT License
Make a network of roads with ease and creativity in the Godot engine!
License: MIT License
As intersections are stretched between the origin of the intersection and every next connected node, two adjacent intersections overlap over the same path.
This is easily solvable by the user, but it would be nice to make sure this does not happen. This way, the out-of-the-box user experience would be better and less stressful.
Suggestion
We need to detect that the next node on a branch is also an intersection. Given that information, we could auto-add a node in between, but it would probably be better to just offset the end of the curve by 50% and make the intersections meet in the exact middle. If the user wants more control, they can add an actual node there and adjust it.
We could also leave it as is for some time and let users fix that as they see fit. But note, that the current behavior also introduces an error due to invalid mesh trying to be created:
servers/visual_server.cpp:965 - Condition "array_len == 0" is true.
scene/resources/mesh.cpp:851 - Condition "len == 0" is true.
scene/resources/mesh.cpp:971 - Index p_idx = 0 is out of bounds (surfaces.size() = 0).
scene/resources/mesh_data_tool.cpp:45 - Condition "p_mesh->surface_get_primitive_type(p_surface) != Mesh::PRIMITIVE_TRIANGLES" is true. Returned: ERR_INVALID_PARAMETER
So at the very least, this error needs to be silenced.
Currently only a brief explanation is available in the readme file. We should work on more documentation to explain all the necessary details, including how to use parts of the plugin individually (so, detailing what APIs the nodes expose; should also help with contributing).
GitHub Wiki can be used for that.
Currently the branches and curves are mapped using a clockwise order from the -Z direction (so, 12 o'clock if looked at from the top). This results in weirdness, though, then the top-facing branch is to the left of that line. When it's to the right, it's properly mapped to be the first branch, but when it's to the left it's mapped as the last branch, being in the 300+ degree area.
This doesn't make good usability and produces this:
We should try to identify that we want a top-facing branch to start the order and find the most appropriate out of all of them and use that as the initial direction instead of -Z. Similar problem needs to be solved for #7.
Current toolbar only allows clearing the network (should probably be replaced with an icon button). Tool modes can only be activated by pressing and holding specific keys on the keyboard. This may not always be handy, plus this means that we lack feature parity with the built-in path editor.
So tool mode switches must be introduced to the toolbar. That would be dedicated buttons to select a mode for something that is only currently possible with holding a Ctrl or a Shift. That would include adding and removing nodes; connecting, splitting, and separating paths; adjusting smoothing, including making the curves ins and outs align in a pattern. Most of those, if not all, could benefit from a dedicated tool mode.
Currently the PathwayNetwork
gizmos are projected to the 3D space using the same logic as the built-in path editor does. The screen space is used as a plane and then the point is put at some distance away from it. This works okay for the top-down view, but not so much for other views, especially when you need to precisely adjust your points vertically.
Thankfully, https://github.com/HungryProton/scatter already does provide a couple more interesting options, including using the plane of the path and relying on colliders (so does https://github.com/Arnklit/Waterways, if I understand correctly).
I've already included the necessary code for those options into the project, but there is no way to toggle between them. Buttons need to be added to the toolbar for that, and the switch needs to be hooked into the logic where appropriate. Functions were not tested yet either, so there may be some bugs. The collider option can also benefit from selecting which physics layers it can interact with.
It's hard to make precise grids currently, as all the nodes and gizmos are placed in freeform. However, there are road network patterns that require precise placement, like city blocks.
A solution would be to enhance projection options from #17 with snapping settings. In addition to grid snapping, smoothing handles would likely benefit from radial snapping too.
Currently this action just clears the entire network without any confirmation or a way to revert the change. It was okay for the testing, but it's not going to be okay for user projects.
Thankfully, after we've refactored the network operations to record all the affected nodes before any action, we can easily utilize it here to store the network data and do UndoRedo properly.
Current setup demands that the models follow specific shape to be properly mapped, like a T-pose. Y-shape intersections need to have a branch going top (-Z), then another 120 degrees to the left and another 120 degrees to the right. T-shape uses the same logic but the second and third branches need to be 90 degrees to the side with a 180 degree spread below. And finally X-shape uses 45 degree start and then every next branch needs to be 90 degrees from the last one (following the X shape).
This may be too limiting, plus you need to input the appropriate length of all bones in the inspector, and all bones must be adjusted at once. It can be a good improvement to allow handles to be moved independently to give them arbitrary angle and length. The T- and Y- and any other shape can then be used just as a guide for the initial position (see also #7).
On the other hand, mapping bones by hand may be too unreliable and preparing a proper mesh could be a more stable solution for end-users. This warrants more feedback before implementing.
Currently it's impossible to intentionally deselect any node, this can only happen automatically under certain circumstances. It is possible, however, to create disconnected parts of the same network by splitting existing paths, but due to the aforementioned limitation you cannot just go ahead and create new dangling nodes to start a new part.
The logic is already there, I just didn't implement the toggle for it. When clicking on the already selected node we should simply deselect it.
Currently the zoom level of the preview camera is fixed for simplicity, but the intention is to automatically adjust it to always fit the mesh in camera's view. The AABB of the mesh should be used for this, plus some padding on top.
This is how it looks in a demo scene right now due to meshes being larger than the ones I used for debugging:
We can keep the zoom slider though, it works, can be useful.
If you try to create a new node by holding Ctrl, an icon will be drawn to indicate that. However, it can be unclear that the new node will be connected to another node that is already selected. We should draw a clear connecting line to highlight that fact.
We already draw that line when we drag from the node to branch out, so it should be exactly the same.
Due to how the smoothing handles/guides are stored and synced with the actual available nodes, every time we remove a node we remove the associated handle. However, this becomes a problem when we only remove the node to replace it with another one on the same curve (when we split a path, or remove a node from the middle of a path, for example). In such cases the handle should be kept and remapped to the new node id instead.
As the roads produced by this are fully 3D, they could be used for creation of elevated highways or bridges. The underside of the pieces would be a problem, however. It would probably be impossible to handcraft a matching shape for the resulting mesh, so the only option right now would be to provide a mesh with an underside being a part of it and extending as far as it can possible go.
A smarter solution would be to allow defining a separate underside mesh for every PathwayPiece
with an ability to define an extrusion zone โ a part of the mesh that would auto-extrude to meet the ground below. Intersections would be rather problematic though, due to their extensive deformations. So another idea would be to introduce some smart pillars that would intelligently attach to the bottom of the generated mesh instead.
Requires further research.
Current way to deform the intersection mesh relies on almost "skeletal" deformation. The branches mapped in the PathwayPiece
node are then mapped to the corresponding curves of the network. And with them, the parts of the mesh are stretched to match the curves.
The manner is similar to the straight pieces, but the problem is that we have areas affected by multiple "bones"/branches. In these areas each bone's weight is accounted for (weight is basically a function of vertex distance along the "bone" from the start of the bone/origin to the end of it). The simples way to account for multiple weights that I could come up with was averaging them out, which is okay for the ends of branches (they are normally only affected by a single "bone"), but creates rather chunky middle parts of intersections:
A better logic is required.
To that end, a better logic is required to account for the origin rotation and radius. It should likely operate the same as weights, but maybe not. Another idea would be to use the rotation before anything else, so that the middle vertices are pre-rotated to the specified degree and only then transformed along the curve.
There is currently an option to define a T-shape intersection, but it's not actually utilized by the Pathways
node. For it to be used properly we need to
Then again, this may not be worth the effort. On the other hand, there are other types of intersections which can be based on the same logic. Like, railroad tracks can split and intersect in a manner that is very different from automobile roads. We may still want to add even more types of intersections here.
PS. We may want to refactor the intersection classification to just count the number of branches (3, 4). Then the basic shape would just be a button that organizes guides on the PathwayPiece
preview. This would allow any possible shape, but would be harder to support intelligently when generating the network.
When the straight mesh is extruded N times to match the length of a curve, it's just copied several times over without any concern for the overlapping vertices.
We should keep track of the added vertices and reuse them for the faces instead of adding new vertices all the time. A simply position-based dictionary should do the trick.
Title is self-explanatory. While it is possible to click on each mesh and use editor's own tools to create collision shapes for each node, it's not exactly fun to do it this way. We should look into making it either an automatic process during the mesh generation, or, if it's not feasible for the real time, to expose it as a toolbar action that can be triggered on demand.
While the Pathways
node keeps track of all its PathwayPiece
children, it only uses the first known option of each intersection or straight type. A basic logic to use random pieces can be achieved trivially (but keep in mind that determinism is preferred, so this needs to use seeds and an internal RNG).
However, more control should be provided to the user to achieve the exact look they want from the system. It should be possible to pick the exact intersection piece of the supported type to use for each network intersection. We could create billboard gizmos around such nodes that would act like buttons to pick between options.
For straight pieces it can be a bit harder, as pieces are multiplied based on the length of a curve, so there is no way to access individual pieces from the network. It would probably make the most sense to apply the same logic to the whole stretch then instead of the pieces. We could add the same type of gizmo-buttons for changing the look of a straight part as we would for intersection, and add an option to apply random pieces there as well.
Currently paths just abruptly end whenever there is a deadend in the network. A simple solution to that is an introduction of deadend pieces that would be added at such points as is, without any deformation. A more creative solution would be to reuse the same mesh as the ones used for the straights and generate a stump from that.
Not entirely sure how to achieve the latter and would enjoy more control from providing a dedicated mesh from the former, so I'd probably go with that.
Whenever a part of the network is created by two adjacent curves, the ends of the transformed meshes don't quite meet. It happens because the code for deformation has a condition that if we try to transform something beyond the end of the curve, we use the data from the last tiny bit of it, effectively repeating the last transform.
This means that two curves don't try to follow the overall shape of the network, and instead just end with the last known direction applied twice at the end. This results in breaks and overlaps like this:
Suggestion
To solve this we need to feed our mesh deformation logic with more data than just their curve. They need to become aware of how the path continues after they end, with proper smoothing and position of the next node applied. At the same time, I think that the current baked_curves
data should not be changed for this. It's good to be able to export the exact curves that make up the network. This information should probably be supplied in the same way we supply the intersection information.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.