I quite literally just tried this on my own. We’re live tracking a dancer, and wanted hundreds of raycasts shooting out to interact with the environment to be shown on an LED wall. Thank you for your impeccable timing
I can only say one thing, when my first game comes out, you will be one of the biggest reason for my success.Your courses and topic selection is absolutely amazing.
@@git-amend dude im not even slightly kidding. you did all the PC stuff, and then the playables and the burst stuff. it keeps getting harder and harder to skip trying stuff out. ...i always watch but it takes a time investment to retain some of this stuff. the last stretch of videos i have not actually spun up projects to learn. cause i need to focus on my game. im going on a vacation this week. Im installing unity 6 RN. im gonna go through the last few videos one night at a time during vacation while the fam is asleep!
I keep looking forward to Sundays because of these videos. Always something new to learn. Even if I know the topic you are covering, your take on it always adds something to my knowledge. Question. With you covering jobs and burst will you be doing something with ECS (DOTS) as well? How about generating a mesh from base vertices and triangles using jobs and burst?
Awesome, thank you! Yes, there have been many requests for DOTS and we'll get there. That's a great idea for a video, I'm going to write that down. Cheers!
Thanks, enjoyed the tutorial...I just watched it as a video so far but will code it once I get to a pc.. did I miss something? I'm trying to work out why you used the max-distance squared for the bullet?
Using distance squared (sqrMagnitude) avoids the computationally expensive square root operation required by `Vector3.Distance`, making it more efficient for distance comparisons in performance-critical code.
In terms of raw performance, the job-based approach can handle many more raycasts per frame without bottlenecking the CPU because it allows you to run multiple raycasts/spherecasts in parallel, while traditional raycasting is limited to the processing power of a single thread. It's difficult to give specific numbers, because all projects are different. If you don't need many raycasts every frame, then just stick with normal raycasts, but I think in an FPS game it will have a good payoff.
your videos are quickly becomes my favorites, but i'm wondering what makes the icon left of you code lines and what do they mean i see fire symbol and unity logo and other?
I'm glad you're enjoying the videos! The icons you see next to the code lines in Rider are called gutter icons. Fire means 'Frequently called code' and the Unity icon has several different meanings, but usually it means something that is exposed to the Unity editor. www.jetbrains.com/help/rider/Settings_Gutter_Icons.html
and I have a some question. After studying your video, I understand that it involves putting various pieces of information into a NativeArray and then using it. Is my understanding correct? If so, when I follow such a Data-Oriented Design (DOD) approach, can I use NativeArray by placing data into it? I apologize for my lack of understanding
While NativeArray is not inherently Data-Oriented Design (DOD), it is a tool that supports DOD principles by allowing for efficient memory management and data access. DOD focuses on organizing and processing data in ways that minimize cache misses and optimize CPU performance, and NativeArray helps achieve this by storing data contiguously in memory. When used within a DOD approach, NativeArray enables better performance, especially in parallelized systems like Unity's Job System.
@@git-amend I’m sorry for always bothering you with questions due to my lack of understanding. I always enjoy watching your content. As you know, I’m a relatively new Unity player(2years), and I’m trying my best to clone code from all of your projects. Thank you as always. I’m learning a lot.
I think it will really depend on the project. It think it will scale well for most projects, especially if you can cache the different arrays, which would require a little bit of refactoring. I would prefer this kind of system when I want to know precise details about collisions, and it could be used for other purposes as well such as an AI Sensor. On the other hand, a Particle system is low cost and great for visual effects where you need less info about what they collide with.
@@git-amendI like the shaders used in this video, but if it's alright with you, I would love it if you could share the shaders you create. I can make basic shaders too, but you are always on a higher level.
The () => syntax you see in the code is called a lambda expression in C#. It’s a way to define an inline function (anonymous method) without explicitly declaring it. It's a more concise and readable way to define small, reusable functions.
Amazing Tutorial. One thing i would suggest is to make the font size bigger as you record your videos. Because it might be difficult for some people to see the code...
First, good video, goes over things well. However, correct me if Im wrong, but if you were raycasting the bullets against the volumes, you wouldnt need to substep the bullets. Projectiles are often actually raycasted since they do move fast, and the raycast is from last_frame_pos to this_frame_pos, and thus doesnt need a substep. (I prefer sweep casting of sphere (ie, capsules/lozenges), but its functionally similar) Im not a big Unity dev, but it should have (hopefully batch) raycast options, which might end up faster than your substepping (depending on quite a few things). Substepping the point projectiles could be faster, so if I was looking at it, Id keep both versions around.
In Unity, Raycasting works by testing against intersections, not against the full volume of a collider, and on top of that Raycasts will not detect colliders for which the Raycast origin is inside the Collider which is why 'tunnelling' is a common issue in Unity.
Ok, so below is my question and (hopefully) understanding of the issue. Also if this _is_ the issue, that.. rough, but at least understandable. By "ray" its really an origin, direction, and max length, so its technically a line segment. Ill be using ray below as is common with this. Unless you mean this (forgive the bad text art below): Key: [ ] == the collider |----> == the ray |---> [ ] == Clear miss |----[---> ] == hit |--[------]---> == this should be a hit, but is it a miss in Unity? If so, thats strange, but also if so, I now understand better. (description of the above (Third is the real question). First one is just no intersection, with the ray outside completey. Second is an intersection with a side, with the origin of the ray outside, and the end of the ray inside. These are for example. Third is start of ray is outside, _and_ end of ray is outside, but the ray itself intersects the collider. Im guessing third is the one that is broken on Unity?)
Nice tutorial. I was wondering why the sub steps help with detection? It doesn't make sense to me that ray casts would fail if the object we're colliding with is not moving. Surely there must be something else wrong in the logic. Is this a result of the frame loop not aligning with the jobs? so some frames are being missed by the jobs. Would it not be better to solve the issue by casting a ray from the bullets last checked position to its current position ? This should also allow for more complex trajectories.
You're correct that casting a ray from the bullet's last known position to its current position is often a solid approach to stop tunneling and ensure collisions are caught, especially with fast-moving objects. If you don't care if your object passes through or collides with the obstacle, then that can be a useful strategy. As for your other questions about the behavior of the Physics engine, I don't have the answers to that, but "bullet through paper" has long been a Unity issue.
Just curious if this is actually more efficient than just putting a box or sphere collider on each bullet and letting the default physics do the collision detection?
Detecting ray intersections in multithreaded batches of native memory is much cheaper than determining if entire colliders intersect one by one, and depending on your project you can make it even more efficient than the video by streamlining your memory allocations.
Hey! Instead of a fixed raycast length, why not just have the raycast be equal to the distance it travels during the frame it moves? It works for me and now my projectiles can have just about any speed without worrying about passing through objects. edit: you can actually just do the collision check BEFORE the movement
You can adapt this approach for enemy AI cover detection by using spherecasts or raycasts to check for obstacles between the AI and potential cover points. By casting in multiple directions from the enemy's position, you can determine if a cover object is blocking line-of-sight to the player. This technique allows the AI to evaluate which positions provide the best cover from incoming threats.
@@git-amend Like for potential cover I shoot ray from the cover to player which ever ray doesn't hit the player we add that position to the list and from the list we check the closest cover distance from enemy and assign it as a cover like this am I right
@@git-amend but this approach work with manually setted cover position in level but there is any way to find cover without any manually set the cover position in level
There shouldnt be a need for sub-stepping here. In your job(s), move each projectile to the desired position. Then, raycast from the old position to the newest position. If hit, remove the projectile. That guarantees no tunnelling.
That sounds promising, but it's just the inverse of the move/raycast operations as they exist in the video. Casting the ray before or after the move does not change the fact that it can potentially miss. It's the same ray, just cast at a different time.
@@git-amendSub-stepping is not necessary here, and doesn't completely solve the problem. The "tunnelling" you're getting on that closest stationary boxes is caused by the fact that you're using the projectile's position after it has moved as the origin of the raycast. This skips the raycast for the first "step" of the projectile's path. In your scene that puts some of the projectiles inside the box by the time the first raycast is performed. Adding sub-stepping only reduces the distance from the bullet's spawn point at which the problem occurs. Starting the raycast at the previous position of the projectile would solve that problem more completely than substepping, and without the added performance cost. It'd also be more appropriate to use the distance the projectile travelled that frame as the distance for the raycast rather than a constant value. If the projectile's velocity was sufficiently high so that its per-frame translation exceeded that constant it could also introduce missed intersections, and if the fixed distance were much higher than the distance travelled it'd show the bullet disappearing before reaching the hit target.
@@cgaudino Implementing those suggestions, which I have already tried, does not completely solve that issue. The first rays are not being cast from inside the closest box either way, and raycasts can still occasionally miss any boxes at any range, even if the ray is drawn from the previous position with a much longer distance.
@git-amend Hi, I am having issues trying to get on your discord server it says all the links are invalid. I suspect a problem with the thing between my keyboard and chair but how do I join?
That's hard to say, but the Discord is alive and well. The last time someone couldn't join was because they had reached their max limit of servers they could join.
Happy Sunday! Hope this video gives you some ideas for optimizing your game, no matter how many bullets you are firing! 👍
I quite literally just tried this on my own. We’re live tracking a dancer, and wanted hundreds of raycasts shooting out to interact with the environment to be shown on an LED wall. Thank you for your impeccable timing
Awesome! That sounds very interesting!
I can only say one thing, when my first game comes out, you will be one of the biggest reason for my success.Your courses and topic selection is absolutely amazing.
Great to hear! Thanks!
I hope you don't stop making these videos. You're the only one i found that explains advance stuffs like this
Thank you!
everytime im stucking in anything, git-amend make a video about it 🤯
Hahah! Nice!
I swear man. Everytime
Such a good tutorial, can't believe it only has 532 thumbs up, 5 days after release. Thanks for it 🙂
Glad you like it!
very cool. its videos like this that will cost me an extra month on my current project cause i want to play with the ideas in them!
Haha! Don't get too distracted!
@@git-amend dude im not even slightly kidding. you did all the PC stuff, and then the playables and the burst stuff. it keeps getting harder and harder to skip trying stuff out. ...i always watch but it takes a time investment to retain some of this stuff. the last stretch of videos i have not actually spun up projects to learn. cause i need to focus on my game.
im going on a vacation this week. Im installing unity 6 RN. im gonna go through the last few videos one night at a time during vacation while the fam is asleep!
Amazing, I was looking into this yesterday and didn't make much performance improvement. This is perfect. Thanks.
You're welcome!
Another great video. I still haven't started working with jobs, but this makes me want to do some premature optimization now 😀
Haha! Awesome!
Thanks hit-amend!
No, thank you!
I keep looking forward to Sundays because of these videos. Always something new to learn. Even if I know the topic you are covering, your take on it always adds something to my knowledge.
Question. With you covering jobs and burst will you be doing something with ECS (DOTS) as well? How about generating a mesh from base vertices and triangles using jobs and burst?
Awesome, thank you! Yes, there have been many requests for DOTS and we'll get there. That's a great idea for a video, I'm going to write that down. Cheers!
Please continue making videos! They are really good.
I surely will! Thank you!
If this is what being a senior C# dev looks like... I gotta long way to go.
One day at a time... there is always more to learn.
Another great lesson!
Glad you liked it!
Thanks, enjoyed the tutorial...I just watched it as a video so far but will code it once I get to a pc.. did I miss something? I'm trying to work out why you used the max-distance squared for the bullet?
Using distance squared (sqrMagnitude) avoids the computationally expensive square root operation required by `Vector3.Distance`, making it more efficient for distance comparisons in performance-critical code.
@@git-amend ..gotcha , cheers !
Very nice! Thanks!
You're welcome!
This gives me a few ideas about stuff. Great!
Nice, glad to hear that!
Thanks, very interesting method, try to use something like that in my FPS game))
Awseome! Glad to hear that!
@@git-amend how much that method better than usual raycast? I mean performance and physics calculation.
In terms of raw performance, the job-based approach can handle many more raycasts per frame without bottlenecking the CPU because it allows you to run multiple raycasts/spherecasts in parallel, while traditional raycasting is limited to the processing power of a single thread. It's difficult to give specific numbers, because all projects are different. If you don't need many raycasts every frame, then just stick with normal raycasts, but I think in an FPS game it will have a good payoff.
your videos are quickly becomes my favorites, but i'm wondering what makes the icon left of you code lines and what do they mean
i see fire symbol and unity logo and other?
I'm glad you're enjoying the videos! The icons you see next to the code lines in Rider are called gutter icons. Fire means 'Frequently called code' and the Unity icon has several different meanings, but usually it means something that is exposed to the Unity editor.
www.jetbrains.com/help/rider/Settings_Gutter_Icons.html
and I have a some question.
After studying your video, I understand that it involves putting various pieces of information into a NativeArray and then using it. Is my understanding correct?
If so, when I follow such a Data-Oriented Design (DOD) approach, can I use NativeArray by placing data into it?
I apologize for my lack of understanding
While NativeArray is not inherently Data-Oriented Design (DOD), it is a tool that supports DOD principles by allowing for efficient memory management and data access. DOD focuses on organizing and processing data in ways that minimize cache misses and optimize CPU performance, and NativeArray helps achieve this by storing data contiguously in memory. When used within a DOD approach, NativeArray enables better performance, especially in parallelized systems like Unity's Job System.
@@git-amend I’m sorry for always bothering you with questions due to my lack of understanding. I always enjoy watching your content. As you know, I’m a relatively new Unity player(2years), and I’m trying my best to clone code from all of your projects.
Thank you as always. I’m learning a lot.
I wonder how well this will scale up or would using the particle system would be better?
I think it will really depend on the project. It think it will scale well for most projects, especially if you can cache the different arrays, which would require a little bit of refactoring. I would prefer this kind of system when I want to know precise details about collisions, and it could be used for other purposes as well such as an AI Sensor. On the other hand, a Particle system is low cost and great for visual effects where you need less info about what they collide with.
Thanks for the info!
Additionally, could you share some shader you made later? That's great.
Do you mean a shader from this video, or just shaders in general?
@@git-amendI like the shaders used in this video, but if it's alright with you, I would love it if you could share the shaders you create. I can make basic shaders too, but you are always on a higher level.
thanks
You're welcome! Thanks for the super!!
What is this () =>? I don't get why you use it
The () => syntax you see in the code is called a lambda expression in C#. It’s a way to define an inline function (anonymous method) without explicitly declaring it. It's a more concise and readable way to define small, reusable functions.
Nice!
forming a list to release objects at the end of the frame is actually such a Giga Chad move.
Thank you! Cheers!
Amazing Tutorial.
One thing i would suggest is to make the font size bigger as you record your videos. Because it might be difficult for some people to see the code...
First, good video, goes over things well.
However, correct me if Im wrong, but if you were raycasting the bullets against the volumes, you wouldnt need to substep the bullets.
Projectiles are often actually raycasted since they do move fast, and the raycast is from last_frame_pos to this_frame_pos, and thus doesnt need a substep. (I prefer sweep casting of sphere (ie, capsules/lozenges), but its functionally similar)
Im not a big Unity dev, but it should have (hopefully batch) raycast options, which might end up faster than your substepping (depending on quite a few things). Substepping the point projectiles could be faster, so if I was looking at it, Id keep both versions around.
In Unity, Raycasting works by testing against intersections, not against the full volume of a collider, and on top of that Raycasts will not detect colliders for which the Raycast origin is inside the Collider which is why 'tunnelling' is a common issue in Unity.
Ok, so below is my question and (hopefully) understanding of the issue. Also if this _is_ the issue, that.. rough, but at least understandable.
By "ray" its really an origin, direction, and max length, so its technically a line segment. Ill be using ray below as is common with this.
Unless you mean this (forgive the bad text art below):
Key:
[ ] == the collider
|----> == the ray
|---> [ ] == Clear miss
|----[---> ] == hit
|--[------]---> == this should be a hit, but is it a miss in Unity? If so, thats strange, but also if so, I now understand better.
(description of the above (Third is the real question). First one is just no intersection, with the ray outside completey. Second is an intersection with a side, with the origin of the ray outside, and the end of the ray inside. These are for example.
Third is start of ray is outside, _and_ end of ray is outside, but the ray itself intersects the collider.
Im guessing third is the one that is broken on Unity?)
Can you make a video about optimization using lua?
That sounds like an interesting idea! What kinds of bottlenecks are you facing with lua?
amazing
Thank you! Cheers!
How can you this good?
Thank you for the kind words!
Nice tutorial.
I was wondering why the sub steps help with detection?
It doesn't make sense to me that ray casts would fail if the object we're colliding with is not moving. Surely there must be something else wrong in the logic.
Is this a result of the frame loop not aligning with the jobs? so some frames are being missed by the jobs.
Would it not be better to solve the issue by casting a ray from the bullets last checked position to its current position ?
This should also allow for more complex trajectories.
You're correct that casting a ray from the bullet's last known position to its current position is often a solid approach to stop tunneling and ensure collisions are caught, especially with fast-moving objects. If you don't care if your object passes through or collides with the obstacle, then that can be a useful strategy. As for your other questions about the behavior of the Physics engine, I don't have the answers to that, but "bullet through paper" has long been a Unity issue.
Just curious if this is actually more efficient than just putting a box or sphere collider on each bullet and letting the default physics do the collision detection?
Detecting ray intersections in multithreaded batches of native memory is much cheaper than determining if entire colliders intersect one by one, and depending on your project you can make it even more efficient than the video by streamlining your memory allocations.
Hey! Instead of a fixed raycast length, why not just have the raycast be equal to the distance it travels during the frame it moves? It works for me and now my projectiles can have just about any speed without worrying about passing through objects.
edit:
you can actually just do the collision check BEFORE the movement
how can i use it to find cover for enemy ai
You can adapt this approach for enemy AI cover detection by using spherecasts or raycasts to check for obstacles between the AI and potential cover points. By casting in multiple directions from the enemy's position, you can determine if a cover object is blocking line-of-sight to the player. This technique allows the AI to evaluate which positions provide the best cover from incoming threats.
@@git-amend Like for potential cover I shoot ray from the cover to player which ever ray doesn't hit the player we add that position to the list and from the list we check the closest cover distance from enemy and assign it as a cover like this am I right
@@brutalgamer1507 Yes, that sounds like an approach that could work. Or you could do the inverse and shoot rays from the player and get the hits.
@@git-amend but this approach work with manually setted cover position in level but there is any way to find cover without any manually set the cover position in level
@@git-amend and 1 more question
I want to make realistic Spider-Man swinging like in spiderman PS4 but how should I use raycast to make this happened
I would like to see a cpmparison to an implementation without the job. It looks like the same data is copied twice.
By all means, I encourage you to do so and use the profiler to see what is happening with (and without) the Jobs.
There shouldnt be a need for sub-stepping here. In your job(s), move each projectile to the desired position. Then, raycast from the old position to the newest position. If hit, remove the projectile. That guarantees no tunnelling.
That sounds promising, but it's just the inverse of the move/raycast operations as they exist in the video. Casting the ray before or after the move does not change the fact that it can potentially miss. It's the same ray, just cast at a different time.
agreed. also can raycast and then move to hit point or to frame distance.
@@git-amendSub-stepping is not necessary here, and doesn't completely solve the problem. The "tunnelling" you're getting on that closest stationary boxes is caused by the fact that you're using the projectile's position after it has moved as the origin of the raycast. This skips the raycast for the first "step" of the projectile's path. In your scene that puts some of the projectiles inside the box by the time the first raycast is performed. Adding sub-stepping only reduces the distance from the bullet's spawn point at which the problem occurs. Starting the raycast at the previous position of the projectile would solve that problem more completely than substepping, and without the added performance cost.
It'd also be more appropriate to use the distance the projectile travelled that frame as the distance for the raycast rather than a constant value. If the projectile's velocity was sufficiently high so that its per-frame translation exceeded that constant it could also introduce missed intersections, and if the fixed distance were much higher than the distance travelled it'd show the bullet disappearing before reaching the hit target.
@@cgaudino Implementing those suggestions, which I have already tried, does not completely solve that issue. The first rays are not being cast from inside the closest box either way, and raycasts can still occasionally miss any boxes at any range, even if the ray is drawn from the previous position with a much longer distance.
@git-amend Hi, I am having issues trying to get on your discord server it says all the links are invalid. I suspect a problem with the thing between my keyboard and chair but how do I join?
That's hard to say, but the Discord is alive and well. The last time someone couldn't join was because they had reached their max limit of servers they could join.