TheDuckCow / godot-road-generator

A godot plugin for creating 3D highways and streets.
MIT License
328 stars 17 forks source link

Create the editor UX design #18

Closed TheDuckCow closed 1 year ago

TheDuckCow commented 1 year ago

This is a UX task around thinking of the best way to design the interface tooling around

The design should touch on the outlined features of this task, which represents more of the implementation side.

TheDuckCow commented 1 year ago

I have some working progress in another app, but in the meantime I wanted to share this video export I have from Miro (other diagraming tools like Figma's Figjam provide a similar experience). While it might not feel very godot-like to "pull out" segments like this to create individual road segments, it could be a novel way to allow users to create intersections from roadpoints.

https://user-images.githubusercontent.com/2958461/201505399-edb418fa-03cf-4f82-a6ff-e053c224e630.mp4

The biggest design hurdle I'm so-far stuck on is trying to make drawing roads as easy as adding new points in a curve, without having to completely reinvent a new operational mode (without some weird side effects).

TheDuckCow commented 1 year ago

See below first draft proposal for the road widget design. This does not presume any advanced or global editor panel exists, but does alleviate some of the need for one. This initial iteration does not account for a good way to draw more road points (ie what the demo above from Miro is showing off). We should see first how feasible it is to create custom widget shapes.

roadpoint widget mockup 01.pdf

bdog2112 commented 1 year ago

I had read that you could change Godot's gizmo handle appearance. So, I took a moment to test this in my spare time and I'm happy to report that it was easy and worked great!

There did appear to be limitations in terms of your ability to orient the handles. In fact, it only seemed to support "billboard mode" regardless of whether you enabled/disabled it.

As a test image, "road_segment.png" was used. It effectively replaced the circular handles, which was cool! Although, the hover activation zone still appeared to be a small circular area as opposed to the entire surface of the image.

On a positive note, the hovered handle image became brighter/more opaque to inform the user when it was ok to click.

Custom Handles

TheDuckCow commented 1 year ago

Nice research! Is it possible to set an orientation of those billboards, or will it always be perfectly top-down? Basically, for use to really make use of the custom shapes, we'd want them to align to the orientation of the mesh.

My guess is that the answer is "no", and that we'd have to use 3d immediate geometry (or similar) for that. It's still a good thing though, as we could create different colored circles to blend with immediate geometry colored geo to match.

bdog2112 commented 1 year ago

You're correct. There is no way to orient the billboards. They are always facing the camera.

Although, a camera is fed into the "set_handle()" routine. That could, theoretically, be aligned to a non-active camera. But, that raises additional questions. For instance: Would you want to add a separate camera for every handle? :-) Also, would you want the tiny 2D circular handle facing away from the active camera?

My takeaway is that the default "pink" handle appearance can be changed to something more aesthetically pleasing, attractive, or fitting for a project. Perhaps a light blue or white colored diamond or crosshair.

I like the way the handle becomes brighter when hovered and think it would be nice to extend that visual cue by also brightening a subsection of the widget geometry (using "is_handle_highlighted()"). That might help to fill the gap imposed by the handle's limitations.

bdog2112 commented 1 year ago

Oh! Just noticed that EditorSpacialGizmo has the following routines: "add_collision_segments()", "add_collision_triangles()". These exist side by side with "set_handle()" and they're used for "picking". So, it may be possible to simply click-drag the actual widget geometry! If so, then that might be the ideal solution.

So, to be clear: We're currently using "EditorSpacialGizmoPlugin". "EditorSpacialGizmo" is an alternative that might provide some additional features at the potential cost of added complexity.

Update: Both solutions utilize both EditorSpacialGizmoPlugin and EditorSpacialGizmo. However, the more advanced solution overrides EditorSpacialGizmo in order to better facilitate the use of its enhanced features.

TheDuckCow commented 1 year ago

Thanks for doing some of this investigation. Doing some more looking, indeed we are already using EditorSpatialGizmoPlugin for the current curve magnitude handlers. It seems we won't be able to push that much further than the pre-exisitng circles. Based on what you said and found, indeed I think we'll need to look into EditorSpatialGizmo

Two pages of relevance:

bdog2112 commented 1 year ago

Godot's tutorial for "EditorSpacialGizmo" actually tells you to, first, create an object from "EditorSpacialGizmoPlugin" Then, they go on to say that you must also create an override for EditorSpacialGizmo; meaning that you must use both.

I can't help but wonder if there's a subtle way that we can just take what you've already done and do some simple type casting or other magic in order to gain access to the desired subroutines.

The most important question, however, is: Do the "collision" subroutines actually deliver the functionality we want? Can we make the geometry directly clickable without the need to click on a tiny circular handle? It would be great to see an example where someone has demonstrated that it works. ;-)

TheDuckCow commented 1 year ago

yeah my thoughts are the same, a sample would be good to see. Hence I did some of the code searching, maybe some answers in the GPL sample referenced above which could be worth a look.

bdog2112 commented 1 year ago

