Instancing a random shape with a random start frame

Here I’m instancing a group of Arnold standin sequences, and giving each instance a different start frame. (Each standin sequence is an animated bulge on a cylinder.)
random shape w random offset
PS It works fine until you go past the last frame of the sequence, because looping or clamping the ShapeInstanceTime doesn’t seem to prevent SItoA from loading the non-existent ass file.

Building an array for weighted random selection

Here’s a little ICE tree that takes an array like
[ 0.1, 0.2, 0.2, 0.5 ]
and builds an array where

  • 10% of the elements have value 0
  • 20% of the elements have value 1
  • 20% of the elements have value 2
  • 50% of the elements have value 3

This is something I wanted to do for randomizing with weighted probabilities. The array [ 0.1, 0.2, 0.2, 0.5 ] is the weights I want to use for the values 0, 1, 2, and 3. The idea is that if I randomly select from the larger array, the weights will determine how likely I am to get each value (eg if 50% of the elements have value 3, then I’ll be much more likely to get that value when I randomly select).

To automatically build the array, I had to use a Repeat with Counter; I didn’t see around that.


So, for example, in an array of 1000 elements, I would have 100 elements with the value 0, 200 elements with the value 1, 200 elements with the value 2, and 500 elements with the value 3.

That works fine if the input array of weights adds up to 1, but what if I start with an array like [2 4 2 8 16] ?
To handle that, I need to make a small change:


Randomizing with weighted probabilities

The question came up the other day of how to use Randomize Value by Range so that some values were more likely to come up than others. For example, suppose you wanted some shapes to be instanced 4 more times than some other shape…


A common task is to make a random.choice() with weighted probabilities.

If the weights are small integer ratios, a simple technique is to build a sample population with repeats:

>>> weighted_choices = [('Red', 3), ('Blue', 2), ('Yellow', 1), ('Green', 4)]
>>> population = [val for val, cnt in weighted_choices for i in range(cnt)]
>>> random.choice(population)

So basically, if I want shape 1 to have a weight of 4 (so that roughly it is used 40% of the time), I would build an array that looks something like this:
[0, 0, 1, 1, 1, 1, 2, 2, 3, 3]
Then I generate a random integer and use it to select from that array. Because the “1” appears more often in the array, in the long run it should be more likely to be randomly selected.

Here’s an ICE tree where I apply this technique:
scn file here if you want it

This is what goes on inside the compound where I randomly select from the “weighted array” of possible shape IDs:

And here’s how I build an array with repeated values (the number of repetitions corresponds to the weight):

To get an idea of whether this works on not, I keep track of the number of instances of each shape:

For example:

Randomize Values by Range and integers

Randomize Value by Range doesn’t quite work with integers. Consider what happens when you try get a random integer between 0 and 7.

Randomize Value by Range was not designed to work with integers. By forcing it to integer type, you end up with a Random Value node that has a mean of 3 and a variance of 4 (hence the -1, which is the result of 3 – 4).

A Random Value node with a mean of 4 and a variance of 3.5 would give you an integer between 0 and 7 (because when you force the random value into an integer, ICE truncates the scalar, so 7.5 would be 7, 0.5 would be 0).

A better way may be to use Floor on the scalar output of Random Value. I know some users have done their own Randomize Integer by Range compounds.