Coder Social home page Coder Social logo

godot-pathways's Introduction

Godot Pathways

Godot Pathways is a plugin for the Godot engine that allows you to create roads and paths for your 3D worlds. You can map an interconnected network with curvatures and intersections, and then let the plugin intelligently apply meshes to it, stretching and deforming them as necessary. If it doesn't quite fit the geometry over the curves correctly, you can always use manual adjustments to achieve the results you want.

This plugin is still in development, so definitely expect (and please report) bugs!

How it works

This plugin provides 3 new nodes for you to use.

Pathways node is the main node that combines the data from other nodes to produce the results. You can select where to output the resulting meshes. By default it will create a child node for output. Place it in your scene where you want the paths to be.

PathwayNetwork is a custom implementation of 3D paths and curves that allows to create a network of nodes with curves between them. Nodes can be a part of a straight path, or an intersection with up to 4 branches. Hold Ctrl to place a new path node, use Shift and drag from a path node to create smoothing handles. Place a single PathwayNetwork node as a child of your Pathways node.

PathwayPiece is a node that allows to define a mesh that will be used for either a straight part or an intersection. You need to select a MeshInstance for it to fetch a mesh resource. Intersection meshes need to be mapped on a "skeleton" for branches. You can use Y or X intersection type, with T existing but not being utilized yet. Place as many piece nodes as you want as children of your Pathways node. (Currently only the first node of any type is used).

License

This project is provided under MIT License.

godot-pathways's People

Contributors

yurisizov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

godot-pathways's Issues

Vertices are duplicated for the straight meshes

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.

Shapes don't meet properly at the ends of connected curves

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:

image

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.

Deselect currently selected node by clicking on it

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.

Two intersection overlap when they occupy adjacent nodes

As intersections are stretched between the origin of the intersection and every next connected node, two adjacent intersections overlap over the same path.

image

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.

Draw a connecting line between the selected node and the create node gizmo

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.

Add support for the underside of pieces (e.g. auto-extending pillars)

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.

Add support for multiple piece options of the same type

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.

Implement automatic collision generation for the resulting meshes

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.

Make the `PathwayPiece` preview auto-adjust camera to fit the mesh

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:

image

We can keep the zoom slider though, it works, can be useful.

Allow to manually adjust handles in the `PathwayPiece` preview

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.

Add support for the deadend pieces

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.

Add tool modes to the `PathwayNetwork` toolbar

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.

Make "Clear Network" toolbar action use UndoRedo

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.

Removing a node destroys its associated smoothing guide in connected nodes

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.

Add more detailed documentation on how to setup and use the plugin

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.

Improve intersection deformation logic and the application of weights

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:

image

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.

Add grid snapping for gizmos

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.

Add support for T-shape intersection, or drop it as an option

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

  1. Figure out that an intersection is more of a T than a Y (i.e. it has a big, ~180 or greater angle between two of the following branches).
  2. Learn how to properly rotate the mesh to match the curve disposition better. Currently we always start from the -Z direction and just move the branches around the center. For this we would need to pre-rotate the mesh to align more sensibly with the curves.

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.

Improve the mapping between intersection branches and curves

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:

image

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.

Add more projection modes when moving the gizmos

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.