Here is a Godot 4 bug report with a demo file and it specifically references gizmos and our subroutines of interest! The code reportedly works until you comment out a certain line. So, this may be a working demonstration of what we're looking for.

By the way, I looked at the examples you posted and I didn't see any that referenced "collision" routines. Did you?

Also, noticed that the issues we referenced now include the name and link of this issue thread, which is interesting since the repository is currently private.

bdog2112 commented 1 year ago

Further investigation into Godot's Gizmo "Collision" feature showed that it was a dead end. It doesn't provide the functionality we need.

Our Gizmos are attached to a Spatial called a "RoadPoint" and we use the Gizmo for its Handles. A Gizmo Collision Mesh moves the Spatial. Whereas, we want it to move/replace the Handles. Hence, the best approach is to continue using Handles as we currently do.

It's perfectly feasible to render a standalone 3D Mesh that tracks with the Handles when making "Slider" Lane Adjustments. So, that's probably our best bet.

Be aware that there may be minor conflicts if Lane Divider Handles are combined with Segment Magnitude Handles because, eventually, they'll all want to occupy the same space at the center of the RoadPoint. That subject needs some careful consideration. But, there's no reason why it can't work.

bdog2112 commented 1 year ago

For visualization purposes, here are some screenshots of a Lane Adjustment mockup inside Godot. Just remember to imagine pink dots superimposed on top of the widget Handles. We can change the dots to whatever image you want. ;-) We can even hide the pink handles when the widget is in motion.

Also, know that the Blue 3D Arrows will track along with the pink dots. But, conform to the RoadPoint Y-direction.

Two examples are demonstrated: 1 PNG Widgets 2 Mesh-only Widgets

Obviously, PNG images use a mesh. But, they look noticeably different than meshes that don't use image textures.

Pros and cons of each solution: PNG - smooth aliasing; washed out gray colors when zoomed out Mesh - jagged aliasing; brilliant colors when zoomed out

PNG color consistency might improve if only a single color was used. (e.g. Blue or White).

Godot Widget Screenshots

TheDuckCow commented 1 year ago

I'm leaning towards having the mesh layout, especially since immediate geometry needs to be pretty light. But, do you have an impression (for you) which will be faster to implement? Time might be the driving factor, and if both UIs are reasonably equivalent in their utility, then might go with the one that is quicker.

bdog2112 commented 1 year ago

Either solution requires a similar level of effort. One might consider whether they want to allocate resources to the art team to make PNG widget images or the modeling team to create widget models.

Meshes require modeling and they, ultimately, exist as a Scene in Godot.

PNG's use a simple Plane as a Mesh, which means no modeling is required. You can create a scene or just preload the PNG and instantiate a PrimitiveMesh in memory when needed. Of course, someone must create the PNG.

Once the assets are loaded, moving them around with Handles is, pretty much, the same regardless of which option is chosen.

bdog2112 commented 1 year ago

In an effort to find the best way to implement lane widgets, I did a deep dive into Godot's Gizmo classes: EditorSpatialGizmoPlugin (Plugin) and EditorSpatialGizmo (Base Class). This post is for posterity and anyone else who may benefit.

Godot's Gizmo Plugin Tutorial, however well intended, is quite lacking, confusing and, frankly, incomplete. In fact, many people note this in various blog posts and even bug reports.

It says to override the Base Class and instantiate it in order to create custom Gizmos. It's worth noting that a lot of Gizmo plugins are not doing this.

Overriding the Base Class yields an inconsequential improvement over avoiding it altogether and simply using the Plugin. There are 2 reasons:

  1. The Plugin gives you access to all Gizmo functions including those from the Base Class.
  2. You're attaching Gizmos to a Spatial (or other node), which can be used to house additional functions and store per-Gizmo settings. Hence, adding a custom Base Class into the mix just creates additional unnecessary complexity.

In the following table, we see that the Plugin and Base Class share some functions. Each class also has unique functions not found in the other. But, the Plugin has access to its unique functions as well as the Base Class functions because every Gizmo inherits from the Base Class.

Gizmo Class Comparison

Many of the routines in the Plugin have "gizmo" as an input and they are triggered when the user interacts with a Gizmo. Gizmos are "EditorSpatialGizmos", which means you can access all of the Base Class functions through them.

So, again, just to reiterate: It's not necessary to override EditorSpatialGizmo or even instantiate it. Just access Base Class routines through the Gizmos in EditorSpatialGizmoPlugin. If you have a special use case that warrants additional complexity, then by all means, customize EditorSpatialGizmo. But, chances are you won't need to.

TheDuckCow commented 1 year ago

Thanks for this writeup, very helpful here and to others (once this repo is open-source'd)!

Let me know if there's anything that still needs deciding, otherwise I'm happy to have you move along as discussed 👍

TheDuckCow commented 1 year ago

I am going to close this issue in the meantime. There will always be more iteration of the design, but this is a solid space in the meantime. "Drawing" and clicking to add next points will be a follow on discussion, but at this stage, I'm more likely to try and replicate the native curve drawing experience that godot users will be used to, rather than invent our whole other slick way of "dragging out" new roads.