Master Simulations Using Geometry Nodes in Blender | Yassine Larayedh | Skillshare

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Master Simulations Using Geometry Nodes in Blender

teacher avatar Yassine Larayedh, VFX Artist

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Trailer

      1:51

    • 2.

      Repeating Zones

      1:46

    • 3.

      Simulation Zones

      2:30

    • 4.

      What is a Simulation

      1:04

    • 5.

      What is Velocity

      1:07

    • 6.

      What is Acceleration

      3:27

    • 7.

      What is an Attribute

      5:05

    • 8.

      The Acceleration Attribute

      8:38

    • 9.

      The Problem of Delta-t

      8:13

    • 10.

      Adding Constraints Pt.1

      5:08

    • 11.

      Adding Constraints Pt.2

      6:51

    • 12.

      Radius

      11:46

    • 13.

      Collision

      9:36

    • 14.

      Particle's Spawning

      4:31

    • 15.

      Friction

      3:51

    • 16.

      Final Overview

      7:56

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

195

Students

3

Projects

About This Class

In this course, you will learn how to create simulations using Geometry Nodes in Blender, by building your own physics engine.

This course is not just another “click-this-button” tutorial — It’s a deep dive into the world of simulations in Blender.

You won’t simply learn to think like an artist, but also like an engineer.

You will explore the technical side of creating realistic simulations.

We’ll cover essential physics concepts such as

  • Gravity
  • Velocity
  • Acceleration
  • Collision, and more

All of that will allow you to master simulations with a solid understanding of the science behind them.

By the end, you’ll be equipped to design complex, dynamic scenes with confidence.

Meet Your Teacher

Teacher Profile Image

Yassine Larayedh

VFX Artist

Teacher

I'm a VFX generalist, which is a fancy way of saying I do a bit of everything when it comes to visual effects.

I also have a bit of an obsession with the technical side of 3D--things like shading nodes and procedural stuff that make most people's eyes glaze over. But hey, it's fun for me!

I also happen to be pretty good at video editing. VFX and editing go hand-in-hand, so I figured I might as well get good at both.

When I'm not working on my own stuff, I actually enjoy teaching others how to do this kind of thing. I know, weird, right? But there's something really satisfying about breaking down complicated processes and seeing people have that "Aha!" moment. So, I started creating courses to share what I've learned.

Thanks for stopping by! Feel free to reach... See full profile

