Today I finally got around to putting together a little tool for use in VEX/VOPs, to generate random numbers weighted according to a ramp. In the example below, I’m distributing 8000 points by ramp weight in the X axis, and randomly in Y – you can see how the density of random X values corresponds to the ramp.
This is using a simplistic method I remembered from a while ago when I saw it used for importance sampling brights parts of an environment map during rendering.
The idea is a bit similar to making a histogram. Divide your function (in this case the ramp) up into a number of bins, and scan over them, accumulating the sum of all bins up to that point in an array. The final value in the array will be equal to the sum of all bins.
Above you can see the normalised sum curve overlaid on the ramp curve. Where the ramp has a high value, the slope of the sum is greatest (because the change in value of the sum is highest when its summing high ramp values).
If we then choose a range of random numbers in y, most of the corresponding points on the sum curve will be in the areas of greatest slope. It’s easy to visualise as if you’re projecting points horizontally and intersecting the curve – areas of low slope will tend to get missed, and the majority of the random values will stick to the areas of greater slope, and therefore the greatest values in the underlying ramp function.
You can drop the VEX code below into a wrangle SOP or a snippet VOP. Right now it’s not hugely optimised, it’s pre-processing the ramp every time its run (eg. for each point), and it’s using a linear search to find the ‘random number intersections’ when a binary search might be faster. It’s still super quick though, so further work may not be so necessary.
Example .hip file is here: http://mattebb.com/projects/houdini/weightedrandom.hipnc