December 3, 2020

Railsystem | Chapter 4 Clip 2

Well, I have a wonderful electronic invention. I want you to see

welcome back to chapter four. In this second clip, we are going to continue setting up the main logic system. 

Last time we made a couple of tests to find out which points can place objects with specific requirements. I'm going to separate the rail into segments that allows me to ignore certain segments like a tunnel, but I can apply some rules.

My case. I want to suggest that the tunnel is already providing some support, which means you will have no objects placed in front of the tunnel. Let me explain how I intended the whole support system to work. It should be complex enough to reflect the terrain and how towers tunnels and bridges,are providing support to the rail.

But it should be simple enough to allow easy debugging and later changes. You could bring in complex formula to calculate stability of a structure, but that wouldn't be practical at all. It needs to be a lot more simple than that. It should be something that you can easily explain to others and allow quick adjustments.

So my strategy is that specific points would hold a certain support value, not even a float, but just a simple integer. Let's say a point has a support of five. That support is then. Distributed to the neighbors, four, three, two, and one. Then the system will notice that the point after that has zero support, that means it needs to play something there a tower maybe that will provide its own support.

The challenge will be not to just place it right there, where there is already no support. If the tower provides again, five support, it should be placed further ahead. And when its support is distributed. All points should have at least one support. When we continue with that process, we end up with a rail covered with support, but first we need to notice a switch in the segment.

It could be done in easier ways since I only have tunnels and not tunnels, but I wanted to have a system that could be extended to multiple possible options. And this is how I did that. The Wrangell will be on detail. The first task is to give each point a specific segment ID that shows where it belongs.

So I create that ID and directly applied with zero. At the first point, I'm going to need two variables to signal a change in the groups. That's when we will know there's a different segment. First I'm initializing the variable in tunnel with what 0.0 is in. You can use the function in point group for that.

At the point is in it, it returns one. If it's not, it would turn to zero that can also be used as a condition conditioning. An if statement. Now I want to go over all of my points with a four loop. I already covered point zero. So I begin with one at the start. I set the mismatch to zero. That way, each iteration starts with a clean slate.

Now I check if the value and the variable internal is not equals the result of the InPoint group using I as point number two, get the current iteration. If it is not equal, wherever mismatch, you would do that for each of your possible groups. After that you look at the mismatch and if it is set, we put the new value into the internal variable.

So I have a one or zero. If I reach this point, I have either reached a tunnel or just left a tunnel. That means we can now increase the segment ID. In any case, the current part gets his own segment ID, which either stayed the same or worse, increased.

Looking at the spreadsheet, we can see that we ended up with five segments going from zero to four, looking at our terrain. That seems to be right. We have two areas where the tunnels are created. One segment at both the beginning and the end, and one short segment connecting the tunnels later, we will need to know how many points each segment has.

That is fairly easy to get with one line of VEX. We want a new attribute called segment length, and we fill it with the function findattribvalcount. This we'll look at the point attributes, segment ID, and count. How many have the same value as the current point. Now, each point knows in what segment he belongs and how many points are in the segment.

Next, we need an overall info about the amount of segments you can see. There are five, but how to tell that to a loop, another way to grab information like this is using the attribute promote note. We can look at the segment ID and turn it into a new detail attribute using the maximum method.

That way we get the max segments attribute.

With that available. We can do a, for loop using the number preset.

We'll do a fixed number of iterations. We just need to tell it to use that attribute, to make it easier to read. Let's rename this note, find max segments. When we go down to the end note, we can now enter an expression into the iteration. Parameter. That expression grabs the detailed attribute of that note with the name we choose.

And we need to add one to that. The amount of loop iterations start to count with one by our first segment and the duration counter of the loop starts at zero. So what to do once we are in the loop, I do a turn for each segment. So I only want to look at each segment on its own. The curve is through connected.

So the easiest way to get one segment at a time is to get rid of what is not part of one segment that is active for one iteration. Another wangle that are called current segment is going to do that. Connect the mater note into the second input for easy access of its attributes. Because when you look at this note, you can see that you hold some detailed attributes, like on what duration are we on?

And how many iterations are there in total? Very handy. Let's write this in a readable way. First, I get the value behind the iteration attribute that starts with zero and goes up to four. That means we can remove all points that have a segment ID, unlike the current iteration. That means we now have direct access to each segment by itself.

That does also mean that point number zero and the last point. Is no longer start and end of the whole curve, but from just this segment, we can use it like, so

if we are on point 0, this is the start of a segment.

And then just, if this is the start of a tunnel, we apply a certain amount of support to this point. The tunnel begins. So it doesn't need external support structures. Like towers.

I will Also apply a trigger attribute on this point. It signals that it has support to be distributed to the neighbors. More than that. Soon, I do the same with the last point, which marks the exit point of the tunnel. Here we apply the same, a certain amount of support, and then a trigger attribute. Let's switch the visualizers to show support and the distribute trigger.

If we now take a look at this spreadsheet, we see that we see nothing. There's no support nor a trigger attribute. We also don't see any visuals in the viewpoint, but that is actually correct. We are looking at a segment that is not a tunnel. Also. We have not yet set the value for the tunnel strength channel.

So let's switch to the second segment and this one is a tunnel and you can see the yellow one at each end of it.

This seemed to work for all segments as it should. Let's take a closer look at this spreadsheet just to be sure we did everything correctly. We have one start and one end point, according to the available segments. So we did everything correctly. Before we go further copy of the code of this Wrangle I want to apply another rule.

And that is that the global started end should also have an initial support. It doesn't make sense to create objects right at the corner of the scene. At the very least, you should be able to apply something there to control it, create a new record, and this is start and end global paste in the snippet we created before.

And now we just have to get rid of everything we don't need. We don't need to set an attribute or the segment test anymore. So we'll throw that away. Instead of tunnel strength, we get this very from a new channel and I call that border strength.

Remember that all of these attributes go to the control node at the end of this chapter. That leaves us with one final task. And that is to do the actual support distribution. This will be a piece of coding that we can reuse in the main algorithm, but before the main logic can figure out where to place objects, the initial support needs to be set in this Wingo.

We are going to deal with the local and offset support, and we want to loop over specific points this time. All the points that have support to distribute. There's a special form of a form that allows us to do that. As usual, we start with four and then call the counter PT. This time it gets filled by a colon polo by the function pint attra, Val, we provide the point attribute to distribute with a value of one.

And now we loop just over those few points that have the trigger attribute. All the start and end points of the tunnels and the two global border parts. First, we need to find out what this points, supporters that is the local support. Then we create a nested loop starting from that point with the trigger plus one.

So it's direct neighbor and the loop continues until we reach the point number. Plus that local support. Now we want to get the support that should be added to that neighbor. That difference is the initial local support minus the counter variable minus PT. That means if that local support is let's say five and we are currently looking at point 10, that is distributing it support.

I would be the point 11, so 11 minus 10. That's one local support minus one. Is what should be edit two point 11. So four point 12, that would be five minus 12, minus 10, which results in three additional support for point 12. I want to make sure that I add that support on any existing support. So I grabbed the support of that offset point, and then I can add the difference to it.

After that I set the value as a new support attribute. That covers the distribution to the next point, but we also need to apply that to the points behind us. So copy and paste this whole block. And while this was the fava distribution, this is now the backward distribution. This is another good opportunity to talk about scope of parables.

That is the right term for what I explained earlier about variables that are created inside these blocks. I have a second identical if block that uses the same variables, like the encounter called I and the difference Variable, I also created inside the block. All I have to do is change the leading sign of these operations.

Now I is PT minus one, and I continue until I is bigger than PT minus local support. And this loop is decrementing the variable. Also the difference is calculated slightly different by turning PT and I around, but I can absolutely use the variable. I and difference, even though I used them in the block before the backwards block doesn't know the variable difference since it is only in the scope of the forward block.

So he is a challenge for you. When do we have to declare a variable, like difference at the top of our coding? And when can we do that inside of a block and even declared another time in another block? Like I just, it feel free to pause the video and give it a thought and continue once you have an answer, 

just to be clear, if you have no idea, you can now continue to watch the video.

He will explain it. Now that was an educational tool because he is fancy or lame. You decide 

the answer to that is. You only need to declare the variable outside of the block if you're not only needed again, but you also need to know what value this brew comes out of the last block. So in my case, since I don't care about what difference values it had during its last iteration, I can declared once again, without getting any syntax errors, the same goes for the counter variable and finally, something very Houdini specific against something about scope.

But this time about attributes. As I explained, I read the support of the offset part so that I can add the new support on top of that. So if it already has any support value on it from a tunnel, maybe I don't want to override it. This is how I will do it later in the main process where I go through each point by itself.

But right now I go over all the points were one single wrangle. This is something totally different and absolutely confused me when I started learning Houdini and vex, while I can write whatever I want into variables. The final values of attributes are only applied after the Wrangler is finished processing.

So even if I write a new support value, like you see here in line 15, if I later read the attribute again, it will be whatever the wrangle started with. So for this wrangle, every time I read the point, attribute support from an offset point, that will be always zero at this stage. Also important to mention this doesn't count.

If you're on a point wrangle and change the global attributes like at P you're directly manipulating the attribute on that specific point here, in my case, I'm on a detailed rigger and create my own loop over all points. That's what makes the difference. For some, that might sound obvious, but if you're not aware of that, it's one nasty pitfall.

Since we don't need to look at the offset support at all, there's no reason to make that step so obvious with these lines. There's another way. Or we could write that part. You provide the difference to the set point atrip function, but change the mode from set to add. Now, the difference is also added to the existing values.

And finally at the very end of the loop that went through all the points with something to distribute, we want to toggle these points off here. We once again, use the moat toggle in the set at troop punching and there you have it. We no longer have points to distribute because all of them already did.

So. The support is provided to the neighbors by steps of one. This will allow us quite some control where to place objects in toll far, they can spread support by still being fairly simple to debug and 

customized. With that we prepared the logic system to go into its main calculation where towers and bridges should be placed.

So if you want to know how to create that system, come back next time or don't and never discover the secret knowledge of procedural Sci fy construction planning, a very important skill to have maybe someday. Whatever, come back to the next video. Subscribe hit the bell icon, pet a dog, wear a mask. Any other stuff you have to do, but mainly subscribe to the channel. .

Leave a Reply

Your email address will not be published. Required fields are marked *

David Kahl VFX

a Software Developer, Nerd and VFX Artist based in Germany
Visit Patreon
linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram