Somehow, I feel like reading that article diminished the original critique, however, inefficient raycasts aren't some sort of pathological edge case.
Raycasts are the most commonly used spatial queries in a 3d game. Hopefully this discussion will lead towards this issue being resolved.
I actually found Sam Pruden's complaint a bit odd since it sounds like he's developing a 2d game. If you're spamming 1000s of raycasts per frame for your 2d game, there's probably something else going on...
"If you're spamming 1000s of raycasts per frame for your 2d game, there's probably something else going on..."
Yup .. but maybe not stupidity, but rather a non generic game.
In my case I need lots of raycasts, to determine what exactly the player and the enemy bots can see. Basically I have a simulation in 2D (using box2d directly in js as a wasm libary) - and all the bots and the player only (mostly) get information based on raycasts. They have to scan the world and react to that information, which leads to a different result, than the usual approach (cheating).
So I am looking forward to get this fixed asap as well and also cannot really consider godot before that.
Edit: performance problems with raycasts I had to experience as well, because the roundtrip js to wasm is expensive. I first wrote a WebGPU shader doing only raycasting in my world, but better was modifying box2d (and compiling to wasm) to include a function, that does all my raycasts in one call and returns a big array (or rather a array with pointers to the structs in the internal wasm heap).
If the game is 2D and you can divide space into tiles/blocks and walls/obstacles have their own blocks/tiles (or you can easily establish a grid over your world and determine what cell each actor is in), I wonder if there's way to use BFS in a maze-solving manner to calculate shortest path between a given actor and the target you want to check visibility for, and if the distance in blocks/tiles returned by BFS/pseudo-pathfinding is greater than a direct distance formula calculation between the two blocks/cells then maybe you know there's an obstacle? I guess that requires you to be able to create the network/graph of traversable nodes as well.
Well, the world is destructible, so when there is a small hole (of dynamic size) in a wall, then a enemy bot should really only see the player, if there is no rubble blocking the path.
Meaning tiles are waay too big for my simulation and raycasting the most straightforward way, also some enemies can evade projectiles and obstacles, but also have to scan them first.
And it works already the way I want it. It could just be more performant, so more details and realism would be possible.
Yes. I just expect raycasting to work allmost as good as possible, not on 50% to become a unnecessary blocker. But they say, they are going to fix it with some priority.
"Good raycasting should be sublinear"
yes, but some folks like to stick 100 raycasts on every character which will kill the performance regardless of what engine your making your game in.
It's hard to tell without seeing a screenshot or video of the game in question, but there are almost certainly ways to optimize this problem.
If there are on the order of even several dozen enemies on the screen at any given time, you could simply maintain runtime sets of different factions and only do line-of-sight checks between hostile groups within a certain proximity.
There's probably hundreds of better ways to do this than by spamming raycasts.
I have a VR space game with dozens of spaceships, and there are generally never more than num_spaceships raycasts getting fired every frame
"but there are almost certainly ways to optimize this problem."
Sure, I optimize what I can. But there is only so much I can do, without hurting the core game mechanic. Which is a arcade shooter, but also a hacker game, where you program your bots. So the bots are mostly limited to radar distance information by design, to work out their position in the world and what to do next (but to make this work with many bots, I already had to cheat a lot).
And it is unreleased, in case you are wondering .. but I hope to ship an alpha, soon. So it already works and it is fun. So I won't change core functionality, but I am still optimizing wherever I can. 3 months ago, it would only run on gaming hardware. Now medium mobile phones (a big market) are within reach.
Well, I would like to be able to do 1000s of raycast per frame (360 for each bot), but cannot and yes, I do not use godot, but my own engine (with pixijs for graphics and a emscriptem port of box2d for physics
https://github.com/Birch-san/box2d-wasm.) Godot uses box2d, too, so that would be convenient, if I switch to godot, but only if it is worth the performance improvement, which it currently does not seem to be. Maybe next year.
It's hard to evaluate this without seeing a screenshot of your game, but 360 raycasts per bot per frame for a basic 2d game is INSANE.
It sounds like you are trying to query every angle in every direction for every character. This is madness.
I have a 3d space game in Unity which uses raycasts for navigation. Each ship fires a maximum of 1 navigation raycast per frame with a sweep pattern. In addition there are anti collision thrusters placed around each ship which fire roughly every second in a staggered pattern to prevent ships from getting stuck
In my fully 3d game, that's effectively ~1 raycast per frame per enemy. To locate hostiles, each ai character scans a runtime set of potential hostiles and does a line-of-sight query roughly once every 5 seconds.
There definitely is another issue going on here with your setup that is independent of the extreme overhead in Godot.
I would recommend Sebastian Langue's excellent boids video
to get a sense about other strategies to deal with these types of queries: https://www.youtube.com/watch?v=bqtqltqcQhw
It's possible that they are building a game in which players can program bots that only know the state of the world by performing raycasts, as if it were a sensor of sorts. That would be a valid reason to require such an amount of raycasts per bot - although I probably would not run them every frame, but rather spread the load throughout multiple frames.
Yes exactly. But the projectiles are moving every tick, so the evading logic wants to run every tick as well. But optimizing that will be up to the player..
I’d recommend cheating! It only has to appear to the user that the bot is scanning the world. For example in this specific case you could find all the projectiles close enough to the bot to be detected and do one raycast per projectile to determine visibility. This is functionally the same result as many dense raycasts but at a fraction of the computational cost because you have all the information already in the simulation.
Although I really like the idea of giving the player control over how the bot raycasts and letting them optimise that. Lots of fun strategies to find there! I’d even bound it so they can’t afford to do too many raycasts so they have to get creative.
> Although I really like the idea of giving the player control over how the bot raycasts and letting them optimise that. Lots of fun strategies to find there! I’d even bound it so they can’t afford to do too many raycasts so they have to get creative.
This is actually exactly what I did when I built a similar game about a decade ago! Bots had a budget of 20 raycasts per second, which would slowly replenish. It was the bot programmer's responsibility to figure out the best way to use them. It was a lot of fun! :)
The usual solution for something like this is just to spread the work over multiple frames. Most game enemy logic doesn't need running every single frame. Update 10% of your bots every frame.
Also consider whether 360 rays is really needed to begin with, one ray per degree sounds like an arbitrary first-pass value. Can you cast a smaller set of rays first, and only cast the in-between rays if certain conditions are met (e.g. the initial rays hit something close, or their hit distances vary significantly)
"Can you cast a smaller set of rays first, and only cast the in-between rays if certain conditions are met "
Yes I can do this. But my case is really special as in basically the players have to do this by themself. As it is (also) a hacking game, meaning they have a limited scan budget and need to figure out to spend it the most useful for their bots.. but since they also want to evade projectiles and other bots, they want to scan as much as possible to not miss a threat.
So it works the way it is. Just would scale better, with better raycast performance.
I probably should have hinted more above, why my case is really special, but that was kind of my point, there are always special cases. And I do not want to limit my design, because of a bad raycast implementation.
You can still optimize this. If the scan has to establish line-of-sight between bots, your engine can establish that, and when firing raycasts, to skip those that are known to be misses. It doesn't change anything for the bot that fires raycasts. You could also calculate extremes (leftmost and rightmost) and return positives in between. This would decrease number of raycasts by two orders of magnitude. Also add a possibility to skip every 2nd, 3rd etc frame so that you can evaluate if it impacts game play.
Ideally yes, this is what I would like to do, to be able to control armies of bots. So because of the limitations, there are only 2-3 smart bots and lots of dumb ones.
I've been using ammo (wasm bullet) and while wasm interfacing certainly has a mismatch with idiomatic js I haven't knowably hit a problem with that bridge.
It used to be waaaay more expensive and has gotten much better now. But it still costs, all I know is, that when I do 600 raycasts each, it costs me around 8 ms on medium hardware. Batching it reduces the cost to 2 ms for me. For simple things like GetPosition I did not noticed a perf hit, but for getting vertices I also did. So mid term, I will batch all often used calls into wasm. For now raycasting was the biggest bottleneck.
Yeah it’s quite common on most interop boundaries because there is always some amount of marshalling. It used to be a thing in Unity that it was significantly faster to run your own tick for all entities from a manager that hooked the callback from native code than to have to cross back and forth n entity times.
For anything you’re doing in WASM it’s much better to batch and cross the boundary as little as possible in hot loops. For example a performant renderer wouldn’t translate all the API calls but put together a command buffer to be returned to JS and then forwarded to the API in one go.
> inefficient raycasts aren't some sort of pathological edge case.
You're right that raycasts aren't an edge case in terms of usage, but Juan Linietsky's point is that the inefficient path used for this API call is a rare exception to the efficient paths used by the vast majority of the API.
If you’re doing thousands of raycasts per frame in any game, 2D or 3D, then something has gone wrong. Raycasts are very general, and there is often a more specialized way to get the same information that won’t require as much work.
I learned to code in the 8-bit days where you'd count to 1000 in a BASIC for loop to create a significant delay. I guess I've not got out of the mindset that doing anything 1000x is quite a lot (particularly when you're aiming to do it 60 or more times per second).
But as somebody working in Unity (and often on mobile), there's still many cases where 1000 of something is a lot, and should perhaps be cause to rethink your approach. For example 1000 draw calls, 1000 UI elements, 1000 instances of even the most simple prefab.
1000 raycasts per frame is also something that I'd try to avoid. But if they seemed important, you've just got to try it and profile it. Nobody can answer 'what is the cost of 1000 raycasts?' without a fair bit more information.
I don't think how it can be wrong. I wrote a beaten-up game, 2.5D. Player(s) + Enemies + NPCs + Weapons + Bullets.. I can imagine that in some moments, we were easily doing a few hundreds of raycasts per frame.
Raycasts are a very useful tool, and you shouldn’t avoid using them if they’re the only thing that will work. But a _fully general_ raycast is always the most expensive option. For example, an axis–aligned raycast will always be cheaper and might do the job just as well.
The previously mentioned case of doing hundreds of raycasts all starting in the same location but each in a different direction could be done with rasterization instead. That’ll involve a single loop over all the triangles in the world instead of one loop over the same triangles for each raycast. And for NPC vision you could rasterize billboards instead of the full character geometry. You can probably simplify the world geometry too.
The original complaint was that Godot’s C# bindings have a raycast method that returns a dictionary. The reply article point out that this is a legacy of an earlier, less performant, C# implementation and that the work to clean it up was already under way. My point is only that raycasts are already something that you want to avoid; the extra work of allocating a dictionary each time you call it is unfortunate but not fatal.
There's nothing wrong with spamming 1000s of raycasts per frame in a 2D game. They should be very cheap, so the performance impact of that should not be something you have to think about, and if some interaction or mechanic is easy to express with a boatload of raycasts, you should be able to just do that
That's raytracing. You can do LOS by raycasting only at line segments and points of blocking shapes, especially in 2D, which is the original post's concern. https://ncase.me/sight-and-light/
Absolutely not. There's uh, a lot of tutorials on YouTube about how to go about implementing this kinda thing, depending on the kind of game (top-down 2d, vs 3d etc). Sorry don't have time to do a full write up lol.
I'm not sure I would have been so generous to the author of the article this is in reply to. But I suppose that's a skill of a successful open source leader -- to turn interactions with critics into productive discussions rather than arguments, and perhaps even turn the critics into supporters.
It seems to have been that author who chose the FUD-ful title "Godot is not the new Unity". I guess there are times in life where you face a choice: be fair, reasonable, and intelligent, or... just try to get them clicks.
I said this not long ago in a different thread, but after reading this article I want to say it again. I'm very impressed with the management of the Godot project. They seem to be avoiding all the common mistakes and drama that so many projects fall prey to. They're doing everything professionally.
I have contributed a very small amount of code to Godot. In the process of doing so I was very impressed with the entire process. They were very supportive and quick to respond. Overall it was one of the best open-source contribution interactions I have experienced.
> I'm not sure I would have been so generous to the author of the article this is in reply to. But I suppose that's a skill of a successful open source leader -- to turn interactions with critics into productive discussions rather than arguments, and perhaps even turn the critics into supporters.
FWIW, reduz (Godot author) and sprudd ("Godot is not the new Unity" author) previously discussed this on Reddit[1], and sprudd was actually sounded pretty nice (the first reply even includes a "and I hope that I wasn't too rude in the article. :)").
Overall, I think the original article was written in good faith, just with a click-baity title (and I imagine reduz thought the same thing). That might have helped to avoid a more angry reply.
Common now, the original article is perfectly reasonable one, and that includes its title as well.
For the past few days everyone is talking about Unity, and I don't think it's exaggeration to say that Godot has become the de facto alternative in low to mid level game development.
Godot itself will (if not already is) benefit from that status a lot.
Article that brings highlights parts well Godot is lacking compared to Unity is perfectly valid criticism to have.
> Godot itself will (if not already is) benefit from that status a lot. Article that brings highlights parts well Godot is lacking compared to Unity is perfectly valid criticism to have.
And that's because the author didn't even touch the "in-app" purchase and "in-app" ads capabilites from Godot x Unity, which is the way the studios complaining about the new Unity pricing, generate their income..
It sounds like Godot just needs a few more hands on deck to close up a lot of these smaller gaps, as Juan mentions most of the issues are already being discussed or were simply lower priority to fix. Hopefully with the influx of Unity refugees (and potential contributors) they'll be able to quicker ship more of the things they already have on their roadmap.
I do think the original article's claim of 'Godot is not the new Unity' is accurate, just not for the architectural reasons claimed. Folks probably shouldn't go into it thinking that Godot will handle every use case just as well as Unity. It hasn't had billions poured into it like Unity, but it is mature and ready for serious games. Plus - open source means you can just get your hands dirty and fix critical (for you) bugs instead of hoping Unity gets around to it.
> Additionally, modern processors all have at minimum 64 bit buses, so exposing anything other than 64 bit scalar types makes no sense.
I feel like this entirely disregards the caching costs of using >2x more memory in some cases, speed of float32 vs float64 operations on CPU, and potential CPU <-> GPU memory transfers.
EDIT: Nvm disregard this comment, I just noticed the existence of: PackedByteArray, PackedInt32Array, PackedInt64Array, PackedFloatArray, PackedDoubleArray
Anything set of numbers needed by the GPU or big enough to affect the cache will probably use those arrays.
In the context of function parameters at the edge of C# and c++ I don't think it will ever amount to a large amount of memory being wasted. The cache point may be relevant, but generally if you are calling into C++ in tight loops from your scripting language in a game you have already screwed up. So maybe not so bad.
>but generally if you are calling into C++ in tight loops from your scripting language in a game you have already screwed up.
How do you figure? Are you saying there should be no tight loops that hit engine code, none that live in the C#/scripting lifecycle or all tight loops should be rewritten in C++?
The elephant in the room, Unity, cross compiles the C# to C++ which makes this blanket statement about all games even more confusing to me.
> The elephant in the room, Unity, cross compiles the C# to C++ which makes this blanket statement about all games even more confusing to me.
As a game developer you do not have access to Unity's C++ code so to maintain some performance Unity needs to do that. But this is not the case with Godot or even Unreal where any intensive code should be written (or at least, rewritten) in C++ and use the scripts only to drive the behavior.
This seems inaccurate. You can certainly write C++ for Unity. People usually don't. Its a pain and C# performance is good. IL2CPP allows the compiler to optimize across game and engine code so its rare to write C++ plugins. Unreal also supports generating C++ from blueprints.
But saying 'oh you shouldn't use the nice language anyway' is just making excuses. Obviously they're meant to be used to call engine code.
It's such a bizarro world after a bunch of UE discussions to suddenly see people dismiss scripting concerns with "well just write that code in C++. Blueprints is slow". I'm usually the one saying that, but that's as a professional developer who needs to optimize all that stuff (and TBH the blueprint code tends to have some bad performance choices even before discussing the BP perf loss).
Hearing people dismiss the performance of something as basic as a raycast with "well just code in C++", while many people (including this founder) say that Godot focuses on simplicity sounds counter-intuitive. So is GDScript a lie for anything slightly intensive (and again, raycast. I'm using "intense" in the loosest of words) and I should simply make my whole game an engine module? But I keep hearing that "I should just try GDScript it's really easy and you come around to it!"
What i wrote wasn't making your whole game an engine module (i.e. writing everything in C++) but writing your intensive code in C++ and using scripting (be it blueprints, GDScript or whatever) to drive that intensive code.
There is nothing counterintutive in that, it is right in the name of scripting languages: they're meant to script behavior.
And the dismissal isn't about having a raycast being slow, but about using too many raycast queries in script to do something reusable that should be in native code in the first place. If your scripting language ends up in your performance profile chances are you are using it wrong.
The occasional raycast query in scripts to make a decision is fine, doing thousands of individual raycast queries from scripts is not - if nothing else, make an API that accepts multiple raycast queries at once, performs it in C++ in a single call (so you only get the scripting overhead for that single call) and gives the result back.
But IMO if, as mentioned in the article, you are going to make a controller that is to be used by multiple entities in the game, then you should make it in C++ - potentially with script hooks to customize the behavior, if needed.
What i wrote isn't that you can't write C++ in Unity, what i wrote was that you do not have the C++ source for Unity that would help you address performance issues. Since you mentioned UE blueprints, i have worked with UE and faced the need for better performance: being able to have (and modify) the C++ source (including the blueprint VM and codegen) code was something that helped and at the same time being able to turn blueprints to C++ wasn't a panacea nor the performance was anything close to what you'd get with writing the code in proper C++ in the first place (which is what we ended up doing for some parts).
Tight loops mean:develope one specialized function call which gets a field of data and works on it.. Resurfacing after the job is done.
You may even invert direction, handing over a pure script language function (no context) + the data, so the c++ engine may crunch the data at least in parallel small script vms without stack, similar to a shader.
I think part of the problem is that using GDExtension is like a two-way FFI. You can call (C++) extension functions from GDScript, but the same interface and overhead are used to call (lib) Godot functions from the (C++) extension. AFAIK it's not like there's a <godot_impl.h> with engine functions that the compiler could inline.
Here's a good example (look, there I am!), although it's a bit old and actually led to perf improvement:
It seems weird to extrapolate where Godot will live in the game development ecosystem from its current performance characteristics for certain operations. It's like trying out Windows 95 and saying "Microsoft isn't going to dominate the PC world because Windows 95 crashes a lot!" Maybe.. but these sorts of technical minutae are not the things that determine winners as far as I can tell.
“Godot is not the new Unity” is a present tense statement, issued at a time when many studios are considering a hasty and impromptu transition from Unity -- they are looking for a suitable equivalent now, not many years into the future. It's a sensible question about today and the very near future.
I think this type of discussion can help the design team behind Godot to improve their practices and implementation, in the end it would be very healthy for the gamedev community to have a reliable and performance open-source engine as the "standard" for students, indies and AA projects alike.
Godot is better than Unity on many sides, but the internal architecture is coming from a place where they relied too much on naive and inefficient OOP constructs, those can be very hard to optimize later.
Performance should not be treated as a second class citizen when creating an engine, there are always solutions but it can be very time consuming to find workarounds to palliate design issues with the engine, it can also be a real motivation killer for a small team when they discover the framerate of their game on older/smaller devices...
"Godot is/is not the new Unity" is a pretty loaded statement, and would mean different things to different folks.
This particular discussion focuses on the performance gap between the two engines looking specifically at how raycasts are implemented, and the larger implications from that analysis.
Great response, I downloaded Godot because I was looking for a lightweight engine that doesn't take two minutes to load. This seems to explain the reason for the performance, I'm glad its one of their focus
>Additionally, modern processors all have at minimum 64 bit buses, so exposing anything other than 64 bit scalar types makes no sense.
Yeah but you have a 32 bit data type and a packed 32 bit array, so why not have the same for 16 bit? Not just that, there are also SIMD operations that work better with 16 bit numbers.
>Additionally, modern processors all have at minimum 64 bit buses, so exposing anything other than 64 bit scalar types makes no sense.
I believe the issue was less with the sizes of items being passed in and more with the API conforming to work with GDScript first and formost. Returning a dictionary for an operation that has a few float64's feels overkill and doesn't make sense even with an explanation of the available datatypes.
>Only a pathological use case is shown, the rest of the API is fine.
I wouldn't call raycasting in a full blown engine "pathological". Especially one that touts 3D
Secondly, that doesn't inspire confidence. "Don't mind the room on fire, the rest of the house is fine!". The onus is on the engine to prove that, and numbers prevail over words. So far only one part of the conversation has shown that.
Even in the next sentence it sounds like they focus on a simple API over performance, and that doesn't fill me with confidence. If Godot isn't focusing on 3D, that is fine but there's so much noise trying to to say otherwise
> Eventually, C# will be moved to the universal extension system and this will allow the unifying of the default and .net editors, it is just not the case yet, but its top in the list of priorities
I hope so, but there seems to be a trend of various "top priorities" from Godot that have trouble crossing the finish line. That's a reocurring issue even in this response alone: I'm not convinced that performance is a top priority for Godot. And that confidence means everything if the "BDFL" controls what gets into the project proper.
>The problem is that, at the C++ level, this function takes a struct pointer for performance. But at the language binding API this is difficult to expose properly. This is very old code (dating to the opensourcing of Godot) and a Dictionary was hacked-in to use temporarily until something better is found
Yup... so 10 years later that hack stays in and modern programmers come cross it.
This isn't even a critique, that's simply the nature of legacy code. Unreal has an entire part of a forced namimg scheme (the compiler won't let you run the game without conforming) that can only be explained as "well we wanted to do this in the 90's but we slowly took it out sp it's not relevant today". But if it took 10 years for someone to do more than a few dozen raycasts a frame, it says more about the battletesting than any deep dive. It goes back to my confidence above.
>, you need to create a C# version of a C++ instance as an adapter... Why is it troublesome? because C# has a garbage collector and C++ does not.
slight nitpick: while garbage collection is annoying, you technically do have a built in way to disable it in certain regions, as well as the option in later versions to have unmanaged blocks of code. I'm not saying this is easy to do, but it is something that developers much smarter than me in c# have gotten around. I know c# bindings was a relatively recent endeavor so I'm not going to give it too much flak
> Godot containers don't work like STL containers. Because they are used mainly to pass data around, they are allocated once and then kept via reference counting.
1) reference counting implies some sort of automated memory free-ing scheme. 2) That doesn't necessarily address potential issues of inefficiently allocating memory and keeping it contiguous. But I won't talk much on that because I'd need to first read more on the engine's memory allocating schemes first.
> Godot uses far more optimized containers that are not directly exposed to the binder API.
Okay, but why? Someone wanting to use C# or c++ or whatever script extension that isn't GDScript wants those optimized containers. Does it go back to the earlier quote of "it's difficult to get right and no one wanted it"?
>As a result, we created a special path for GDScript to call more efficiently.
okay, and the link is... an open issue on Github made 2 months ago, with no additional comments or discussions. Simply a request from a code owner.
I don't know if this conversation is simply happening in IRC/chat, but it's unusual given how much other activity I have seen in other PR's/proposals (recent and from years prior). Was this the best reassurance that they are addressing performance?
---------
I don't mean to sound like a downer, but I feel the article is overall missing the forest for the trees. I've read about several different kinds of devs from years prior talk about how they passed on Godot because they hit hitch after hitch once they were doing something slightly advanced. a dismissal of "this is a pathological use case" sounds fine in a vacuum, but it sounds like this has been a long standing issue, and priorities simply weren't on smoothing out such hitches.
I'm not saying they should have listened to those devs, but I think the most frustrating thing is that I don't know what or who Godot wants to service. So far it sounds like they want to have all the cake, but currently are also low-key fine being a hobbyist 2D engine that can maybe do some simple 3D stuff. Which again, is fine. But that's not what it sounds like Godot is selling. It unfortunately reminds me a lot of Unity, both on the outside (yeah, having 2 unsupported netcode solutions with a 3rd in pre-alpha isn't a good look) and within the company itself. I'll quote some part of a post from the creator of Rimworld, who had similar evaluation and conclusions over 5 years ago:
>There's obviously a tremendous amount of technical talent going into Godot, but from what I can tell there's no strategic thought about market positioning or success pathways or goal pillars at all. It basically comes down to "make a good game engine", with all the lack of boundaries and lack of focus that implies.
>My initial thought: Be best at one valuable thing first, then expand out from there into adjacent domains, using the momentum accrued from the initial success. (e.g. If you want to build a restaurant empire, you start with one restaurant to dominate one neighborhood and then expand from there - you don't try to build 100 restaurants at once).
Raycasts are the most commonly used spatial queries in a 3d game. Hopefully this discussion will lead towards this issue being resolved.
I actually found Sam Pruden's complaint a bit odd since it sounds like he's developing a 2d game. If you're spamming 1000s of raycasts per frame for your 2d game, there's probably something else going on...