-
-
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 support for immediate-mode debug drawing #112
Comments
I would use this often. Like all the time, everyday all day, in all my projects. It would save me an tremendous amount of dev time.
With this all I'd need to do would be Alternatively there could be a DebugVector Node, similar of the Line2D:
All properties are are accessed like this if the user want to change defaults: The weeks and months time I spend learning to understand various nested positional vectors could all be saved instantly for newcomers with something like this and allow easy and fast debugging for experienced users. (EDIT: differentiated between print-like functionality and a Node functionality) |
I agree that this sounds like something that would be used in a massive variety of projects, all the time. Personally, I favor the Debug singleton route. It just keeps everything simpler and would allow you to consolidate the implementation under a single class by having nodes call to it and have it submit requests to the VisualServer when appropriate (abstracting away the glue code complexity). |
I added further considerations to the opening post. You may wish to re-read it.
However I am unsure if an Add-on like this could be implemented with the current API. |
People need to realize that anything that is not part of the official download will not be used by users who first come into contact with Godot for a while. |
The AssetLib is clunky, yes, and the one embedded into the editor seems to not work for me at all. I prefer Godot's lean API over the bloated bag of redundant features you get with other Engines. If people have a specific problem they intuitively search for a solution and will likely find the AssetLib. However, that is not to say that I am still unsure where to have this debug feature. |
I made a utility script for this exact purpose some weeks ago, as I was also in need of drawing debug geometry. While it does work, it has at least 2 issues: it requires placing a node in the scene (usually a direct child of the root node), and ImmediateGeometry has some performance issues when drawing and deleting multiple objects every frame. |
It's nowhere near IMGui's capabilities, but I created this debug drawing plugin: https://github.com/Zylann/godot_debug_draw Someone also made an extended C# version with a lot more features https://github.com/DmitriySalnikov/godot_debug_draw_cs |
I read the posts and realized that something was overlooked. Of course, we can meet this need by writing with godot's current draw methods. However, lines or shapes drawn in debug draw applications are completely independent of resolution. In Godot editor settings, if you adapt your game to resolution, for example, the lines you draw for debug will also depend on this resolution. (For example, it will look thicker and thinner) Even if you make a general extension about it, you need to thin the lines that look very thick in a 512x512 game for a healthier test. And again, if you have a 4k resolution scene, you need to thicken and adjust these lines. Don't you think this is a waste of time for a simple debug that will speed up your work? Although the resolution changes in drawing applications with Debug, the image and thickness of the lines are the same even if you zoom in on the scene. Because these are debug lines, It doesn't need detailed settings for its appearance. These drawings don't have to look nice, they have a fixed look, maybe you can add optional color options if you need. |
The current line drawing behavior is to keep lines unscaled if their width is equal to 1, and scale them if their width is greater than or equal to 2. See #1363 and #2391. |
Wouldn't this cause other problems if I'm not mistaken? For example, I made a rope simulation in one of my games where I had 1 pixel lines drawn in runtime. When the camera zooms or we change the resolution, these 1-pixel lines also need to be scaled. I'm sorry if I misunderstood. |
Indeed, this is what #1363 aims to address. |
I'd much prefer to have at least some options at the very least, or rather, make current API more complete. In my experience, any "slightly less trivial" project already requires going for custom solution with Godot... I see that this proposal attracted things like |
I'm implementing a
Can be toggled via
In my implementation I've made it possible to sort of capture draw calls. For instance, you may do something like this: func _ready():
Debug2D.draw_set_color(Color.orange)
Debug2D.draw_set_filled(false)
Debug2D.draw_polygon(points)
Debug2D.capture()
Debug2D.draw_set_filled(true)
for i in points.size():
var point = points[i]
Debug2D.draw_circle(8, point)
Debug2D.draw_text(str(i), point + Vector2(0, -16))
Debug2D.capture()
func _input(event):
if event.is_action_pressed("ui_left"):
Debug2D.get_capture().draw_prev()
elif event.is_action_pressed("ui_right"):
Debug2D.get_capture().draw_next() This will track snapshots of draw calls. You could then play those draw calls back and forth, which is extremely useful for visualizing algorithms: debug_2d_capture.mp4Returning to the tags, I haven't yet implemented it, but I think this could be integrated this way: func _ready():
Debug2D.draw_polygon(...)
Debug2D.capture("terrain")
Debug2D.draw_circle(...)
Debug2D.capture("bullet")
# This will draw every snapshot related to terrain, but not bullets.
Debug2D.get_capture().set_filter(["terrain"]) But yeah, not sure if it's worth it, considering that debug draw calls can be wrapped in
I think this makes sense to implement as By the way, it's also possible to draw onto any Debug2D.canvas_item = $RigidBody2D
Debug2D.draw_circle(32) # This will be drawn relative to RigidBody2D local coordinates (at the center)
# Return back to the default (global) canvas.
Debug2D.canvas_item = Debug2D.get_base() If any such node has The Additionally I'd like to add a default grid as seen in goostengine/goost-plugins#1. There's also a Godot proposal for adding |
Recently I have added debug_draw_2d to Golden Gadget library (I didn't found anything else that fit our needs - not C#-only nor any special compilation/build settings required, for 2D and with more shapes than a line). It's pretty simple, not particularly optimized and only a few shapes, no projection and works similarly like those helper functions from Unity - shapes stay drawn for a few seconds. But for our purposes it's alright and I think it's general enough to be useful to others. It should be easy to use (if you manage to install GG it should just work), but the docs are a bit lacking at the moment (there is an example scene and I believe API is pretty intuitive). It can be turned off globally and is automatically disabled when not running from an editor. # draw a red dot on global position 300 100 which stays rendered for two seconds
GG.debug_draw_2d.point(Vector2(300, 100), Color.red) |
For the record, I have implemented an infinite grid to be displayed at run-time in Goost now: goostengine/goost#168. |
I was going to open an issue about the same problem , but I found this which is awesome these examples are from unreal engine is what I think when it comes to 3D debug shapes |
We've discussed this in a proposal review meeting, and weren't very confident this is needed in the engine. While lowering friction from new users is important, this is partially already possible with existing drawing methods, and partially can be handled by an addon. This also seems to already be implemented by a third-party engine extension, which is another proof that this can be handled by addons. |
Do you mean Goost or something else? |
This is very disappointing. Using _draw() or Line2D to visualize vectors not fast and definitely not userfriendly at all. Very disappointing indeed |
Goost is linked here, yes. But it can probably be made as a plugin too, as a more portable solution. All you need is a canvas item node that is globally accessible and a bit of code. |
Note that while it may indeed be fairly easy to do in 2D, for 3D I've pretty much had to come up with my own suite of immediate mode debug drawing that comes from project to project just to be able to do this pretty basic thing. I strongly suggest reconsidering, at least for 3D - all competitor engines do it out of the box |
In 3D you have the |
I stumbled on this while trying to untangle how to do simple vector visualizations. |
I would fall on my knees and weep if I could use an engine that did visualization like this. |
For 3D vectors, there's http://kidscancode.org/godot_recipes/3d/debug_overlay/ as a good starting point (note that I've had occasional errors with the way it draws vectors, but beats immediate mode lines being almost invisible in the distance with perspective). IIRC there is already an addon or two for 3D debug drawing BUT neither is really complete, that's why I always built my own solutions |
It doesn't print out anything more complex than primitive types and arrays/dictionaries. And there is a reason for that. "Smart" solutions are good as long as you, as a user, share the same sensibilities. The moment you need something different, you no longer have a smart solution. It's always better to give people building blocks to make their own world, than to give them a one-size-fits-all solution that would be either great or awful, but never in the sensible middle. So yeah, what you propose is great looking, and can be partially implemented, making it visualize different Variant types like vectors or rects. But it's better that for something more complex users decide for themselves what they want to see. Otherwise we would end up with people pulling the sheet in a dozen different direction over how to visualize an area in a way that works for everyone. Besides, your suggestion is additive to Calinou's description. We can have any helper method after we have a system, but first we need to create a system. When you attempt to draw outside of the drawing context you need to consider several things first. You conveniently show your method being run from the processing code, but people would expect it to work from any code and stay on screen for more that one frame. So you can't escape having parameters for your methods, unlike print, which just logs and moves on. For 3D things get even more complicated, because it seems users want to have two different formats of data. Judging by Zireael's comments, they want to have a projection from 3D space to screen space. But at the same time in 3D you want to have pure 3D debug as well, showing volumes or vectors in their actual space. And we need to make sure people understand that this is a debug-only tool, it shouldn't be used for gameplay purposes, as it is unoptimized and slow. So the fact that it should be stripped in production builds also needs to be considered. We understand what you need it for. Now it's time to figure out how to make it work. |
Pure 3D debug is awesome as long as you can see it. Kidscancode's solution has the advantage of always being visible, no matter how far away from the camera and how angled the camera is. (That said, since e.g. navmesh and portals already use some sort of pure 3D lines/volumes in editor, this should only be a matter of exposing those?) |
You don't seem to get it. We already have this complex solution with building blocks. It's the A fast one line debug draw method that covers (not all but) the most common basic usecases. This is exactly the same discussion we are having in the Mask2D proposal. We already have a feature like that, it's just too clunky and way too customizable, so much so it completely defeats the purpose for fast and convenient everyday use. Put usability first! Especially on a task everyone does a million times a day like basic debugging of vectors, objects, UI, strings, numbers, bools, paths ... |
@Zireael07 I'm not sure what is used in portals in 3.x, but as I've mentioned before, in 4.0 you can use ImmediateMesh as an equivalent of draw methods for 2D, a low level rendering tool. |
But I've agreed we could have something like this... I don't understand why you assume we can either have a low level solution, or a completely ideal high level solution. We can have something in the middle as well. Something that works not only for you and use cases you imagine, but that everyone else can benefit from as well, without being constricted by a fixed "smart" solution. You have described what you want ideally, which is totally understandable. Now it's time to ground your ideal vision in what can be implemented in a sensible, maintainable and widely usable way. For example there is no universal way to debug print or debug display arbitrary objects. We can display primitive data like vectors, but not arbitrary data. Because arbitrary data is complex, and when you take Godot's composition approach into account, you have a lot of variety in what can be important to the developer. Which is why it is best to not try and be smart, but try and be pragmatic. Give easy to use tools, but not tools that make unsubstantiated assumptions. Give debug draw to variant types, but let the dev use it manually on parts of complex objects. Then, as I've mentioned, there are timing considerations that you ignore in your examples. But we cannot ignore them in the implementation. In fact, what Calinou proposes stems from an internal discussion that also looked into how others do it, and is pretty much on par. So please meet us in the middle, where both usability and practicality are covered. |
I have never said or proposed or assumed we can have only either of the two. But we desparately need a super easy and super fast to use low level solution which works well enough for most usecases. A solution which does the work for you. If you also want to implement additional middle ground methods like those proposed by Calinou, that would be cool. But to me that would be a nice to have, not a necessity. Super convenience is where we lack the most in the debugging department (and other areas of Godot), not the "middle ground".
I thought it was obvious enough in my illustrated comment: of course a All this needs is a match statement that checks the type of the variant, then proceeds to draw supported types accordingly or spit out an error message if type is unsupported. Pseudocode: func debug_draw(varient):
match varient:
Vector2:
draw_vector2(varient)
String:
draw_string(varient)
CharacterBody:
draw_characterbody(varient)
_:
draw_unsupported_type_error_message(varient)
print(error_message) If 16 to 32 types and objects would be supported, this would already cover 99% of daily visual debugging usecases and needs. Even 16 supported types/objects would make A practical solution is one everyone can and will use every day because it is just so simple and convenient and covers most of everyday needs. To have that, assumptions have to be made!
This mindset is poison to anyone who values user friendliness and intuitive UI and efficient workflow. I really wish you and the other core devs and contributors would finally realize how clicking 3 times to change a sensible default, is exactly the same as clicking 3 times to create "New ..." from scratch. Only difference being that the sensible default covers common usecase, so for many people if not most it means they either don't have to click at all, or just once or twice instead of three times. If anyone of you has worked on user click patterns at a commercial company, you know every click is weighted in gold. Every single click less is a win! Some of Godots usability is mind blowing fantastic, but some other areas the Godot Editor really has a backwards anciently obsolete approach to usability, and what you just said about not making assumptions perfectly illustrates why. |
Yes, that was your ideal scenario. My point was that it's not going to work like that and not something we can reasonably implement. And it's also not what other tools do, according to our contributors who use them.
Well, you constantly juxtapose what we have now (low-level functions) with your idea of a super high-level method that does everything automagically. I see no assumption that anything in between is allowed. At best you call a middle-ground solution a marginal change. 🤷
Assuming that what is intuitive for you is intuitive for everyone and thus must be the only solution allowed is indeed poisonous. It's fine if you argue about something you passionately want for yourself, but painting people not in agreement with you as deaf to user pleads and full of poison is not a helpful direction to take the conversation in. And it's not going to help us find a technical solution that is sensible yet user friendly. Overall, I see there is a disconnect here between the desire for some user functionality and the reality of implementing it. It's a job for the both sides to hear each other, and so far it seems that technical limitations (and other considerations) are being ignored in an attempt to push for a "panacea" tool that implementers have to figure out themselves, no matter the cost. |
Intuitive is about cost of discovery, and in a game engine is irrelevant. Game engines have always had prescribed workflows for whatever. Intuition is not needed if I have clear documentation and bug free functionality. As a user I would prefer a simple and prescribed workflow than the ability to build the same house 10 different ways. |
This is certainly true, and a good argument why intuitiveness should not be used as a sole measure of success. Whichever solution we implement, it needs to be well documented.
Exactly, which is why it's important to focus on the general setup, and then we can split hair and bikeshed deciding which higher-abstraction methods are useful and which are not. The root of the problem, at the moment, is that we don't have a ready to use solution to draw outside of the draw cycle at all. So this is what we need to focus the efforts on. Hence why Calinou suggested someone interested in implementing this to start with a prototype addon first, to understand how this system would work. Whether it draws a line or a whole character rig in wireframe mode is utterly irrelevant at the moment. |
Can you explain why? Something like
Noting I proposed here is "automagically".
Fuck you Yuri! I'm done with you putting words into my mouth, Strawmen me. You do this every time and I'm so full of it! I never said anything about my comment being the only viable solution. You insinuating I would think it is undermining the message and my plea for more user friendly interface by attacking me as a person. I spend a sizeble amount of time yesterday out of my productive time to propose A possible solution among many other possible solution, because no one else proposed a one liner method with a similar user friendliness to print() yet. I spend a sizeable amout of time to think about how that could work and who it would benefit and in what situations it would be applicable. If you don't like it, that's fine! Please feel free to ignore my suggestions and comments. I'm done here. |
Because a big match/switch statement is not a maintainable nor scalable solution. What can be made ad-hoc for your project is not necessarily a good fit for the engine codebase. We can make a solution that draws different variant types, I'm all for it, but it making it aware of a huge variety of nodes in the engine is not going to yield something we can maintain. Which is why, just like with
You suggest we surface only one method, that would work with just about any data variable or node, or at least major groups of those. Without any user input and control it would just render a control or a character body in the best possible way for a debug. It would keep some assumptions baked into the engine and would "just work" from the user perspective. That's what I call "automagically". The burden here for us is when it doesn't work as some user expects. And the "smart" automatic solution becomes a problem for the user. Which is why I am insistent on the "building blocks" approach. So the user can decide "I want to render this nodes position, speed and general shape" instead of "I hope this universal method works out for my case".
I am trying to ground it and refine it. I ask you to consider the technical side of things, the part that is currently blocking the implementation. I ask you to meet the maintainer's concerns half-way, instead of focusing exclusively on user friendliness as you see it. In response you call my approach poison then swear at me 🤷 |
@golddotasksquestions overall, I don't understand why this conversation ended up insulting each other, actually both methods calinou's method works like every engine out there, draw_3D_debug(Object/Vector3/CollisionShape/etc) actually I think we can even combine both
using calinou's function and like golddotasksquestions suggested :
so I don't see a reason to fight here. |
@ywmaa If you've read my comments, I don't propose us to use Calinou's proposed API either. I, in fact, agree with Golddot that we could use one method, but I propose we stop it at only handling Then we can also have simplified methods to draw primitive shapes, if we want. What I ask us to focus on from Calinou's message is the general requirements section, because it outlines concerns beyond the simplest use case for the exposed API. |
no need to add every single node to this debugging tools, I think only the basic types are enough : |
These are not nodes, and yes, both Vector3 and Transform3D should be handled by this method. Collision shapes are resources, so I'm not sure (well, |
this looks good enough. also I agree and I don't think having a super debug tool that knows how to debug every node/resource/type is usefull, it can become messy in the Godot source code. basic types are enough and handle any other object with a simple draw. for me if I want to draw the skeleton3D maybe I can just get each bone, and get its Transform3D and then draw_3D_debug(Transform3D) |
Haven't read the whole discussion but if we're down to insults, this is really not constructive. Locking this for now, we'll reconsider once everyone has calmed down. I ask that users do not open new proposals on that topic for at least one week. We'll see then to either unlock this proposal for further constructive discussion, or open a new one summarizing the discussion so far (probably better). |
I opened a new proposal for debug drawing based on my above comment: #5196 Please continue the discussion there 🙂 |
Describe the project you are working on:
A side scrolling fighting game.
The game logic is in 2D, but visuals may be changed to 3D at some point.
I frequently wish to draw points or vectors in space to visualize and debug my logic, e.g. distances, directions, targeting, velocity, grids, touch-input bounds, etc.
At first I intuitively tried to call the public
draw_*()
methods of aCanvasItem
derived Singleton, but this results in the error:Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.
Describe how this feature / enhancement will help your project:
The goal is to conveniently draw debugging visualizations from anywhere in your code without cluttering the actual logic with glue code.
Further, any debug drawing code shall be clearly separated from drawing that is intended to end up in the final product.
Currently I see two workarounds to draw debug visualizations, both have drawbacks:
You either embed the entire debug drawing logic into your class e.g. if its Node2D or Control, but this clutters your logic with debug code for drawing. It does not distinguish between drawing that is supposed to end up in the shipped game and debug visualizations.
Or you have to implement a Singleton that provides various helpful shapes like point, line, box, etc. and make it work with the transforms of 2D, Control and 3D.
Similar to this: https://github.com/klaykree/Godot-3D-Lines/blob/master/DrawLine3D.gd
In the spirit of "The Godot editor is a Godot Game" we may argue that "any drawing is drawing" and we should not have an engine-side differentiation between debug and release drawing. In this case we may discuss what changes, if any, would be needed to facilitate the implementation of an Add-On with the desired capabilities.
Show a mock up screenshots/video or a flow diagram explaining how your proposal will work:
An API example may be of more use here:
Considering the performance impact it would be preferable to have the option to toggle all
Debug
calls at runtime additionally to compiling them out.Describe implementation detail for your proposal (in code), if possible:
https://github.com/klaykree/Godot-3D-Lines/blob/master/DrawLine3D.gd seems like a good start. Possibly attention needs to be paid to handling multiple viewports and offscreen rendering.
If this enhancement will not be used often, can it be worked around with a few lines of script?:
I assume it will be used often. It is likely more than a few lines of code to provide a generic class with a rich set of shapes like CanvasItem to draw in both 2D and 3D.
Is there a reason why this should be core and not an add-on in the asset library?:
A DebugDraw class like this may well be an add-on.
Implementing it on the native side may benefit performance though.
However more important may be to not hide such a debug feature behind an add-on.
Misc:
A more advanced version (or a add-on implemented on top of this core functionality) may offer the possibility to add Tags. This would allow to toggle the drawing of only certain tags at run time.
The text was updated successfully, but these errors were encountered: