-
-
Notifications
You must be signed in to change notification settings - Fork 97
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 singletons for 2D and 3D debug drawing #5196
Comments
I think there is a benefit in a generic "debug draw" method for various Variant types. This would allow to have a quick and simple way to draw base data, like bounding boxes and vectors, without going too deep into magically being able to debug draw every node in Godot. The proposed low-level methods are also useful to construct your own complex debug drawing behavior, but won't be as handy in my opinion. We can have both, we should have both. But I think it's important to have a relatively high-level method here. In a complex situation a high-level method can still be used as a building block. E.g. if you want to visualize some position of a node you'd be able to feed it to the method, I'm not in favor of a too high-level method, that would work like |
<3 <3 <3 Also nitpick: when tinkering with my own workarounds, I found it difficult to specify a 3D line's width, IIRC the point size parameter is ignored on most GPUs... So how do you default to 0.01 unit? EDIT: There ARE already several addons around doing debug drawing, off the top of my head I know three, but none are complete. |
It would default to 0.01 units in 3D space, which means the line's effective on-screen width would vary depending on distance. It may be possible to cancel this out with a shader, but at the same time, having a variable width depending on distance from the camera may be desired. |
Question, do any Built-in Nodes use |
It doesn't exist in engine code. In engine code |
I still think this is the right direction, but does not nearly go far enough. There is hardly any difference between this proposal and using _draw() in an Autoload. Debugging should be a single short line. Let me debug draw objects like this I have written a long and extensive comment on how that might work in practice here. Yes, for this to work we have to decide for the user how these debug visualizations look by default (details could be adjusted in a Project Setting). But the benefit of speed and convenience using sensible defaults would outweight customization a million times. If users don't need convenience but want customization and control over their debug visualization looks, they can already use _draw() in an Autoload with almost exactly the complexity and behaviour as it is proposed here. All this proposal saves them from doing is spending 2 seconds to add a Node to Autoload. All the other boilerplate code (getting points, defining colors, setting sizes), they would still have to write just the same with this proposal. If we had |
And how do you propose those "sensible defaults" would be arrived at? Unless they're extremely simple things like what visible collision shapes does, there is no way to predict what the user means when he wants debug_draw(object) especially when the object/scene is something more complex. Let's say I call this on my FPS character or my racer car. Do I want the collision? The raycasts? The spherecast? Speed/velocity as numbers? As vectors? The waypoint they're at? The state/mode the AI is in? There's NO way to set "sensible defaults" imho.
No, they can't (at least NOT in 3D). In 2D, yes, this proposal is essentially what you say, but for 3D there are NO functions to draw even a straight line, let alone a sphere or a ray (arrow) |
Exactly how we arrive at any other decision: Someone makes a proposal, other users comment and discuss their concerns or express their support.
If you seen my comment on how I would propose this solution to work, and following comments discussing it, you might have also seen me saying: Exactly like You can make the same argument about Scene Unique Names or many other Godot features. Often they are not for everyone in all situations, but for most cases for most people they make things easier and more convenient and therefore improve the overall efficiency to use Godot. If this (like: visualizing vectors with arrow heads to indicate direction, AABB with origin, Rect2 and origin of Control nodes, Collision shapes and origins of bodies and areas, print Strings and Number to a screen overlay, accept arrays of variants to allow to debug draw groups and children ... these are just the examples I reflecting my most common needs needs, I would have hoped others would comment their typical most common needs), then most people in most cases would have their needs met and we would only rarely have to write lot's of boilerplate code to do our visual debugging. I don't know about you, but I'm often too lazy to write all this custom code and push it out for later "when I really need it", just because it's so much setup just to make a damn vector conveniently show up on screen. And therefore often go without have any visual debugging for way too long.
You have to think of it like just like
When you call The key point is that you can write one line like Debug.draw(MyFPSCharacterScene.velocity) and it would automatically 2D overlay draw on screen an origin point, a line, an arrow head, maybe be name of the property and it's owner name as well plus give it all a unique color and outline. Compare this with the solution in this proposal: var random_color = Color(rand_rage(0,255), rand_rage(0,255), rand_rage(0,255), 1.0)
var velocity_start_point = cam.unproject_position(MyFPSCharacterScene.global_transform.origin)
var velocity_end_point = cam.unproject_position(MyFPSCharacterScene.global_transform.origin + MyFPSCharacterScene.velocity)
var arrow_head size = 5.0
var arrow_start_point = velocity_end_point + (velocity_end_point.direction_to(velocity_start_point ) * arrow_head_size)
DebugDraw.line(velocity_start_point, velocity_end_point, 0, random_color, 2)
DebugDraw.circle(4, 0, -1, 0, random_color, true)
DebugDraw.arrow(arrow_start_point, velocity_end_point, 0, random_color, 2) That's just one property. If you have multiple, you would have to write your own custom function with the current proposal. This is going to be way more verbose still. The workflow and effort for the user is almost identical to using In my proposed approach, you could simply use an array as argument, carrying any property or object you might want to debug draw: var debug_draw_array = [fps_char.velocity, fps_char.shape, fps_char.state, WayPointManager.current_waypoint]
Debug.draw(debug_draw_array) Or easily and simply draw everything you marked in your scene for debug drawing: var fps_char_debug_nodes = get_tree().get_nodes_in_group("fps_char_debug_draw")
Debug.draw(fps_char_debug_nodes) If that's not enough, write custom debrug draw code either using _draw() or Calinous proposed methods. |
Print outputting the name of an object and its sequential ID is not in the same league as guessing what is relevant for individual nodes or groups of nodes in visual debugging. Most of the time printing a complex object is useless, and you need to print its properties instead. Which is @Zireael07's point. The user needs to decide what to print or debug draw, because the user knows what is relevant in a complex object. In the parity sense, the result of printing a complex object is equal to adding a 2d or 3d label at the position of that object with its name and ID in visual debug, nothing more. |
Yes exactly. So why are we talking about it? Just like Sometimes printing an object is very useful though. For example If you are trying to print a complex scene, what is actually printed is the root node. The DebugDraw singleton could do the same. Also this feature could start small and get expanded over time if there is demand. Anything that allows faster visual debugging with less coding or thinking is an improvement imho. |
I guess this plugin should be mentioned as one point of reference: |
Wasn't aware of this one, thanks for sharing - it'll be extremely useful until this proposal is realized |
Just wanted to add that I completely agree with what @golddotasksquestions proposes. It feels much more natural to have debug_draw's for all built-in types, instead of just simple primitive types, which would just add a tiny bit of syntax sugar on top of the current _draw(). |
This comment was marked as off-topic.
This comment was marked as off-topic.
@visuallization Please don't bump issues without contributing significant new information. Use the 👍 reaction button on the first post instead. |
See also #5533 (comment), which is an approach I tend to like more for this kind of stuff. |
Whichever method/approach is chosen, something needs to be done sooner rather than later, as it's one of the biggest warts Godot has compared to competitors such as Unity |
I like the idea of |
New user of Godot, moving from Unity I'm in total agreeance that this should probably be a priority in some sense. My opinion is that a simple and flexible solution now that can be extended is preferable to one that comes with all kinds of bells and whistles later. Especially considering that the first instance of this conversation was issue #112 , which as of this month, will have been 4 whole years ago. This feature will be used constantly and was the very first thing I looked for when coming to Godot. Could all of this circular discussion be avoided with an implemented solution to just draw a line on screen using an expression, graphing calculator style? Extremely flexible and straightforward. Bundle a few basic functions that draws circles and lines, then people can combine those to make more complicated shapes. Even if a graphing calculator type solution isn't feasible, even just a simple draw line solution would allow people to at least hit the ground running with rudimentary shapes for debugging. |
This already exists. It's called "Custom drawing" in Godot: There are also free plugins available if you want something right now. Imo the goal of this proposal should be to make a built-in version of debug draw significantly more user friendly than custom drawing or any of those plugins. |
This is only available in 2D, not 3D. |
The only difference for 3D is looping through any 3D points and unproject their position with a single method call. Given how verbose custom drawing already is, these few extra lines are really neglectable. |
I'm interested in implementing this functionality, however, there still seems to be no clear decision regarding the desired implementation. Personally, I don't get what the big deal is regarding boilerplate code with regards to debug shapes. In no other engine can you feed in a raw GameObject, for example, into a debug draw function and expect it to spit out useful information, if it even works at all. In most other engines, you can only draw primitive types such as lines, text, AABBs, etc. I've never had any issues with this approach. Frankly, if one is too lazy to write 3 extra lines of code to debug their game... I'm not sure game development is for them. In the grand scheme of things, 3 lines of debug code is such a drop in the bucket and would be miles better than what we have now. It's my personal opinion that we should implement this in the way @Calinou originally suggested. Most if not all debug behavior present in other engines will be added as a result. Anything higher level like what @golddotasksquestions suggests should be delegated to an addon. Speaking from the perspective of a user, one-size-fits-all solutions will only cause confusion and frustration. If I was to type Therefore, I think implementing drawing Finally, take this post as me sharing my opinion. I have zero emotional involvement in this. Feel free to pick apart my arguments if you feel they're inadequate. However, if anyone expects this to be implemented soon, a consensus for the intended implementation needs to be reached. |
If you do it this way, custom drawing won't be depth-aware. You won't be able to draw behind solid or transparent geometry. This is suitable for some use cases, but not all the use cases you'd want to use 3D debug drawing for. |
The point of debugging info is to be able to see and read the debugging info. 2D is always rendered on top of 3D for a good reason. In what scenario is it useful to have the debug info hidden behind geometry? Personally I can't think of any. If however someone does, and they really want some debug graphic/info hidden in 3D space, there is still the option to use immediate geometry for 3D lines, Label3D and primitive shapes. |
This makes zero sense. The 3D debug drawing/gizmos should work the same way as the collision debug gizmos. This is how it works in every other 3D engine I've used. If you want something drawn on top of the screen, use 2D gizmos. Otherwise, use 3D. (Or use If the only counter-arguement in favor of the one-size-fits-all solution is that it saves a few lines of code here and there and a dislike on my post, I'm going to start experimenting with an implementation for the functionality in the original post. |
I think string drawing function should also have a version, which doesn't take position as a parameter, but prints the text starting from upper-left (or right if rtl) corner line by line downwards. This, like the other debug draw functions, should also support If I understand it right, the order of nodes running This is IMHO needed, because for moving objects, it's hard to read debug text if it moves with the object/camera. |
I support this, however it's decided to be implemented. Unreal does this in a similar way. Or we could turn this into it's own interface, as seen in #7091 (comment) |
I don't know how it works in Unreal, but traditional style console interface doesn't allow for updating info realtime, doesn't it? What I'm suggesting is that you could set text to disappear on the next frame (to reprint it with new info). |
If you set the console length to the number of lines you're printing every frame, you can effectively have text at a fixed position that updates in real-time. 😛 |
Here is an addon for Godot 4, which has a decent implementation of such debug draw and it would be great to have it in the Godot by default. Implementing a debug draw will defiantly make Godot a better engine for many developers, as debug functionality is a vital tool while working on games. Made by @DmitriySalnikov |
@SirPigeonz not only controllable but easy to use without spending much time creating a basic setup. For example, using a previously mentioned plugin I can easily visualize and debug the path between given points. @tool
extends Node
@export var target_points : Array[Node3D] = []
func _process(delta: float) -> void:
if target_points.is_empty():
return
var path : PackedVector3Array = []
for point in target_points:
if !point:
continue
path.append(point.position)
DebugDraw3D.draw_arrow_path(path, Color.RED, 0.25, true, delta) In this case, I spent more time thinking about what I want to debug, rather than creating a setup for this. |
Moving to Godot from Unreal I was very surprised that I couldn't find built in debug drawing. In Unreal, any raycast has debug visualization, and built-in you get visualization on the line trace and the hit location. And I haven't used Unity for a decade, but I seem to remember being able to just add a checkbox in the inspector for a curve to get it debug drawn, but not in a build... |
Visible Path nodes are available in both 2D and 3D since Godot 4.2 (enable Debug > Visible Paths in the editor then run the project). Per-Path color customization isn't available yet, but there's a PR for it in 3D: godotengine/godot#82321 |
A small addition is that I think there should be an option to allow these to not be stripped from release builds. |
Related to #112 and #4364. This proposal's text is taken from one of my comments on #112.
Describe the project you are working on
The Godot editor 🙂
Describe the problem or limitation you are having in your project
While working on game logic, you often need to visualize things such as:
While Godot already has options for visible collision shapes, raycasts and navigation, this doesn't always suffice. These options also tend to lack flexibility in terms of color and style customization, although it's probably better to address this specifically.
Still, for use cases that don't involve physics or navigation, a different solution is needed.
Describe the feature / enhancement and how it helps to overcome the problem or limitation
Add singletons for low-level 2D and 3D drawing (lines, shapes, etc). The goal is to allow drawing anything quickly, from anywhere. There is no requirement to use a dedicated function like
_draw()
, or having to draw from a script that extends from a specific node type.Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
Here are some requirements I can think of. Note that these requirements are geared towards convenience over absolute performance or flexibility:
General requirements
DebugDraw2D.line()
instead ofDebugDraw2D.draw_line()
.-1
can be used to draw something for a singleprocess
frame, and-2
for a singlephysics_process
frame. There could be constants for those special values, but you may want to type magic values instead while iterating as it'd require less typing.on_top
defaults to false in 3D. Font sizes default to 16 pixels.2D debug drawing functions
line(from, to, duration, color, width)
arrow(from, to, duration, color, width)
(arrow tip length is relative to width, and is reduced for short lines)multiline(points, duration, color, width)
(takes an array of points, for fewer draw calls and better joints between points)multiline_colors(points, duration, colors, width)
polyline(points, color, width)
(allows for proper joint between last and first point)polyline_colors(points, duration, colors, width)
polygon(points, duration, color)
polygon_colors(points, duration, colors)
rect(size, duration, rotation, color, filled)
(filled
isfalse
by default)circle(radius, duration, height, rotation, color, filled)
(height
defaults to-1
, which adjusts to beradius * 2
automatically).filled
isfalse
by default)string(position, text, duration, color, size)
(always centered and uses default font, supports\n
line breaks)3D debug drawing functions
line(from, to, duration, color, width, on_top)
(drawn from thin boxes to allow for lines of any thickness)arrow(from, to, duration, color, width, on_top)
(arrow tip length is relative to width, and is reduced for short lines)multiline(points, duration, color, width, on_top)
(takes an array of points, for fewer draw calls and better joints between points)multiline_colors(points, duration, colors, on_top)
polyline(points, duration, color, on_top)
(allows for proper joint between last and first point)polyline_colors(points, duration, colors, on_top)
polygon(points, duration, color, on_top)
polygon_colors(points, duration, colors, on_top)
box(size, duration, rotation, color, filled, on_top)
(filled
isfalse
by default)sphere(radius, duration, height, rotation, color, on_top)
(height
defaults to-1
, which adjusts to beradius * 2
automatically)cylinder(height, top_radius, duration, bottom_radius, rotation, color, on_top)
(bottom_radius
defaults to-1
, which adjusts to be the same astop_radius
automatically. Can also be used for cone with one of the radii set to 0)string(position, text, duration, color, size, fixed_size, on_top)
(always centered and billboard, supports\n
line breaks, uses Label3D internally.fixed_size
istrue
by default for better readability)If this enhancement will not be used often, can it be worked around with a few lines of script?
No, especially in 3D where
_draw()
can't be used.Is there a reason why this should be core and not an add-on in the asset library?
I'd suggest prototyping this with an add-on first, so that you can get an idea for possible shortcomings that may come along with development.
Once this is done (and the add-on proves popular enough in real world usage), we can consider rewriting it in core for better performance and engine integration.
The text was updated successfully, but these errors were encountered: