October 6, 2019
Pulley Wheel Positioning System
Video Demo of Wheel Positioning System
By: me
General System Needs
My pulley system needed to create a rope with objects attached to it, as well as objects which act as the pulley wheels which will support the rope. The positioning of these wheel objects must be in line with the rope, but below it. Using the HFF system, the rope gets generated and then falls, draping itself over any objects below it.
Keeping those requirements in mind, I also wanted the system to be able to generate a varied amount of these pulley wheels and place them in varied positions below the generated rope. Having the option for multiple wheels became more important when I noticed that sometimes ropes with heavy objects attached can break through rigid body wheel support objects, but having more (therefore more support) can sometimes alleviate this issue.
So to summarize, I wanted a system that could choose a varied amount of positions along a randomly determined line, with extra rules dictating how far these positions should be from the ends of that line, and how much of a space buffer should be given to each position (so when an object is instantiated at one of these positions, it does not collide with another instantiated object).
Starting Off
To keep the system simpler for now, since the system needs to fall into place anyway, I was specifically randomly generating the rope on the xz plane at some height y. The wheel positions are then generated on basically the same line, but some distance below that line (to ensure the wheels are within the rope line, but below for the rope to fall on them).
Adaptive Range System
The difficult thing with this position range system is that choosing a position for an object removes a specific range around that position to account for the space needed to instantiate an object at that position. Because of this, I needed a system that could update the range options everytime a position was chosen. I came up with a system that could determine how to update the ranges everytime a position was chosen, and could also determine if a range needed split into multiple.
The first range is the easiest to determine. It is just the full range of values between the beginning and the start of the wheel positions, with a buffer at each end factoring in the value for distanceFromEnds that we want to give to keep objects from instantiating too close to the ends.
With this first range created, we choose a random position within this single range. After that is when the adaptive range system comes in. Depending on the position selected, there are several possible options to account for the options that have been removed from the range:
- If the position is sufficiently far away from any other range bounds, a range is effectively split in two.
- If the position is very close to both the min and max bounds of the range, that range is fully removed.
- If the position is very close to either the min or the max bound of the range, that range can just be modified.
Weighting the Ranges
One issue with a system that creates multiple ranges is that these ranges can be different sizes. So if at some point in the process I am randomly selected a range first, to then select values from, each range will inherently have the same chance of being selected, regardless of its size. To remedy this, I used a weighting system.
Each range has a weight in the range (0, 1] (The minimum bound is exclusive, as nothing should ever have a weight of 0, but the maximum bound is inclusive since if there is only 1 range it is the only option) representing how much its individual range covers amongst the total coverage of all the ranges within a list of ranges. This is easiest to explain with an example: We have 3 ranges: (0, 2] (2, 5] (5, 10]The total range coverage is: (2 – 0) + (5 – 2) + (10 – 5) = 10The individual weights for these ranges are then:Range 1 (0, 2]: Weight = (2 – 0) / 10 = 0.2Range 2 (2, 5]: Weight = (5 – 2) / 10 = 0.3Range 3 (5, 10]: Weight = (10 – 5) / 10 = 0.5
So when we go to select a range, we randomly roll a number in the range of (0, 1] and use this to determine which range to pull a value from. This works by checking if the rolled value is less than or equal to the first range’s weight. If this is satisfied, that is the range to choose from. If not, it moves to check the next range’s weight. To fit this within this (0, 1] range, each time a range is not used, its weight is added to a pool to add to the next range’s weight. This helps move the weight check along the range of (0, 1] with many values significantly below 1.
To follow the previous example to show this in action:Our randomly rolled value to select a range is: 0.75General Formula:Check range n: Is rolledValue <= (rangenWeight + weightCheckPool)? No, add rangenWeight to weightCheckPoolCheck range 1: Is 0.75 <= (0.2 + 0)? No, add 0.2 to weight check pool and move to next rangeCheck range 2: Is 0.75 <= (0.3 + 0.2)? No, add 0.3 to weight check pool and move to next rangeCheck range 3: Is 0.75 <= (0.5 + 0.5)? Yes, use this range to select a value from