Level: Intermediate

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Trailer: Hey, take a look at this. This entire simulation was made just by using geometry nodes. And if you know just a little about nodes, you know how challenging creating such thing can be. The thing is, understanding nodes is hard and frustrating. But if you don't, you will miss on a crucial aspect of blender that will open a new world of possibilities for you. You probably also have seen some of those crazy node crees and wondered, how do you even start doing this? How do I know that? Because I was there. I suffered to find a lot of answers to my questions. By making this course, I'm aiming to make the process of learning simulations in geometry nodes easier and more fun for you. Throughout this course, you won't just learn how to create a physics simulation in blender. You will literally build your own physics engines inside of geometry nodes. You will learn about the real life forces that makes our world function the way it is. You will learn about velocity. You will learn about acceleration, collision, gravity, and how all of these forces interact with each other. And more. And you will learn all of that by creating the falling balls simulation. I know what some of you might be thinking right now. Hey, Yassine, why would I bother creating a falling balls simulation? I want to learn to create the good stuff like explosions or learn what every node does. Believe me, that would be a terrible approach. As simple as falling balls might seem like a concept. You will be surprised by the sheer amount of concepts you will learn by just creating the simulation. Which makes it the perfect exercise? Being good in simulations is being good in physics. And this course will bridge the gap between both of those and open that door for you. So if you're interested in learning simulations using geometry nodes in blender, this course is for you, and I can't wait to see you on the other side. Please. 2. Repeating Zones: Repeating zones. In the recent versions of Blender, a new concept was introduced, repeating zones. This is the default cube, delete it because you have to, and I'm going to add a sphere. If I open the geometry node editor, create a new tree, and let's call it, for example, simulation. If you go to add der utilities, you will have an option for repeating zones. As you can see, will have these two nodes with this box around them. Repeating zones are a way to tell blender to repeat certain operations multiple times. For example, What's coming out of this group input is my original geometry, which is the sphere. I also have my group output, which is the geometry I'll have by the end. I will plug the repeating zone between them like this. I'm also going to add another node called set position, which will allow me to change the position of an object. Shift A, set position, and I'm going to plug it in the repeating zone. Let's say I will move the sphere by 1 meter on the x axis, and that's exactly what I will have if I type one here. Now, let's say I want to repeat this operation ten times. Of course, it can be as easy as typing ten here, but imagine if you have a bigger node tree. In that situation, you will need to multiply every single value by ten, which can be a hassle. That's why in the first node of the repeat zone, you have this number labeled iterations, which represents how many times you want blender to compute what's inside the repeating zone. If I type ten here, blender will execute what's inside this repeating zone ten times. So, if we were to sum up what are repeating zones, repeating zones are a way to tell blender to repeat certain operations a certain number of time. It is that simple. Now, what about simulation zones? 3. Simulation Zones: Simulation zones. Simulation zones have a similar concept to the repeating zones. There are a way to execute certain operations multiple times. The only difference between simulation zones and repeating zones is that in the repeating zones, you specify how many times you want blender to compile those different operations. Meanwhile, in the simulation zones, Blender will compile all the operations at every frame. If I go to add simulation, I will have simulation zone. As you can see, it is pretty similar to the repeat zone, except that it doesn't have the iteration value. Has dilta time instead. Now if I duplicate the same operation of set position inside the simulation zone, plug the group input into the simulation input and the simulation output into the group output to see the final result, nothing will happen at first. But if I open the timeline and hit play, you will see the sphere moving. Now, Blender is executing the operations inside the simulation zones at every frame. At frame one, blender will move the sphere by 1 meter, and at frame ten, will move the sphere by 10 meters. It is that simple. Now it is important to note that blender is not running the simulation ten times when it is at frame ten. That will need a lot of computer resources. It's more like Blender is accumulating the results with each passing frame. For example, at frame one, Blender will move the cube by 1 meter by running the simulation once. At frame two, Blender will move the cube also by 1 meter based on the previous position. Blender runs the simulation only once, and the starting position of the simulation is the result of the previous frame. I hope that makes sense. In summary, you can think of simulation zones as a just a repeating zone where the number of iterations changes at every frame. In fact, if I add a node called scene time, this frame socket will give me the number of the frame am on. At frame one, it will output one, and at frame 37, it will output 37. If I go back to the repeating zone and I plug the frame into the iterations, that means that the number of iterations will follow the number of the frame am on. If I hit play, I will get the same result as the simulation zone. You can think of simulation zones as a repeating zone with the scene time plugged into the iterations. The difference now should be clear between repeating zones and simulation zones. Repeating zones are a way to repeat certain operations manually by specifying how many times you wanted to repeat. Meanwhile, simulation zones will do that automatically at every frame. Now, with all of that out of the way, now we can start talking about simulations. 4. What is a Simulation: What is a simulation? I found this good definition of what is a simulation. A simulation is a method for imitating a real world process over time. It evolves creating a model that represents key characteristics, behaviors, and functions of the process or system. As an example, if I have a ball and make it fall, A simulation will be a program that predict what will happen. I will give that program certain inputs like how big is the ball, how high is it from the floor, how heavy it is, how strong is the gravity pulling it down. And based on those inputs, the program will try and predict what will happen. So if we want to create a physical simulation in blender, we need to think of ways to recreate reality in blender. That means we need to think of the real life forces that allows our world to function the way it is. The key to that are two forces, velocity and acceleration, and we will explain both of them. Now we're starting to get into the fun part. In the next video, we will learn about velocity. 5. What is Velocity: What is velocity? Vlocity is a physical vector quantity that describes the rate at which an object changes its position. To put it simply, velocity is how fast something is moving. We commonly refer to it as speed. What I want you to keep in mind is that we can't think of velocity without considering the factor of time because velocity at the end of the day depends on the distance crossed within a certain period of time. We can't say the speed of the car is 100 kilometers or 100 miles. We need to specify per what unit of time are we talking? Is it 100 kilometers/hour per minute per second? There is a huge difference. In our small simulation, this sphere is moving at a rate of 1 meter per frame, and that's its velocity, 1 meter per frame. Or since my frame rate is 24, that means the sphere will move 24 meters/second. We can say that its velocity is 24 meters/second, or 14 40 meters/minute, or 86,400 meters/hour. You get the idea. So that's velocity. Now we need to talk about acceleration. 6. What is Acceleration: What is acceleration? Velocity is the rate of change in position across time? Acceleration is the rate of change in velocity or speed across time? A car is accelerating when its speed is increasing. Acceleration represents the changes in velocity. Same as velocity, we can talk about acceleration on its own without considering the factor of time. We can say this car is accelerating at a rate of 10 meters. We need to specify per what unit of time are we talking? Is it accelerating at a rate of 10 meters/second per minute per hour? That is a huge difference. In the small system we built in Blender, the sphere is moving at a rate of 1 meter per frame, and that's its velocity. But it is not accelerating nor accelerating, which means that the acceleration is zero. In real life, objects velocities increases and decreases with time because of different forces. So how can we program such things blender. Before I explain how to do that, I want to change the simulation a little bit. I'm going to delete the group input and instead, I'm going to add a point node. It is important to mention that a point in blender is just a data container that we can later replace with other objects. That's why we're using it because it offers a huge flexibility later. I'm going to change the simulation to become a falling point simulation by moving the 0.5 meters in the air, so that would be my starting position. Since I want the point to be falling, I need to update the set position node. Instead of moving on the x axis, I need to tell blender that we will be moving on the z axis. I'll reset the x axis to zero, and on the z axis, I'll write, for example, 0.1 meter. If I hit play, you will notice that the ball is moving up not down. It's because blender is moving the ball by 01 meters up. So if we wanted to move it down, we need to change it to -0.1 meters. Now, if I hit play, you will notice that the ball is falling slowly down. Now we can start thinking about how to implement acceleration in our system. To understand what we will be doing, we need to go back to the definition of acceleration. Acceleration is the change in speed of an object. A falling object will be accelerating, which means its velocity will gradually increase the more time it spends falling. In other words, we need to figure out a way to tell blender, Hey, blender, we want you to increase the velocity with each passing moment. As in, for example, at frame one, move this point by 01 meters down. At frame two, move this point by zero 15 meters down. It will be at minus 020 5 meters. At frame three, move this point by zero 2 meters down. It will be at -0.45 meters. The key to getting acceleration, to make the distance traveled with every frame bigger and bigger. Think about it. If the ball is moving the same distance every frame, you will have a constant speed. But when it accelerates or decelerates, that means that the distance crossed with every frame is either getting bigger or smaller. If the distance is bigger, that means it is accelerating, if the distance is getting smaller, it means it is accelerating. The solution to implement acceleration in our system is to figure out a way to tell blender to either increase or decrease this value with time. In order to do that, there is an important concept that you need to understand. Which is attributes. That's what we will be talking about in the next video. 7. What is an Attribute: What is an attribute? If you check the blender manual for what is an attribute, you will find the following definition. An attribute is a generic term to describe data stored per element in a geometry data block. Here's how I want you to think about it. Imagine a three D geometry. This geometry can be as simple as a point like in our example or any other three D object. Attributes are data attached to the three D object that defines certain characteristics of that three D object. For example, If I jump to my geometry nodes workspace, and from the spreadsheet, I will jump to point because the only geometry I have right now is the point. Here you will be able to see all the different attributes attached to this geometry. First of all, you have the index. In this case, it is zero. But if I increase the number of points, for example, to five, each point will have an index. The index number is an attribute. In the case of the index, the attribute is the number that refers to the index of each point. You have also the position attribute which define the location of that particular point. You have also the radius of that point. That's also another attribute. Attributes are like an ID card that defines the characteristics of an element in blender. That's why the best way to think of attributes, as I said, is them being a data block attached to the three D object, that defines certain characteristics of that three D object. Now, those are the attributes that come by default with the point. The nice thing is that Blender allows us to create our own attributes. If I go to add attributes, store named attribute, I will have this node that I'm going to plug right after the simulation input. The store named attribute node will allow me to create my own attributes. I can start by specifying the type. In our case, velocity and acceleration are both vectors. That's why I'm going to change the data type from float to vector. Next, I'm going to give this attribute a name. You can call it whatever makes sense for you, but to keep everything clear, I'm going to call it velocity. Now, if I go back to the spreadsheet, you will notice that we now have another attribute called velocity. If I select the store named attribute and hit empty mute it, notice how that property will disappear from the spreadsheet editor. I hope at least now you have an idea of what is an attribute. It is a data block attached to a three D object. But you might be wondering, how is this supposed to be useful? Well, Now that we have velocity as an attribute, we can start doing a bunch of cool operations with it like changing it with every passing frame. Because remember, that's our goal to make the velocity either increase or decrease with time, which will give us acceleration. In our current node tree, the velocity is constant. If we think of what's happening at every frame, blender will change the position of this point by the specified amount of the set position node. Also, as you can see, this offset socket is a vector, since it does have three values, and it does have the diamond purple socket. Technically, if we want to be more precise, this offset socket represents the rate of change at every frame, which we mentioned before, that is velocity. Something simple I can do is to add a node called vector and plug it into the offset. I didn't do anything fancy. I just replaced the offset with this vector. If I write -0.1 on the z axis of the vector node, Hit play, I will get the same exact result. This vector node right now is representing velocity. To go even further, I'm going to delete this vector node, and I'm going to add a node called named attribute, which will allow me to summon a certain attribute. The attribute I want to summon is a vector, and its name is velocity. This velocity attribute we're calling is the same exact attribute we created using the store named attribute node. What is the nature of this velocity attribute? It is a vector, which is the exact nature of the offset socket, so I can plug the named attribute into the offset socket. If I hit play, Nothing will happen because this velocity vector is basically all zeros. How do I know that? Because in the store named attribute, we didn't specify the values of this velocity vector. If I write -0.1 on the z axis and hit play, you will get the same exact thing we had before. Here's the logic of what's happening. We created a vector we called velocity, and it has the following values. Then in our node tree, we can summon or call the vector we created and use it in multiple places. So this named attribute node is looking for a vector called velocity, which is defined by this store named attribute node. It's like we created a vector, Now we're using it in multiple places in the note tree. In the future, if I want to change the velocity vector, all I need to do is to change the values in the store named attribute, and that change will ripple through the entire note tree because I will be using the named attribute node everywhere in my note tree. Now that we changed a little bit our note tree and created the velocity attribute, and the next video, we are going to create the acceleration attribute. 8. The Acceleration Attribute: Acceleration attribute. As I mentioned before, acceleration is the change in velocity. So if we want to implement acceleration in our system, we need to figure out a way to make the velocity change with time. We want to tell blender to increase the rate of change. In other words, we want to make the distance crossed by the point from frame to frame bigger. For example, at frame zero, the point is at 0.0. At frame one, nudge it by 01 meters down. It will be at minus 01 meters. Then nudge it by zero, 15 meters down, so it will be at minus 020 5 meters, and then nudge it by zero 2 meters down. So it will be at minus zero, 45 meters. By doing this, as you can see, the distance traveled by the point with every passing moment is increasing gradually, which means it is accelerating. So how can we program such thing in nodes in blender? Well, this is simple. So this is where we stopped last time. We have this store named attribute that is defining an attribute called velocity that does have these values, and we later use this velocity attribute or this velocity vector right here. We're calling it from this node, and we use it to update the position, and this is giving us a constant speed. What we want to do, as I said, is to make this velocity vector increase its values by time. Some of you might suggest that I can key frame this property right here and add a couple of key frames, and I will be able to animate this value with time. And this is actually a viable approach. What we want to do is to build a physics engine that can take care of everything. I will do something that will sound a little bit counter intuitive at first, but I will explain it. I'm going to go add named attribute. As you remember, this node will allow me to call or summon a certain attribute that I have created. In this case, I'm going to call a vector, which is velocity. It is the same exact vector This node is creating. It is the same attribute, and I'm going to plug it into the value. As I said, this might sound counter intuitive. So basically, this node is defining a property called velocity that does have this value. In this value, I'm plugging an attribute that is called velocity. It is literally the same attribute. It is like the meme of the guy pouring the water in himself while he's in the pool. You can probably guess the blender reads the note tree from left to right, so it will start with the points, then enter the simulation zone. Store named attribute, and for every node, it will start from the top to the bottom. At first, it will read vector point, then read the geometry, then this election, and then it will create a property called velocity or an attribute called velocity. For the value, I plugged the velocity, and whenever you plug an attribute into the node that is creating the attribute, blender will assume a value of zero. That's why now if I hit space bar to hit play, nothing will happen. The point will stay at the same place, because this connection I did right here, plugging the attribute velocity into the store named attribute defining it will lead me zero. So nothing will happen. But the really nice thing now, if I go add shift A and look for vector math, and I'm going to plug it right after the named attribute, Now Blender will take the velocity vector, which is in our situation a zero, we'll add to it a value that I will specify right here, and that will be my new velocity value or my new velocity vector that I will use later to update the position. If let's say, for example, I type -0.1. Now try to think of what will happen. At frame zero, of course, nothing will happen. I'm going to open my timeline, and to better organize my workspace, I'm going to collapse this to this, and I'm going to add another editor right here, and I'm going to change it to the three D viewport, and let's bring it down like this. This will give me more room here in my note try. I have here is at the timeline, and I can move right here in my three D viewport. And since we are working right now on only two dimensions, I'm going to hit one from the number pad to jump to the front view. So this will be my working space. I think this is better. Maybe even I'm going to drag this a little bit so I have more space in my note try. As I said, right now at frame zero, nothing will happen. The point is at the starting position of zero or actually 5 meters, but we assume it is zero. At frame one, Blender will take the velocity vector, which does have the value of zero, will add to it -0.1, and that will be my velocity vector that we later use to update the position. So now at frame one, blender will move this point by 01 meters down. Look, boom. So this is 01. At frame two, let's say blender will run the cycle again. But what is the value of this velocity node right now? Is it zero or is it minus 01? This is the important thing that you need to keep in mind, which is that this node right now will keep the value of the previous state. This node right now contain a velocity attribute that is not 000. It is actually 00 minus 01. Now when I will add to it minus 01, This new velocity vector that I will get from here will not be minus 01. It will be minus 02, and notice what will happen. Now the distance that is traveled at frame two is slightly bigger. In the third time for frame number three, what is the value of this one? It is the previous velocity value, which is minus 02. Now I will add to it minus 01, so I will have minus 03, and this will be my new velocity that I will use to change the position. So now the gap is getting bigger. I'm at frame three. At frame four, this velocity vector will not be zero. As I said, it will be minus 03, and when I add to it minus 01, it will be at -0.4, and that's what I will use to update the position. Boom. Now if I hit play, you will notice that the ball will fall slightly faster, the more time it spends falling. Let me zoom out a little bit to fully see what happens. And if I hit play, as you can see, now we're getting something that resemble a ball falling. The key to that is this small trick we did right here. We take the velocity of the previous state, add to it a certain value, and because it is a low blender every time it runs the simulation, we add minus 01 on the z axis to the previous state of the velocity vector. I hope that makes sense. Right now, this vector I'm adding right here, this vector is actually the acceleration vector. These values are the ones that defines how much you want blender to increase the speed with every passing moment. This is actually acceleration. Since I want also acceleration to be an attribute because I will be using it later, I'm going to add another node right now called store named attribute, shift A, store named attribute, and I'm going to store a vector that I will call acceleration that does have these values. And I'm going to use it right here, so look for named attribute. I'm going to look for a vector that I just created called acceleration. Where is acceleration? Okay? It's a vector called acceleration. And I'm going to plug it here. Nothing will happen because this acceleration is zero. How do I know that? Because in the node defining it, I didn't specify what value should this vector have. If I go back to frame number one, and if I hit play, nothing will happen because the acceleration is zero. I'm not adding anything. Nothing will change. That's why I'm going to type minus 01. Mm. And now, if I hit play, you will get the same exact animation or simulation we just had. So this store named attribute will define a vector called acceleration. And every time blender we run the simulation, we're adding this value to the rate of change. In other words, every frame or whenever blender runs the simulation. This is how much blender will increase the distance crossed by the point. Every time the distance will increase by minus 01 meters. I know it might be a little confusing because we're using minus, but always remember that the main reason we're using minus is because we are falling down. That's why we need the minus sign. So this is our current notary. I hope it makes sense. Now we have a falling point simulation, I guess. But actually, there is a small problem in this simulation that we need to fix in the next video. 9. The Problem of Delta-t: Problem of Delta T. Something I mentioned before is that simulations in blender are evaluated at every frame. This will cause a small issue. Our current frame rate is 24 frames per second. This means the blender will execute the simulation 24 times in 1 second. I'm going to jump back to the geometry nodes workspace, points. If I hit plate to cache the simulation and then go to frame 24, here's the location of the point. 00 -25. Now, let's say I want the final animation to be smoother. So I decided to bump the frame rate to 60 frames per second. After 1 second, how many times do you think Blender will execute the simulation? You guess at right, 60 times. If I hit plate to catch the simulation and go to frame 60, notice the location of the point. 00 -178. I know this might be confusing, so to really nail the point home, here's what happens in real life. Imagine you're throwing a ball from a high place. Let's say the ball will take 3 seconds until it touches the floor, and you have two cameras, one recording at 24 frames per second and the other at 60 frames per second. Throw the ball. In 1 second, the ball will be on this level. The important thing to notice is that both cameras will capture the ball at the same position. The only difference is that the 24 FPS camera recorded only 24 frames. In other words, it recorded the ball in 24 different positions. Meanwhile, the 60 FPS camera recorded 60 frames. In other words, it recorded the ball in 60 different positions. The timing is always the same. The only difference is the frame rate. What should happen in Blender is the following. After 1 second, point should be at the same position regardless of the frame rate. So how can we fix this problem? The best way to explain the solution is by doing some math. But I promise, it won't be that complicated. Something I mentioned before is that velocity is the rate of change in position in time. One way to translate that statement into a mathematical function is like the following. V, which is velocity equal Delta P over Delta T. I'd like you to think of the word Delta as the change. P stands for position and t for time. We say velocity is Delta P, the change in position. Over Dilta T, the change in time. Now, what about acceleration? As you remember, acceleration is the rate of change of velocity across time. One way also to write this as a formula is the following. Acceleration A equal, Delta V over delta t. We say acceleration is Dilta V, the change in velocity, over Dilta T, the change time. In our current node tree, Delta t is a variable that changes depending on the frame rate. If the frame rate is 24, then Delta t equals 1/24, and if the frame rate is 60, then Delta T equals 1/60. We want the timing of our simulation to be the same regardless of the frame rate. Based on the first equation, velocity equals Delta P over Delta T, can conclude that Delta P equal velocity multiplied by Delta T. Based on the second equation, A, acceleration equal Delta V over Dilta T? We can conclude that Delta V, the change in velocity equals the acceleration, multiplied by Delta T, the change in time. The math is really simple. All what we did now is to express both the change in position and the change in velocity in function of Delta T. This will make Blender consider the frame rate when running the simulation. How can we translate that logic into the node tree. This will be simple. Let's start first with the Delta P change in position equals the velocity multiplied by Delta T. What is the node responsible for changing the position of the point? It is the set position node, and this part of the equation is the one we need to compute and input into the offset socket. Right now it is just the velocity vector. Based on the equation, we need to multiply the velocity by Delta T. You have to do is to add a vector math node, change the operation to multiply, and multiply it by the Delta T, which you can get from the first node of the simulation zone. Also, you can set the operation of this vector math node to scale, and it will do the same exact thing. We use multiply when dealing with two vectors, but since the Delta time is one simple number, we can change it to scale. You can use this one whenever you're multiplying a vector by a single number. They're also called scalars in blender. Hence the name scale for the operation. Okay, so now we're making up for the change in position based on our Delta time, which is based on our frame rate. Now we need to do the same thing for the second operation. Delta V, the change in velocity equals the acceleration vector multiplied by Delta T. Where are we defining V, the change in velocity? Well, We're defining the change in velocity using this first store named attribute. The one responsible for creating the acceleration. Always remember, the values we're using for the acceleration vector are responsible for how much our velocity is increasing with every frame. So what I can do is to input a vector into the value of this store named attribute, and by default blender will keep the same values. The equation, Delta V equal acceleration multiplied by Delta T, what we will input into the value socket of the store named attribute defines the rate of change in velocity, which is equal to the acceleration, which is this vector node, and we need to multiply it by Delta T. All you need to do is to add a vector math node, change the operation to scale, and multiply it by Delta T, which you can get from the first node of the simulation zone as I mentioned before. That's how we can implement the logic of the equations I explained in the notary. As a result of that, our simulation now will adapt to the frame rate, and it will stay consistent regardless of the frame rate. To make sure that's the case, if I hit play, first of all, you will notice that the animation is too slow. Since our simulation now is based on real life timing, not on frame numbers, we need to start using real life values for these vectors. It is the value of gravity in real life. It is -9.8. Make sure to use that value for the acceleration vector because that's how objects accelerates when falling. So it is always nice to use the real life values because that means that our simulation will be more realistic. Now our current frame rate is 24 FPS. So let's run the simulation by hitting play. Go to frame 24, which means 1 second into the simulation, and see the position of the point. It is at 0.304. Now, let's change the frame rate to 60 FPS, run the simulation again and go to frame 60, which also means 1 second into the simulation because we just change the frame rate and read the position of that point, and it is at 0182. The values are close, but they are not the same. Why is that? Without getting into the nitty gritty details of why is that happening, all you need to do is that whenever you're doing these sort of simulations in Blender, there will always be some error. And that's due to the oiler integration method used in Blender. I can spend hours trying to explain what is the oiler integration methods and all the problems with it. But that will be too much to handle. So all you need to know is that there will always be a margin of error that we need to deal with when doing these sort of simulations in blender. Also, I need to mention that there are other ways to integrate other integration methods in blender using nodes, but we'll be tapping into the more advanced stuff of geometry nodes. And actually, Those are not even about geometry nodes as much about literally pure mathematics. And that's not the main topic of the course. That's why we'll sacrifice some stability and accept a big margin error for the sake of simplicity. And now that our simulation is frame rate independent, we need to make these balls basically bounce of the floor by introducing some constraints, which we'll do in the next video. 10. Adding Constraints Pt.1: Adding constraints Part one, the floor. Our point right now will keep falling forever basically. We need to figure out a way to tell blender, hey, blender, once the point reaches the floor, make it balance off of it. This will be a fun exercise. The first question that comes to mind is, when does the point reach the floor? The answer is simple. Once the position of the point is equal or below zero. Now, if I go back to the sentence, hey, blender. Once our point reaches the floor, we want it to balance off of it, we can change it to the following sentence. Hey, blender. Once the position of our point is equal or less than zero, we want to balance off the floor. Now comes the second part. How can we make it bounce off the floor? The easiest solution will be to reverse all the forces that are applied on our point or on our ball. Right now, our simulation is making the point fall down. So all we need to do is to tell blender that once the point hits the floor, reverse the simulation. In other words, reverse the velocity and position. To fully understand that, I want to explain the architecture of our simulation engine. We first define the acceleration. Tree used to define the velocity, which we use to update the position. It's a pretty systematic or algorithmic in a sense. It's a step by step process. Now we will tell blender, if the position of the point is less than zero, reverse the velocity and reverse the position of the point. This will lead to the point bouncing up. It's like we're building a mini engine that will kick in once the position of the point is less than zero. Let's translate all of these thoughts into nodes. The first step in building our mini engine is to know when will this engine kick in. I said that multiple times. When the position of the point is less than zero, I'll start by adding a position node. Will give us the position of the point, then I'll add a node called a separate x y z because we only need the position on the z axis, since it is the one responsible for defining the position of the point up and down. Add a compare node and set it to less than zero, and this is our condition. One way to read the logic of these nodes we created is the following. When the position on the z axis is less than zero, do something. Now we will build what should happen when this condition is true. This should be simple because all we need to do is to run the same engine we built just in reverse, which we can do easily by multiplying it by minus one. First, we need to reverse the velocity. The point used to go down, now it needs to go up. How can we update the velocity? Easy. Add a store named attribute, change the type to vector, and we need velocity. Whatever we will write here now will override the values we had previously for the velocity vector. I'll then add a named attribute. Vector velocity. This will give me the velocity value from the previous frame, and I will multiply it by minus one on the z axis and one on the x and y axis, since I don't want them to change because multiplying by one will always lead to the same result. And I will plug that into the value socket of the storm named attribute. Now we reverse the velocity vector. Let's move to updating the position, so the ball goes in the reverse direction. I'll add a set position node, add a position node, add a vector math, and multiply it by minus one on the z axis. And one on the x and y axis and plug that straight into the position, because we want to straight up change the position, not just the offset. And now, this is our mini engine responsible for reversing the simulation if the point goes below zero. But right now, Blender still doesn't know when to run the small engine because we need to plug our nodes defining the condition into the selection socket of the store named attribute and the set position. So now, both of these two operations of changing the velocity and changing the position, will only run once this condition is met. If I hit play now, notice what will happen. Our point is bouncing, and that's how we can introduce constraints to our simulation. The ball now will bounce forever, but in real life, it should lose energy slowly until it stops. The way around that will be to tell blender to decrease the velocity gradually. You can do that by increasing the velocity vector, so instead of multiplying it by minus one, which is a perfect reflection, you multiply it by -0.8, for example. Now the simulation will lose steam slowly whenever it touches the floor. Until it stops. The way we programmed friction right now only applies once this condition is met. Once the ball touches the floor. But in real life, the ball should actually lose speed gradually from the beginning of the simulation. A way around that is to add a vector meth node, set it to scale, and plug it right before the store named attribute defining the velocity and set the value to something like 0.98. Now the simulation will lose energy overall or at every frame. Why? Because as we know, blender compiles the simulation every frame. For our simulation, I'm going to delete the scale node, and I will program friction from the nodes responsible for the constraints in a future video. Now we build the constraint system for the floor. We also need to build some constraints for the side walls, and that's exactly what we will be doing in the next video. 11. Adding Constraints Pt.2: Adding constraints for two, the side walls. In the previous video, we created the floor constraint, which will allow the ball to bounce off the floor. In this video, we'll create a similar thing. We'll build the constraints for the side walls, right and left, front and back. Just so that all of us be on the same page, make sure to hit one from the number pad to jump to the front view. We will start by creating the constraints for the right wall. Let's say we want the ball to bounce off an imaginary wall that is 1 meter away. Round here. The concept is really similar to what we did for the floor. We need to figure out a way to tell blender that if the ball touches this imaginary wall, reverse the simulation. Or to use the analogy of the mini engine, we're going to create a small physics engine that will kick in if the ball touches the right wall. Let's start with the condition. This should be simple. The point touches the wall. If the position on the x axis is equal or more than one. Add position node to read the position of a particular point, I'll add next a separate xyz. All I care about is the x axis, that should be greater than one. Is my condition. Now we move on to what should happen if this condition is true. We want to reverse the simulation, so we reverse first velocity, and then the position. Instead of creating all of those nodes from scratch, I'll just copy the setup from the floor constraint and connect it like this. For the multiply of velocity, make sure to change the z axis back to one. Change the x axis to minus one, because now we're working on the x axis. I will do the same thing for the multiply of the position. I will change the z axis back to one and change the x axis to minus one, and also make sure to connect the condition to both the store named attribute and the set position. These operations will only kick in if this condition is met. Now, if I hit play, the ball will fall straight down. I want to push it slightly to the right. I'll go right after the points node, the first node of mine tree, and add the store named attribute. That is a vector, and I'll pick the velocity, and right, for example, two on the x axis. So now, the velocity vector will start at two, which means the point will be pushed slightly to the right, and that way we can test our wall constraint we just created. It's like we created an initial velocity for the point, so it won't start from zero. If I hit play, the point will touch the right wall, but it is acting weirdly. Somehow it jumps to the other side. Why is that? Well, if we focus on this position node, you will notice that we're multiplying it by minus one. So let's say hypothetically, the position of the point at a certain frame is at 0.9 on the x axis. The simulation will continue working normally because we didn't touch the one line. At the next frame, the position of the ball is at one, which means the condition is now met, which means blender will run these operations that tell it to reverse the simulation. So now the ball should also be here at 0.9 on the x axis. But since we're multiplying the position on the x axis by minus one, jumps to the other side to -0.9 on the x axis. The solution for this is simple. We need to bring this ball two units to the right, which we can do by adding a vector meth node, set it to add, and let's add two on the x axis. And now if I hit play, you will notice that the point bounces perfectly of the right wall, and this is our constraint for the right wall. Now we will create the constraint for the left wall. This should be simple. I'm going to duplicate the entire right wall constraint and connect it after it like so. The left wall is the minus one line. When does the ball touch the left wall? Or the minus one line, when the position is equal or less than minus one, I will change my condition to be when the position on the x axis is less than minus one. So this is my new condition. What should happen is we'll reverse the velocity by multiplying it by minus one on the x axis. So I will keep these nodes the way they are, and for the set position, we're multiplying it by minus one. We need to correct for that by adding two. In the case of the left wall, Since we're multiplying by minus one on the x axis, that means the ball will now jump to the right side, so we need to move it two units backward, which we can do easily by subtracting two. All you need to do is to change this vector math node from add to subtract. Now if I hit play, you will see how our point is bouncing of both the right and left wall, and that's exactly what we want. Now we created the constraint for the right and left wall. We will do the same exact thing just for the front and back wall. In our three D viewport, we're now looking at the front view, which means this is the right and left wall. If I hit three from the number pad, I will jump to the side view, which means now this is the front, This is the back. Another way to think of this earlier, we were working along the x axis. If I hit one from the number pad, you will see the red line which represents the x axis. Now if I hit three from the number pad, I will jump to the side view, and I will be working along the y axis now. Creating constraints for both of these will be really simple. I'll just duplicate the entire setup for both the right and left wall and change it from functioning based on the x axis to the y axis. I'll select both of these two clumps of nodes and hit D to duplicate them. I will connect them like this. Let's start with the right wall which is now the front wall. Change the value coming from the separate x y z to the y axis. It should be equal or greater than one. If this condition is met, we will do the following. Take the velocity and multiply it by minus one on the y axis now and change the x axis back to one. For the position, same thing, multiply it by minus one on the y axis and change the x axis back to one. And since we need to also account for the correction, we now need to add two on the y axis and write zero on the x axis. This is the constraint for the front wall. Now let's move on to the constraint for the back wall. I will do a similar thing. Change the value coming out of the separate x y z to the y axis. It should be equal or less than minus one. And if this condition is met, we will do the following. Take the velocity and multiply it by minus one on the y axis now and change the x axis back to one. For the position, Same thing, multiply it by minus one on the y axis and change the x axis back to one. And since we need to also account for the correction, we now need to subtract two on the y axis and write zero on the x axis. And this is how you build the constraint for both the front and back wall. Now, if I go back to the first store named attribute node that is giving us some initial velocity and give our point also some initial velocity on the y axis and hit play, you will see our point bouncing of the different walls. Okay, so this is how you can build some constraints for your simulation. In the next video, we are going to replace these points with some spheres basically or bowls, which will introduce a new set of challenges that we need to overcome. 12. Radius: Adding the radius. At this point, we're running our simulation based on points. As I mentioned before, points in blender are just data containers that we can later swap with other objects. What we want to do in this video is basically to replace those small points by sphere or any object. If I go to the end of my node tree and add a node called instance on points, I will plug it right before the group output node. This instance on points node will replace the point by an instance or a three D object we will pick. I want to replace these points by sphere. I'll add a U sphere. And I will plug it into the instance socket. And as you can see, our point is now replaced with the sphere. For the radius of this UV sphere, I wanted to inherit the radius of the points, which we can specify from the points node, the first node of the notary. One way around that is to add radius node and plug it into the scale of the instance on points node. And now, if I change the radius of the points, I will also be changing the radius of the instances or the spheres. Now, if I hit play, you will notice how our sphere is bouncing off the floor and side walls. But if you focus, you will notice a small problem. Or a big problem, depending on how you look at it. You will notice that when the sphere touches the floor, part of the sphere goes under the floor line. Why is that? Well, since we were dealing with points earlier, and I said they are just data containers, so they don't actually have a radius. Now that we replace those points with spheres which are actual three D geometry, and they have a radius, we need to account for that in our physics engine. In other words, we need to figure out a way to make our node tree aware of the radius, so it will consider it when running the simulation. Will be simple. I promise. Let's first start with the constraint for the floor. When does the sphere touches the floor. That should be easy to answer. When the position is less than the radius. Always remember that the position is evaluated from the center point of an object. When the position or the center of the three D object is less than the radius, that means that three D object is touching the floor. For the floor constraint, all I need to do is to add a radius node and plug it in the less than operation. Now it becomes if the position of the sphere is less than the radius, do the following operations. If I hit play, everything will run smoothly. Looks like the ball is bouncing of the floor. But if I change the radius of the point to something like 0.5 meters, for example, and hit play again to catch the simulation, you will see something weird. Now the ball for whatever reason goes beneath the floor before it bounces up. Why is that? Well, you see Blender is doing all the calculation based on the center of the object. It is important to emphasize that all of the operations we're doing here are all based on the points we created. These points only become spheres at the end of the notary when we're using the instance on points known. So up until this point of the notary, we're still dealing with points, which means Blender is seeing points here, not spheres. So as a solution for this, we can tell Blender the following. If the ball touches the floor, move it down by the radius amount, do the correction, and then put it back This will look something like this in nodes. I'll add a radius node and plug it into a combined XY Z node into the Z axis. We're doing a bunch of operations on vector, that's why I need to convert this radius, which is a single value into a vector. I want to move the position down by the amount of the radius. I will add a vector math node, change the operation to subtract, and I'm going to plug the position to the first socket, which means I will subtract from position. The second value should be the vector we got from the radius. So I will plug the vector from the combined x Y Z node into the second socket. Next, we will do our correction by using this vector multiply node. We need to cancel the subtract operation we did before by adding a vector math node set to add, and I will add the vector I subtracted before, which is the vector coming out of the combined x Y Z node. If I hit play, you will notice that the ball is now bouncing of the floor the right way. Now comes the worst part, which is that we need to do a similar correction to all the different constraints, right and left, front and back. But that will be simple. Let's do it really fast. Let's start with the condition of the right wall. When does the sphere touch the right wall? Simple when the position on the x axis is greater than one minus the radius. I'll add a radius node. I will connect it to a math node, set it to subtract, so it will be one minus the radius, and plug that into the greater than node. This is my new condition. Why should happen now if this condition is true? Reverse the velocity, that should stay the way it is. If I hit play, you will still notice that the ball will still go beyond the right wall because we need to do a similar correction to what we did for the floor. Offsetting the simulation to the right, do the correction, and then move it back. This will look something like this. I'll add a radius node and plug it into the combined xyz node into the x axis this time. As I mentioned before, we're doing a bunch of operations on vector. That's why I need to convert this radius, which is a single value into a vector. I want to move the position right by the amount of the radius. I will add a vector math node, change the operation to add. I'm going to plug the position to the first socket, which means I will add to the position, the second value, which should be the vector we got from the radius. So I will plug the vector from the combined x y z node into the second socket. Next, we will do our correction by using this vector multiply node, Then we use the ad operation to count for the other correction, and we need to cancel the add operations we did before by adding a vector math node set to subtract, and I will subtract the vector I added before, which is the vector coming out of the combined x y z node. If I hit play, you will notice that the ball is now bouncing off the right wall correctly. This is the correction for the right wall. Now we need to do it for the left wall. Let's start with the condition for the left wall. When does the sphere touch the left wall? Simple when the position on the x axis is less than minus one plus the radius or the radius minus one. I'll add a radius node. I will connect it to a math node, set it to subtract, so it will be the radius minus one, and plug that into the less than node. This is my new condition. Should happen now if this condition is true. Reverse the velocity, that should stay the way it is. If I hit play, you will still notice that the ball will still go beyond the left wall, because we need to do a similar correction to what we did for the floor and right wall by upsetting the simulation to the left. Do the correction, and then move it back. This will look something like this. I'll add radius node and plug it into a combined x Y Z node into the x axis this time. I want to move the position left by the amount of the radius. I will add a vector math node, change the operation to subtract. I'm going to plug the position to the first socket, which means I will subtract from the position, the second value, which should be the vector we got from the radius. I will plug the vector from the combined xyz node into the second socket. Next, we'll do our correction by using this vector multiply node. Then we use the subtract operation to count for the other correction, and we need to cancel the subtract operation we did before by adding a vector math node, set it to add. I will add the vector I subtracted before, which is the vector coming out of the combined xy Z node? If I hit play, you will notice that the ball is now bouncing of the left wall correctly. This is the correction for the left wall. Now we need to do it for the front and back wall. This should be really similar to the right and left wall. I'm going to hit three from the number pad to jump to the side view, and let's start by doing the correction for the front wall, which looks like the right wall from this view. When does the sphere touch the front wall? Simple when the position on the y axis is greater than one minus the radius. I'll add a radius node. I will connect it to a math node, set it to subtract, so it will be one minus the radius, and plug that into the greater than node. This is my new condition. What should happen if this condition is true? Reverse the velocity, that should stay the way it is. I I hit play, You will still notice that the ball will still go beyond the front wall because we need to do a similar correction to what we did before by setting the simulation to the front, do the correction, and then move it back. This will look something like this. I'll add a radius node and plug it into a combined xyz node into the y axis this time. I want to move the position forward by the amount of the radius. I will add a vector meth node. Change the operation to add, and I'm going to plug the position to the first socket, which means I will add to the position, the second value, which should be the vector we got from the radius. So I will plug the vector from the combined xyz node into the second socket. Next, we'll do our correction by using this vector multiply node. Then we use the ad operation to count for the other correction, and we need to cancel the add operation we did before by adding a vector meth node set to subtract, and I will subtract the vector I added before, which is the vector coming out of the combined xyz node. If I hit play, you will notice that the ball is now bouncing of the front wall correctly. This is our correction for the front wall. Now we need to do the same for the back wall. Let's start with the condition. When does the sphere touch the back wall? Simple. When the position on the y axis is less than minus one plus the radius or the radius minus one. I'll add a radius node. I will connect it to a math node, set it to subtract, so it will be the radius minus one and plug that into the less than node. This is my new condition. What should happen now if this condition is true? Reverse the velocity, that should stay the way it is. If I hit play, you will still notice that the ball will still go beyond the back wall because we need to do a similar correction to what we did before by upsetting the simulation backward, do the correction, and then move it forward. Will look something like this. I'll add a radius node and plug it into the combined XY Z node into the y axis this time. I want to move the position back by the amount of the radius. I will add a vector math node, change the operation to subtract, and I'm going to plug the position to the first socket, which means I will subtract from the position, the second value, which should be the vector we got from the radius. So I will plug the vector from the combined XYZ node into the second socket. Next, we'll do our correction by using this vector multiply node. Then we use the subtract operation to count for the other correction, and we need to cancel the subtract operation we did before by adding a vector math node, set it to add, and I will add the vector I subtracted before, which is the vector coming out of the combined x y z node. If I hit play, you will notice that the ball is now bouncing of the back wall correctly. And now our physics engine is aware of the radius of the points and will consider it when running the simulation. I know it might feel like we did a lot of operation in this video and that might be overwhelming. But in case you don't understand what we exactly did, go back and watch this video from the beginning and try to focus a little bit and try to visualize what's happening, and you will be surprised of how easy these concepts are. I know it might feel like really complicated, especially when I'm doing the stuff so fast, but believe me, once you understand it, you will be able to do it like literally blindfolded because you understand the concepts behind. Probably we will also laugh at yourself for thinking that too is complicated. This is how we can implement the radius in our simulation, and Right now there is only one more problem we need to solve, which is how to make these balls collide with each other. That's what we will be doing in the next video. 13. Collision: Collision. Hello, and welcome to the last technical video on how to create your own physics engine in blender using geometry nodes. We went through a lot, so give yourself some credit because this video might be the most complicated one so far. We're not going to add a lot of nodes, but some of you might find it a little bit complicated to understand the concepts behind all the operations we will be doing in this video. But I will do my best to explain everything step by step. And hopefully, if you focus enough, you will understand exactly the logic of the thing we will build. This is where we stopped last time, and right now we're only dealing with one point. Or one ball. I want to have multiple ones. The easiest way around that will be to increase the number of points to something like ten, let's say. And let's make the radius set to something small like 0.2 meters. Now, all of these balls will be on top of each other. That's why I'll connect to the position, a random value node, and this node will assign a random position to each point. And all you need to do is to give it an interval by specifying a minimum maximum value, and it will assign a random value in that interval for each point. You can play with the values until you get the result you want. But in my case, I ended up using these values for the minimum values minus one minus one, three, and for the maximum values, one, 15. Now, if I hit play, you will see that we now have ten spheres, but the biggest issue is that all of these bowls, they intersect with each other. Are not colliding. We told Blender to make the balls bounce of the different walls, but we didn't tell it to also make them bounce of each other, and that's a crucial part of building our own physics engine. So how can we do such a thing? Let's try to brainstorm some ideas on how we can program such a thing. Let's start with the first question. One does two balls basically collide? Because if we know that condition, we can tell Blender that, hey, if this condition happens, do something. Well, I'll give you the answer. Two balls collide when the distance between them or the distance between the centers is less than the radius multiplied by two. I think that should be clear from this visualization. I always find it hard to pronounce that word. That's the logic of the condition we will build later. We'll tell Blender to always calculate the distance between two points, and if the distance between them is less than the radius multiplied by two, that means they are colliding, and you should do something about it. Now, let's translate that into nodes. I will add a node called index of nearest. This node will give me the index of the closest point. If I jump to the geometry nodes workspace, as I mentioned before, each point have an index that refers to it. The index of nearest node will give me that index of the closest point to a certain point. Once I know the index of the closest point, I can ask blender to read its position, which you can do by adding a node called evaluate at index, which is a way to tell blender. For that point, I want you to calculate something. In our case, we want to know the position of that point. I'll change the type from float to vector. Because position is a vector. I will add a position node and plug it into the value. Now the output vector of this evaluate at index node is the position vector of the closest point, point B, which is the closest to my point. The output of the position node is the position vector of point A. Once I have both of these two vectors, I can add a vector math node and change the operation to distance, and if I plug the vector coming from the evaluate at index and the position node, This node will give me the distance between them. Now, how do I know if those two points are colliding? I said the answer before. If the distance between the two points is less than the radius multiplied by two. I'll add a radius node that I will multiply by two, the distance should be less than two times the radius. The output now of this less than operation is my condition for when two points or balls are colliding. Now there is something important we need to think of, the order of the operations. Should we run the collision constraints before or after the balls constraint, think about it for a second. Answer is before. We need to count for colliding before the walls constraints. The reason for that being is that it makes more sense to calculate the collision before the walls touches the walls, since they might push each other away from the walls or push each other into the walls. Once we know that, we can run the walls constraints. That's why I will add a set position node, and I will plug it before the part where we have the other constraints. Basically, right after the node responsible for updating the position. And I will plug the result from the less than operation. To the selection socket of the set position note. Now that we finished building our condition, now we need to move on to what should happen if this condition is true or what should happen if two balls are colliding. So my question now, what should happen if two balls are colliding? Think about it. The answer is the following. If two balls are colliding, we need to push them away from each other. That's a safe thing to say, and also I think it is supergenious to say. But there are two important questions that we need to answer. First of all, by how much should we offset both of these two balls? Is it like this or they will push themselves like this? That's an important thing to figure out. So that's number one. Number two, along which direction. So if both of these two balls collide, would they go like this or this or this or this? That's also an important thing that we need to figure out a way to translate it into nodes. For the how much we need to offset the position of the two points, that should be simple. Calculate the distance between the two points, divide it by two and move each point by that amount. For the direction, need to push along the vector that crosses both the two points. How can we calculate the vector? Here's the position vector for the point A, and here's the position vector for point B. I can calculate the vector crossing them by doing a subtract operation, position vector of point A minus position vector of point B. That will give me the vector along which the offset position should happen. Now, let's translate all of those thoughts into nodes. I'll start by calculating the vector crossing the two points. As I said, that will be the position of point A minus the position of point B, which you can do by adding a vector math node and set it to subtract. I will plug the position in the first socket and the vector coming out of the evaluate at index into the second socket? That's the vector I will move the two points along. Now let's move on to the amount of by how much to offset the two points. We need to calculate that distance divided by two, and that's the amount by how much I should offset each point. How can I calculate the red line? This is the radius. This is also the radius, and this is the distance between the two points. If I do two times the radius minus the distance, that will give me the length of the red line or by how much the two points are intersecting. Let's translate that into notes. I will add a math note set to subtract. The operation is two times the radius, minus the distance between the two points. Will add another math node and set it to divide, and I will divide it by two. The output of this is the amount of offsetting. I will add a vector math node, change it to scale, and I will scale the vector along which I want the operation to happen, which is coming from the vector subtract node, and scale it by the amount coming from the divide math node. This will go straight into the offset socket of the set position node. And that's it. That's how you can build collision in our physics engine. Now, if I hit play, you will still notice that the balls are still colliding. This is the part where you can start hating me because even after all of this complicated math, it still doesn't work. But we'll fix that. I want to mention that it is not that what we did is wrong, the problem is about blender. It's not our fault. It's blenders. As I mentioned before, because of the oiler integration method used in Blender, we need to deal with high numbers of error. The oiler integration method is fine at best, and it is really prone to error. So the best solution to make our simulation more precise is instead of running this operation only once, what if we can figure out a way to tell blender that each frame don't just run this physics engine once, run it, for example, 100 times. That way you will get away more precise result. Actually, you already know the answer for this question. Can you guess it? Drum rolls, and it is repeating zones. The first thing we talked about in this course. What I will do is to add a repeat zone and I will insert my entire constraint system inside the repeat zone like this. And now from the first node of the repeat zone, I can specify how many times I want blender to calculate the constraints. Yes, Blender will run the simulation only once, but I can specify using the repeat zone, how many times to run certain operations within one frame. That's called substep. I will do, for example, 50. Now, if I hit play, blender, every frame will run the collision system 50 times to get a really accurate result. And now, as you can see, our balls are colliding nicely, and everything is working smoothly, and that's how we create the collision system for our balls. In the next video, I will share some final thoughts on how to do certain things in our physics engine. 14. Particle's Spawning: Particles spawning. Hello and welcome, and in this video, we are going to make the points spawn over time and not have them all at once. This is where we stop last time. Right now, our simulation has only ten points. Let's say I want 100 points. If I increase the number of points to 100 and hit play, you will notice that the simulation will go haywire because when we increase the number of points, we increase the probability of error, and that will make the simulation super unstable. So what is the solution for that? Well, in our current simulation, we have 100 points from the beginning. What if we figure out a way to tell blender to not have 100 points from the beginning, but spawn them or add them over time? That should lead to a more stable simulation. How can we do that? Let's start with the first part which is how to tell blender to spawn the particles over time? That will be simple. All you need to do is to add a joint geometry node and plug it as the first node in the simulation zone. I will take the output from the points node, technically from the store named attribute node and plug it into the joint geometry node. What will happen now is that blender will add more points each time it runs the simulation. Or to be more precise, Blender will join the previous geometry with the new geometry. Next, I'm going to lower the number of points to one, because if I don't do that, blender will explode. It will start having 100 points, and every frame will add another 100 point. You can easily see how that will lead to having a crazy number of points really fast, which will crash the software. When I change the number of points to one, Blender will only add one point every frame. Actually, that's still too much, and we'll need to make a blender spawn a point maybe every 20 frames. But before we do that, if I hit play, as you can see, Blender is adding a new point every frame, which is still too much, and it is still leading to the stimulation being unstable. The solution will be to tell blender that T don't one point every frame. Maybe add one point every ten frames or 20 frames. So how can we program such a thing? I will start by adding a same time node. This node will either give me the seconds value or the frame am on. I will take the frame and plug it into the count of the points node. Now, at frame one, blender will add one point. At frame two, Blender will add two points, so I will have three points and at frame three, Blender will add three points, so I will have six points total. That's not what I want. I want to tell blender that a point every certain number of frames. I will add a math node and I will set it to floored modulo. Floord modulo is just a fancy way to say that this node will return the remainder of a division operation by this value. This node will allow us to specify how often we want blender to add a new point. I will also add another math node and I will set it to equal two, and the value should be zero. Here's the logic of what's happening. Blender will take the number of the frame amon will then divide it by this value, and if the remainder is equal to zero. That means this equal to condition is true, which means this node will output one, so Blender will add one point. And if the remainder is not equal to zero, that means this equal two condition is false, which means this node will output zero, so blender won't add any point. Want blender to add one point over 20 frames. That's what I will get if I type 20 here. Here's an example of what will happen. Let's say I'm at frame 55. Blender will divide 55 by 20. The remainder of the operation is 15. 15 is not equal to zero, which means this node will output zero, and since this node is going to the counts of the points node, that means blender won't add any point. Now, let's say I'm at frame 60. Blender will divide 60 by 20. The remainder of the operation is zero, zero is equal to zero, which means this node will output one because this condition is true now. That one will go to the point count socket, and Blender will add one point to the simulation. I think the logic should now be clear of what's happening. Now if I hit play, Blender will start adding particles gradually, which is exactly what I want. The last thing I want to do is to tell blender to spawn each point to a different direction. I can do that by assigning a random initial velocity vector to each point, which you can do easily by plugging a random value node into the vector socket of the store name attribute defining the initial velocity. And I's add the values to minus one minus 10 for the minimum, and 110 for the maximum. This is how we can make blender spawn the particles over time. Think the logic is super simple. In the next video, we will add fraction to our simulation. 15. Friction: Adding fraction. An important part of any simulation is fraction. With no friction, the balls will just keep bouncing forever. That's why it is important to figure out a way to tell blender to dampen the simulation with time. And we actually touched on this topic before, but what we will do in this video is to make the process of changing the friction a little bit easier. Now, this is our entire note tree, and what I plan on doing is the following. As you remember, in the constraints, I have the velocity that is multiplied by minus one depending on the axis. If I bring this value up to something like -0.8, that will lead to more friction. What I want is to change this value for all the different multiplied nodes at once. This is simple. I will add a combined xy z node. I will input the same value here, one, one minus one and plug that into the vector of the multiply node. I didn't do anything fancy, I just replaced the value in the multiply node by this combined x y z node. The reason I did that is that now I can add a group input node and take the z axis and plug it to the group input. Now if I go to the modifier stab, you will see that I can change the value from here. Also, it is important to note that I will only be changing the value for the z axes because that's the socket plugged into the group input. For the rest of the sockets, they will stay one. This will make the process of changing the values of friction way easier. Now, I need to do the same thing for all the different constraints. I will start by doing it for the right wall, add a combined x Y Z node, and add a group input. I will move on to the left wall, add a combined x y zende with the same values, and added group input. I will do the same thing also for the front wall right now. Lastly, I will do the same thing for the back wall. S. And now I can control the friction easily from here. I can also open the side bar by hitting n and the geometry node editor, select one of the group inputs, and you can double click to change the name of this property to something like friction. For my simulation, I'm going to set the friction value to -0.9. Another way to add fraction is by going back to the store named attribute node defining the velocity, and if I add a vector math node and set it to scale, I will be able to dampen the velocity on the entire simulation. It's like a global friction that will apply every frame. I can even add a group input and plug it there, change its name to global friction. I will set it to 0.99. The simulation will lose velocity by a factor of 1% every frame. Also, it might be useful to change the number of steps of the repeat zone from the modifier step. That's why I will also plug it into a group input node and call it, for example, sub steps, and I will set it to 20. Those are the values I use for the promo render. Lastly, I will set my frame rate to 120, so I will have a really smooth frame rate, and my simulation will be less prone to error. For the frame range, let's say I want a ten second render, which means my frame range will be up to 1,200 frames. If I hit play, our simulation is working smoothly. That's it, everyone for this video. We technically finished everything. In the next one, I will show you how I created the final scene and how to render it. 16. Final Overview: Hello again. On last time. This is the last video of building our own physics engine in Blender. This video is a summary, slash a bird's eye view on everything that we did up until this point. The first thing I'll start with in this video is our notary, because currently it is an absolute mess. If you decide to go back to this project in the future, you will probably get lost in the C of all of these different nodes. That's why I'll start by organizing and labeling the notary, and then I will move out to the summary. Okay, welcome back to Blender, and this is my entire not try, and it is a mess honestly. I'm going to hit Control Space bar to maximize this editor. As you can see, there are a lot of nodes, and especially in the future, it will be tough to actually understand what's happening because we didn't label our note try. What we will do in this video, as I mentioned, is, first of all, to start by organizing our note tree. I will go to the beginning of the note try. I'm going to select all of these nodes, hit Control G to create a label around them, hit F two for a name, and let's call it, for example, initial condition. Once we have our initial condition, we enter the simulation zone. We have this joint geometry responsible for adding points over time. After that, we define the acceleration using this named attribute, and it is related to the scale and this vector node. Make sure to select the three of them. Hit Control G, F two for a name, and let's call them acceleration. Next, you will have the store named attribute responsible for defining the velocity. Let's move it here. Same thing. Let's put all of these nodes on top of each other like this by stacking them. Select all of these nodes, control G and F two for a name, and let's call it velocity because we're defining the velocity using these nodes. Next, we're updating the position using the set position node, so stack the nodes over each other. Select them, control G, F two, and let's call them position update. After that, we enter the repeat zone, which is responsible for compiling all the different constraints. Let's put this node around here. Actually, I'll move it up, but let's just try to find a solution in this entire mess right here. Actually, to make the whole process easier and to have more space, I will start organizing these nodes from the end. I will have these nodes that are responsible for transforming the points into the spheres, so I will select all of them, Control G to create a label, F two for a name, and let's call it, for example, instancer. Move these back. Move this also back. The less constraint I have right here, it is the constraint for the back wall. Let's select it entirely, which should be all of these nodes. Let's organize them. First of all, you'll have these nodes on top. I'm going to take Control G, and this is my condition. Let's organize these nodes right here. Something like so. Maybe you will work. And then elect all of these nodes, Control G, F two for a name, and let's call it back wall strant. Next, you will have this. Do a similar thing, select these, Control G and F two, and let's call it condition. Next, I will move these nodes here. This one here, here, these ones here. Select all of them. Control G, F two for a name, and let's call them front wall constraint. Now to the left wall constraint, all of these nodes, select these control G F two condition. Next, is here, this one here and this one here. Select the entire note tree, control G, F two, left wall, constraint. Now to the right wall constraint, Control G, F two condition, move these nodes here. Same thing for this one and this one, then like so. Then select all of them, control G, F two, right wall constraint. Lastly, the floor constraint, which are these nodes. We will do a similar thing. Select the control G, F two condition. Move these ones here, for the position, for the velocity, sorry, and select all of these. Control G F two floor constraint. These are the different constraints, and lastly, you will have the collision system. Let's try to figure out a way to organize all of these. I'm going to select all of them and move everything down. I think this will be better. Let's put this one here and maybe move the p zone and all of these nodes slightly to the left, and then select all of these Control G F two, and it's called it collision. This is my collision group. And bring this group input up, this slightly like this. And by doing this, we organized our node tree. In the future, if you go back to this, you will know exactly what each group of nodes are doing. Because we labeled them. Also, when you take this bird's eye view on the entire node tree, you start to see the logic behind everything we did. As a final summary, here's the logic of everything we built. First of all, we start by defining the initial conditions, how many points we have, when we want to spawn points, and all of that. These points later will enter the simulation zone. The first thing we do here is to define the acceleration and then define the velocity. Which we both use to update the position of our points. Once we have this basic setup, we can start thinking about different constraints. For our physics engine, there are two types of constraints that we care about. The first one being the collision, which is the collision between the different spheres, and then the different walls, which are the floor, the right and back wall, and the left and front wall. And at the end of the note tree, we use this instance on points node to transform those points into an actual geometry, which in our case happened to be EUV sphere. And yet, This is our entire physics engine. And yeah, that's basically it for how you can build your own physics engine in blender. Now you can create a scene around the simulation and render it however you want. Also, since shading and animation are beyond the scope of the scores, and I wanted to keep the course concise and make it just about geometry nodes. That's why I made a bonus free video that you can watch, where I take you step by step on how I created my render. You can watch either from the link in the description or by going to my website. The geometry node part and the shaving part are quite different disciplines, and that's why it made more sense to keep them as separate things since I take different approaches in teaching both of them. Lastly, thank you for tuning into this course. I hope you learned a lot. If you found this course useful, please leave us a good review that helps us make better courses, and you can still check the rest of my courses here. Thank you very much, and I'll see you or.