Skip to content
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

Open
Calinou opened this issue Aug 18, 2022 · 36 comments · Fixed by goostengine/goost#162
Open

Add singletons for 2D and 3D debug drawing #5196

Calinou opened this issue Aug 18, 2022 · 36 comments · Fixed by goostengine/goost#162

Comments

@Calinou
Copy link
Member

Calinou commented Aug 18, 2022

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:

  • Player/enemy travel paths
  • Areas of effect
  • Enemy cones of vision
  • Overhead entity information (health, velocity, …)

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

  • 2D and 3D debug drawing should use separate singletons to avoid naming collisions.
  • Debug drawing should be toggleable with a Debug menu option and command line argument, similar to visible collision shapes and navigation.
  • The singletons and their methods should remain defined in release builds (but should do nothing). This way, your code won't cause errors once exported.
  • I suggest using shorter naming than usual to reduce the amount of typing required. Unlike most game logic, debug drawing is often something you'll pop in and out of during development. So it makes sense to use methods like DebugDraw2D.line() instead of DebugDraw2D.draw_line().
  • It should be possible to specify a duration for which the element is drawn (in seconds). The default is 0 (indefinite). -1 can be used to draw something for a single process frame, and -2 for a single physics_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.
  • Line antialiasing for 2D debug drawing should be toggled with a project setting, rather than provided as individual function parameters.
  • The font for debug 2D/3D text drawing can be overridden in the project settings (so you can use a fixed-width font if desired). The default project font is used otherwise.
  • 3D debug drawing always uses the Disabled cull mode, so that you can see it from the inside (useful for translucent debug drawing). 3D debug drawing is also always unshaded for better visibility and performance.
  • Parameters are made optional whenever possible. Only positions and sizes are required, everything else is optional. Colors default to white with 50% opacity if not specified (so that overlapping lines can be detected). Widths default to 1 pixel in 2D and 0.01 unit in 3D. on_top defaults to false in 3D. Font sizes default to 16 pixels.
  • For optimal visibility on all kinds of backgrounds, everything gets an automatic outline of shadow or some sort. For geometry, this is done by drawing a second time with a slight offset (relative to width) and a darker color (or brighter if the base color is dark). For text, this is done using font outline properties.

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 is false by default)
  • circle(radius, duration, height, rotation, color, filled) (height defaults to -1, which adjusts to be radius * 2 automatically). filled is false 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 is false by default)
  • sphere(radius, duration, height, rotation, color, on_top) (height defaults to -1, which adjusts to be radius * 2 automatically)
  • cylinder(height, top_radius, duration, bottom_radius, rotation, color, on_top) (bottom_radius defaults to -1, which adjusts to be the same as top_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 is true 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.

@YuriSizov
Copy link
Contributor

YuriSizov commented Aug 18, 2022

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, debug_draw(node.position).

I'm not in favor of a too high-level method, that would work like debug_draw(node). This would be complicated to maintain and won't fit everyone's expectations ever. I think supporting only Variant types is a good middle ground.

@Zireael07
Copy link

Zireael07 commented Aug 18, 2022

For optimal visibility on all kinds of backgrounds, everything gets an automatic outline of shadow or some sort. For geometry, this is done by drawing a second time with a slight offset (relative to width) and a darker color (or brighter if the base color is dark).

<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.

@Calinou
Copy link
Member Author

Calinou commented Aug 18, 2022

So how do you default to 0.01 unit?

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.

@SilencedPerson
Copy link

Question, do any Built-in Nodes use _draw() ?

@YuriSizov
Copy link
Contributor

Question, do any Built-in Nodes use _draw() ?

It doesn't exist in engine code. In engine code NOTIFICATION_DRAW is used.

@golddotasksquestions
Copy link

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 debug_draw(object) or like this Debug.draw(object)!

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 debug_draw(object) or Debug.draw(object) all this boilerplate code would be gone for the user and they could focus on finding the error rather than some point in some mesh they have still have to write a custom function for so it's a different color than the one from the previous object ... just so they could finally get to visually debugging ...

@Zireael07
Copy link

@golddotasksquestions:

But the benefit of speed and convenience using sensible defaults would outweight customization a million times.

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.

they can already use _draw() in an Autoload with almost exactly the complexity and behaviour as it is proposed here

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)

@golddotasksquestions
Copy link

golddotasksquestions commented Aug 20, 2022

@Zireael07

And how do you propose those "sensible defaults" would be arrived at?

Exactly how we arrive at any other decision: Someone makes a proposal, other users comment and discuss their concerns or express their support.

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)

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 print(variant), debug_draw(variant) or Debug.draw(variant) would work by making general assumptions, which are suppose to fill common, generally appropriate needs(some of which I illustrated in my comment), and not trying to predicting every possible user debugging desire, trying to fill all needs of all users.

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 debug_draw(variant) or Debug.draw(variant) method would cover only 80% of your daily most common visual debugging needs

(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.

especially when the object/scene is something more complex.

You have to think of it like just like print(scene) vs print(node) vs print(value). All of this works. It does not matter how complex the thing is you are trying to print. I'm saying we need the same, just visually.

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.

When you call print(MyFPSCharacterScene), you would not expect it to magically guess what you care about either, would you?
No, the print method has something I call "sensible defaults": It assumes what is relevant information and that's it, that's what you get. That what you always get. It will print the scene name, the node type and it's unique number. That's it. No need to guess what the user wants, because this assumption is made in the implementation (maybe some of it could be slightly customizable/configurable in the Project Settings, idk).

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 _draw() in an Autoload.

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.

@YuriSizov
Copy link
Contributor

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.

@golddotasksquestions
Copy link

Most of the time printing a complex object is useless, and you need to print its properties instead.

Yes exactly. So why are we talking about it? Just like print($MyConplexObject) most of the time is useless, so would be Debug.draw($MyConpexObject) be useless most of the time. Just like print($MyComplexObject.property) is more useful, Debug.draw($MyComplexObject.property) would be more useful.

Sometimes printing an object is very useful though. For example print(KinematicCollision) or Debug.draw(Control)

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.

@YuriSizov
Copy link
Contributor

I guess this plugin should be mentioned as one point of reference:
https://github.com/DmitriySalnikov/godot_debug_draw_3d

@Zireael07
Copy link

Wasn't aware of this one, thanks for sharing - it'll be extremely useful until this proposal is realized

@Sulter
Copy link

Sulter commented Oct 23, 2022

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().
Have there been any counter-arguments that haven't been refuted yet, or is it just a question of drawing up a new proposal?

@visuallization

This comment was marked as off-topic.

@Calinou
Copy link
Member Author

Calinou commented Jan 12, 2023

@visuallization Please don't bump issues without contributing significant new information. Use the 👍 reaction button on the first post instead.

@Calinou
Copy link
Member Author

Calinou commented May 2, 2023

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 debug_draw(object) or like this Debug.draw(object)!

See also #5533 (comment), which is an approach I tend to like more for this kind of stuff.

@Zireael07
Copy link

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

@nkrisc
Copy link

nkrisc commented May 26, 2023

I like the idea of Debug.draw(object), but in addition it would also be nice if there was a related _draw_debug virtual method defined on Object that would be called by Debug.draw on the object, if overridden, so that if you do have some complex custom object you can define how you'd like it drawn. This way if you wanted to use data from the instance when drawing the debug shapes, you can define that in the class and not muddy up your debug calls elsewhere.

@EikoBiko
Copy link

EikoBiko commented Sep 14, 2023

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.

@golddotasksquestions
Copy link

golddotasksquestions commented Sep 18, 2023

@EikoBiko

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.

This already exists. It's called "Custom drawing" in Godot:
https://docs.godotengine.org/en/stable/tutorials/2d/custom_drawing_in_2d.html
See all the "draw..." methods in the CanvasItem class:
https://docs.godotengine.org/en/stable/classes/class_canvasitem.html

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.

@Calinou
Copy link
Member Author

Calinou commented Sep 18, 2023

This already exists. It's called "Custom drawing" in Godot:

This is only available in 2D, not 3D.

@golddotasksquestions
Copy link

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.

@PrecisionRender
Copy link

PrecisionRender commented Sep 23, 2023

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 Debug.draw(MyFPSCharacterScene.velocity), how would I know what to expect it will do? Even if I know what it will do, what if I want the arrow to be a slightly different color or size than the default? Maybe I want some extra lines representing desired velocity, etc. If I understand this suggested approach correctly, even with this "intelligent" solution, boilerplate code is still required in almost all non-10-minute-prototype use cases. Debug drawing is a highly specialized portion of debugging that should be left up to the user to decide the best way to display on screen.

Therefore, I think implementing drawing Varaints is a bad idea. Why not just use DebugDraw2D.draw_string(Varaint.to_string())?

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.

@Calinou
Copy link
Member Author

Calinou commented Sep 26, 2023

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.

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.

@golddotasksquestions
Copy link

golddotasksquestions commented Sep 29, 2023

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.

@PrecisionRender
Copy link

PrecisionRender commented Sep 29, 2023

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 on_top, but the existence of this variable indicates that it's not the only way to render 3D debug gizmos)

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.

@aXu-AP
Copy link

aXu-AP commented Oct 1, 2023

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 duration. Duration = -1 (process) would be good for monitoring real-time values (eg. fps counter and nodes' properties). Longer duration texts would work more like console printing.

If I understand it right, the order of nodes running _process() is always the same so text would stay in place from frame to frame as long as tree doesn't change (for _physics_process the order might be indeterministic if multi-threading is turned on and generally would mix badly with process timed prints).

This is IMHO needed, because for moving objects, it's hard to read debug text if it moves with the object/camera.

@PrecisionRender
Copy link

PrecisionRender commented Oct 1, 2023

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 duration. Duration = -1 (process) would be good for monitoring real-time values (eg. fps counter and nodes' properties). Longer duration texts would work more like console printing.

If I understand it right, the order of nodes running _process() is always the same so text would stay in place from frame to frame as long as tree doesn't change (for _physics_process the order might be indeterministic if multi-threading is turned on and generally would mix badly with process timed prints).

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.

image

Or we could turn this into it's own interface, as seen in #7091 (comment)

@aXu-AP
Copy link

aXu-AP commented Oct 1, 2023

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).

@Calinou
Copy link
Member Author

Calinou commented Oct 1, 2023

, 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. 😛

@TrickyFatCat
Copy link

TrickyFatCat commented Nov 5, 2023

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
Copy link

SirPigeonz commented Nov 5, 2023

#6857 and #2072 are related to this proposal I think, because they could be solved by this one?

Basically makes debug draws more controllable by users I guess.

@TrickyFatCat
Copy link

@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.

@eobet
Copy link

eobet commented Aug 3, 2024

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...

@Calinou
Copy link
Member Author

Calinou commented Aug 3, 2024

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

@cmann1
Copy link

cmann1 commented Aug 15, 2024

A small addition is that I think there should be an option to allow these to not be stripped from release builds.
There could be situations where you may want to still be able to create debug visuals for users, e.g. modding or level editing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.