Hi, I made a module dedicated to generating random numbers, and you can try it right now!
Features
Here are some of the current features:
- Supports all the random number distributions from C++'s built-in
<random>library, and more! - Implements software emulation of unsigned integer (uint32_t, uint64_t, …) arithmetics, allowing custom pseudo-random number generators (PRNGs) that utilize the behavior of these number types to be created.
- Provides some custom 64-bit PRNGs that you can interact with like Roblox’s built-in
Randomtype. (Even though I only recommend using the nativeRandomtype, because it is much faster) - Some utility functions for your convenience.
How to use the module?
C++ style interface
Step 1, Add the module to your game, and then import the module:
local ServerScriptService = game:GetService("ServerScriptService")
local rng = require(ServerScriptService.RNG.RNG)
Step 2, Construct a random number generator object (You can use the built-in Random type!):
-- I always recommend just using the built-in Random type!
local rd = Random.new()
-- If you want to use the custom PRNG types, you need to seed it with 32-bit unsigned integer values:
local function get_seeds(N: number)
local seeds = table.create(N)
for i = 1, N do
-- this is the range of a 32-bit unsigned integer
seeds[i] = rd:NextInteger(0, 2^32-1)
end
return unpack(seeds)
end
-- Construct a xoshiro256+ PRNG
local x256p = rng.xoshiro256p(get_seeds(8))
Step 3, Construct the random number distribution that you want to use:
-- Construct a discrete distribution using item weights
local my_favorite_fruits = {"Apple", "Banana", "Cherry", "Pineapple", "Melon"}
local my_fruit_scores = {1.2, 2.7, 3.6, 4.1, 5}
local ddist = rng.discrete_distribution(my_fruit_scores)
-- Construct a Poisson distribution with rate=100
local pdist = rng.poisson_distribution(100)
Step 4, You can now start generating random values that follow the desired distributions:
-- Supply the distribution object with a random engine for it to draw random values from!
-- The following line will return a random integer between 1 and 5 based on the weights
local i = ddist(rd)
print("Chosen fruit:", my_favorite_fruits[i])
-- Or you can also call other library functions with the random engine as well
-- Draw 10000 samples from the Poisson distribution with rate=100
local samples = rng.generate_n(x256p, pdist, 10000)
print("Variance: ", rng.variance(samples)) -- this value should be close to 100
Simplified interface (added in V2.1)
Step 1, Add the module to your game, and then import the module:
local ServerScriptService = game:GetService("ServerScriptService")
local rng = require(ServerScriptService.RNG.RNG)
Step 2, You can directly generate random numbers using functions under the rng.get table:
-- These functions draw random values directly from `rng.get.current_random_engine`
print("Poisson:", rng.get.poisson(100))
print("Normal:", rng.get.normal(0, 1))
print("10000 dice rolls:", rng.get.multinomial(10000, {1, 1, 1, 1, 1, 1}))
-- You can also generate multiple values at once using rng.get(n)
-- (the result will be an array containing all generated values)
local loot_rarity = {1, 0.8, 0.6, 0.5, 0.0001}
local loot_indices = rng.get(100):discrete(loot_rarity)
-- loot_indices should now be an array with 100 elements
It is recommended that you use batched sampling (with rng.get(n)) or the C++ interface (you should cache the distribution objects) whenever possible. Because some distributions in this module rely heavily on precomputed values to speed up sampling.
Type annotations used in the module:
See types
-- All of these types show up as just "number" in the type system which is unfortunate
type integer = number -- a whole number
type index = number -- an integer that can be used for 1-based indexing (1, 2, 3, ..., N)
type real = number -- a number that may have a fractional part
type non_negative_real = number -- a real number that is >= 0.0
type positive_real = number -- a real number that is > 0.0
type nonzero_real = number -- a real number that does not equal exactly 0.0
type prob = number -- a real number in the closed unit interval [0, 1]
type vertexId = number -- a "stable vertex ID" returned by the EditableMesh API
type faceId = number -- a "stable face ID" returned by the EditableMesh API
type i54 = number -- signed integer with 54 bits [-2^53, 2^53-1]
type u53 = number -- unsigned integer with 53 bits [0, 2^53-1]
type u32 = number -- unsigned integer with 32 bits [0, 2^32-1]
type u16 = number -- unsigned integer with 16 bits [0, 2^16-1]
type f64 = number -- double precision floating point
type UInt64Generator = SplitMix64 | RomuQuad | RomuTrio | Xoshiro256Plus | any
type URNG = Random | any
List of currently implemented probability distributions:
See distributions (Now with actual documentation!)
--[[
This distribution produces integer values evenly distributed across the interval [min, max].
Parameters:
(min::integer) The inclusive lower bound of the interval.
(max::integer) The inclusive upper bound of the interval.
Range:
[min, max] (integer)
]]
function rng.get.uniform_int(min: integer, max: integer): integer
return rng.uniform_int_distribution(min, max)(rng_get.current_random_engine)
end
--[[
This distribution produces floating-point values evenly distributed across the interval [min, max].
Parameters:
(min::real) The inclusive lower bound of the interval.
(max::real) The inclusive upper bound of the interval.
Range:
[min, max]
]]
function rng.get.uniform_real(min: real, max: real): real
return rng.uniform_real_distribution(min, max)(rng_get.current_random_engine)
end
--[[
This distribution returns 'true' with probability <p_true>, and 'false' with probability (1 - <p_true>).
It models a single binary outcome.
Parameters:
(p_true::prob) The probability of returning 'true'.
Range:
{true, false} (boolean)
]]
function rng.get.bernoulli(p_true: prob): boolean
return rng.bernoulli_distribution(p_true)(rng_get.current_random_engine)
end
--[[
This distribution models the number of successes in a sequence of N independent yes/no experiments, where each trial succeeds with some given probability.
For example, it can model the number of heads in 10 coin flips, without actually simulating 10 coin flips.
Parameters:
(num_trials::integer) The total number of independent Bernoulli trials.
(p_true::prob) The probability of success for a single trial.
Range:
[0, num_trials] (integer)
]]
function rng.get.binomial(num_trials: integer, p_true: prob): integer
return rng.binomial_distribution(num_trials, p_true)(rng_get.current_random_engine)
end
--[[
This is the shifted geometric distribution that starts from one.
It models the number of trials required to get the first success in a sequence of Bernoulli trials.
For example, it can model the number of times you need to roll a dice until you get a six.
Parameters:
(p_true::prob) The probability of success for a single trial.
Range:
[1, math.huge] (integer)
]]
function rng.get.geometric(p_true: prob): integer
return rng.geometric_distribution(p_true)(rng_get.current_random_engine)
end
--[[
This distribution models the time or distance until the next random event if random events occur at a constant rate per unit of time/distance.
For example, it can model the time between the clicks of a Geiger counter or the distance between point mutations in a DNA strand.
Parameters:
(rate::real) The rate parameter (λ) is the average number of events per time/distance unit.
Range:
[0, math.huge]
]]
function rng.get.exponential(rate: real): non_negative_real
return rng.exponential_distribution(rate)(rng_get.current_random_engine)
end
--[[
This distribution models the number of events occurring in a fixed interval of time, given the events occur with a constant average rate of occurrence.
For example, it can model discrete counting processes, such as website traffic per minute or the number of calls received by a call center per hour.
Parameters:
(mean::positive_real) The average number of events (λ) that may occur in a time interval.
Range:
[0, 2^53] (integer)
]]
function rng.get.poisson(mean: positive_real): integer
return rng.poisson_distribution(mean)(rng_get.current_random_engine)
end
--[[
A highly flexible distribution often used to model waiting times until the α-th event occurs in a Poisson process with rate = 1/θ.
It is also used to model continuous, positive, and skewed data.
It generalizes the exponential distribution (when α=1).
Parameters:
(shape::positive_real) The shape parameter (α).
(scale::positive_real) The scale parameter (θ).
Range:
[0, math.huge)
]]
function rng.get.gamma(shape: positive_real, scale: positive_real): non_negative_real
return rng.gamma_distribution(shape, scale)(rng_get.current_random_engine)
end
--[[
This distribution models the number of failures that may occur before a specified number of successes.
The number of trials is not fixed.
Parameters:
(num_successes::integer) The target number of successes to be achieved.
(p_true::prob) The probability of success on any single trial.
Range:
[0, 2^53] (integer)
]]
function rng.get.negative_binomial(num_successes: integer, p_true: prob): integer
return rng.negative_binomial_distribution(num_successes, p_true)(rng_get.current_random_engine)
end
--[[
This distribution is often used in reliability engineering and survival analysis to model the time to failure of a system or component.
It can model various failure rate behaviors:
- shape < 1 : the failure rate decreases over time (ex: infant mortality).
- shape == 1 : the failure rate is constant over time (exponential distribution).
- shape > 1 : the failure rate increases with time (ex: aging).
Parameters:
(scale::positive_real) The scale parameter (λ).
(shape::positive_real) The shape parameter (k).
Range:
[0, math.huge]
]]
function rng.get.weibull(scale: positive_real, shape: positive_real): non_negative_real
return rng.weibull_distribution(scale, shape)(rng_get.current_random_engine)
end
--[[
This is the Gumbel distribution (Type-I generalized extreme value distribution).
It is used to model the distribution of the extreme values (minimum or maximum) of a number of samples from various distributions.
It is used in extreme value theory, such as predicting the probability of an unusually large flooding event.
Parameters:
(location::real) The location parameter (μ), which shifts the distribution.
(scale::positive_real) The scale parameter (β), which controls the spread.
Range:
(-math.huge, math.huge)
]]
function rng.get.extreme_value(location: real, scale: positive_real): real
return rng.extreme_value_distribution(location, scale)(rng_get.current_random_engine)
end
--[[
Also known as the Gaussian distribution or bell curve. It is used to model phenomena that cluster around a central mean.
It is a very common distribution in nature due to the Central Limit Theorem.
Parameters:
(mean::real) The mean value (μ), where the values cluster around.
(stddev::positive_real) The standard deviation (σ), which controls the spread of the data.
Range:
(-math.huge, math.huge)
]]
function rng.get.normal(mean: real, stddev: positive_real): real
return rng.normal_distribution(mean, stddev)(rng_get.current_random_engine)
end
--[[
This is the distribution of a random variable whose logarithm is normally distributed.
It is used to model positive random variables where the effects are multiplicative rather than additive.
Parameters:
(mean::real) The mean (μ) of the underlying normal distribution.
(stddev::positive_real) The standard deviation (σ) of the underlying normal distribution.
Range:
(0, math.huge)
]]
function rng.get.lognormal(mean: real, stddev: positive_real): real
return rng.lognormal_distribution(mean, stddev)(rng_get.current_random_engine)
end
--[[
This is the distribution of the sum of the squares of k independent standard normal random variables.
It can be used to analyze the differences between two categorical variables.
Parameters:
(degrees_of_freedom::positive_real) The degrees of freedom (k), which determines the shape of the distribution.
Range:
[0, math.huge)
]]
function rng.get.chi_squared(degrees_of_freedom: positive_real): non_negative_real
return rng.chi_squared_distribution(degrees_of_freedom)(rng_get.current_random_engine)
end
--[[
This is a continuous distribution describing resonance behavior.
It is known for its heavy tails, meaning extreme events are more probable than in the normal distribution.
It can be used to model extreme events such as large potential financial gains and losses.
Parameters:
(location::real) The location parameter (x0), which specifies the peak location.
(scale::positive_real) The scale parameter (γ), which specifies the half-width at half-maximum (HWHM).
Range:
(-math.huge, math.huge)
]]
function rng.get.cauchy(location: real, scale: positive_real): real
return rng.cauchy_distribution(location, scale)(rng_get.current_random_engine)
end
--[[
This is the distribution of the ratio of two independent chi-squared distributions divided by their respective degrees of freedom.
It is used in ANOVA (Analysis of Variance) and F-tests to compare the variances of different populations.
Parameters:
(d_freedom_1::positive_real) The degrees of freedom (d1) for the numerator.
(d_freedom_2::positive_real) The degrees of freedom (d2) for the denominator.
Range:
(0, math.huge)
]]
function rng.get.fisher_f(d_freedom_1: positive_real, d_freedom_2: positive_real): positive_real
return rng.fisher_f_distribution(d_freedom_1, d_freedom_2)(rng_get.current_random_engine)
end
--[[
This distribution is used to estimate the mean of a normally distributed population when the sample size is small and the standard deviation is unknown.
It is the basis of the T-test.
It approaches the normal distribution as the degrees of freedom increases.
Parameters:
(degrees_of_freedom::positive_real) The degrees of freedom (ν), related to the sample size.
Range:
(-math.huge, math.huge)
]]
function rng.get.student_t(degrees_of_freedom: positive_real): real
return rng.student_t_distribution(degrees_of_freedom)(rng_get.current_random_engine)
end
--[[
This is also known as the double exponential distribution. It has sharper peak and fatter tails than the normal distribution.
It models the difference between two independent identically distributed (IID) exponential random variables.
Parameters:
(location::real) The location parameter (μ), which specifies the peak location.
(scale::positive_real) The scale parameter (b), which controls the spread.
Range:
(-math.huge, math.huge)
]]
function rng.get.laplace(location: real, scale: positive_real): real
return rng.laplace_distribution(location, scale)(rng_get.current_random_engine)
end
--[[
This distribution models the magnitude of a 2D vector whose x, y components are independent and normally distributed with zero mean.
Parameters:
(scale::positive_real) The scale parameter (sigma), which is the standard deviation of the underlying Normal components.
Range:
[0, math.huge)
]]
function rng.get.rayleigh(scale: positive_real): non_negative_real
return rng.rayleigh_distribution(scale)(rng_get.current_random_engine)
end
--[[
A highly flexible distribution used to model many random variables constrained to the finite interval [0, 1].
It is used in Bayesian statistics as a prior distribution for probabilities, and to model random proportions.
Parameters:
(alpha::positive_real) The shape parameter (α).
(beta::positive_real) The shape parameter (β).
Range:
[0, 1]
]]
function rng.get.beta(alpha: positive_real, beta: positive_real): non_negative_real
return rng.beta_distribution(alpha, beta)(rng_get.current_random_engine)
end
--[[
This is used to model the phenomena where a small proportion of occurrences account for the majority of the effect.
The famous "80:20 rule" is associated with Pareto distribution with shape=log4(5)
Parameters:
(xmin::positive_real) is the minimum possible value for the variable being modeled.
(shape::positive_real) The shape parameter (α), it controls how quickly the probability decreases as the value increases.
Range:
[xmin, math.huge)
]]
function rng.get.pareto(xmin: positive_real, shape: positive_real): positive_real
return rng.pareto_distribution(xmin, shape)(rng_get.current_random_engine)
end
--[[
This is the opposite of the Pareto distribution, the probability increases as the value increases.
Parameters:
(xmax::positive_real) is the maximum possible value for the variable being modeled.
(shape::positive_real) dictates how quickly the probability decreases as value approaches 0.
Range:
[0, xmax]
]]
function rng.get.power(xmax: positive_real, shape: positive_real): non_negative_real
return rng.power_distribution(xmax, shape)(rng_get.current_random_engine)
end
--[[
A continuous distribution in the closed interval [min, max] where the probability density forms a triangle shape, peaking at the mode.
Parameters:
(min::real) The minimum possible value.
(max::real) The maximum possible value.
(mode::real) The peak of the distribution. Must satisfy: min <= mode <= max.
Range:
[min, max]
]]
function rng.get.triangular(min: real, max: real, mode: real): real
return rng.triangular_distribution(min, max, mode)(rng_get.current_random_engine)
end
--[[
This distribution generates random indices based on the provided weights, where higher weights mean a higher probability of that index being returned.
The weights do not need to sum to 1.
The resulting index is 1-based.
Parameters:
(weights::{non_negative_real}) A list of non-negative real numbers representing the relative probability of selecting each index.
Range:
[1, #weights] (integer)
]]
function rng.get.discrete(weights: {non_negative_real}): index
return rng.discrete_distribution(weights)(rng_get.current_random_engine)
end
--[[
This is a continuous distribution defined by a set of piecewise constant segments.
It partitions the range of the variable into intervals defined by <boundary_points>, and assigns a constant probability density (proportional to <weights>) to each interval.
Parameters:
(boundary_points::{real}) A sorted list of N points defining the boundaries of the intervals.
(weights::{non_negative_real}) A list of N-1 non-negative weights (densities) for the intervals.
Range:
[boundary_points[1], boundary_points[#boundary_points])
]]
function rng.get.piecewise_constant(boundary_points: {real}, weights: {non_negative_real}): real
return rng.piecewise_constant_distribution(boundary_points, weights)(rng_get.current_random_engine)
end
--[[
This is a continuous distribution defined by a set of piecewise linear segments.
It partitions the range of the variable into intervals defined by <boundary_points>,
and the probability density within each interval changes linearly between the values given by <weights>.
Parameters:
(boundary_points::{real}) A sorted list of N points defining the boundaries of the intervals..
(weights::{non_negative_real}) A list of N non-negative weights (densities) at the boundary points.
Range:
[boundary_points[1], boundary_points[#boundary_points])
]]
function rng.get.piecewise_linear(boundary_points: {real}, weights: {non_negative_real}): real
return rng.piecewise_linear_distribution(boundary_points, weights)(rng_get.current_random_engine)
end
--[[
This distribution generates a vector of probabilities that sum to 1.
It is a multivariate generalization of the Beta distribution.
Parameters:
(concentrations::{positive_real}) A list of N positive concentration parameters (α_i).
Range:
A vector of N non-negative real numbers that sum to 1.
]]
function rng.get.dirichlet(concentrations: {positive_real}): {non_negative_real}
return rng.dirichlet_distribution(concentrations)(rng_get.current_random_engine)
end
--[[
This distribution models the number of outcomes for each category after a specified number of independent trials.
It is a multivariate generalization of the Binomial distribution.
For example, it can model the number of times a six-sided die lands on 1, 2, 3, 4, 5, and 6 after 100 rolls.
Parameters:
(num_trials::integer) The total number of independent trials.
(weights::{non_negative_real}) A list of N weights for each possible category.
Range:
A vector of N integers where each element is non-negative, and the sum of all elements equals <num_trials>.
]]
function rng.get.multinomial(num_trials: integer, weights: {non_negative_real}): {integer}
return rng.multinomial_distribution(num_trials, weights)(rng_get.current_random_engine)
end
Utility Functions
PRNGs
-- RomuQuad PRNG from https://www.romu-random.org/
-- All seeds need to be set to nonzero values
function rng.romu_quad(
wH: u32, wL: u32, xH: u32, xL: u32,
yH: u32, yL: u32, zH: u32, zL: u32
): RomuQuad
...
end
-- RomuTrio PRNG from https://www.romu-random.org/
-- All seeds need to be set to nonzero values
function rng.romu_trio(
xH: u32, xL: u32, yH: u32, yL: u32, zH: u32, zL: u32
): RomuTrio
...
end
-- Splitmix64 PRNG from https://xorshift.di.unimi.it/splitmix64.c
function rng.splitmix64(stateH: u32, stateL: u32): SplitMix64
...
end
-- xoshiro256+ PRNG from https://prng.di.unimi.it/xoshiro256plus.c
-- Seeds cannot be all set to zero
function rng.xoshiro256p(
s0H: u32, s0L: u32, s1H: u32, s1L: u32,
s2H: u32, s2L: u32, s3H: u32, s3L: u32
): Xoshiro256Plus
...
end
-- Implements std::seed_seq from C++
-- See https://en.cppreference.com/w/cpp/numeric/random/seed_seq.html
function rng.seed_seq(seeds: {number}): SeedSeq
...
end
Sampling random 3D positions
type BoundedObject3D = Model | BasePart | Region3 | Terrain
-- Gets the current bounding box cframe and size of a 3D object
function rng.get_bounding_box(obj: BoundedObject3D): (CFrame, Vector3)
...
end
-- Returns a random point uniformly distributed inside the triangle A, B, C
function rng.uniform_point_in_triangle(
random_engine: URNG, A: Vector3, B: Vector3, C: Vector3
): Vector3
...
end
-- Returns a random point uniformly distributed inside the bounding box
-- of a 3D object
function rng.uniform_point_in_bounding_box_of(
random_engine: URNG, obj: BoundedObject3D
): Vector3
...
end
-- Returns a random point uniformly distributed inside a bounding box
-- defined by its cframe and size
function rng.uniform_point_in_bounding_box(
random_engine: URNG, cframe: CFrame, size: Vector3
): Vector3
...
end
-- Returns a random point uniformly distributed inside a circle defined by
-- its center cframe and radius
function rng.uniform_point_in_circle(
random_engine: URNG, center_and_normal: CFrame, radius: non_negative_real
): Vector3
...
end
-- Returns a random point uniformly distributed inside a sphere
-- defined by its center position and radius
function rng.uniform_point_in_sphere(
random_engine: URNG, center: Vector3, radius: non_negative_real
): Vector3
...
end
More random functions
-- Returns a pseudo-random number uniformly distributed over [min, max]
function rng.uniform_real(random_engine: URNG, min: real, max: real): real
...
end
-- Returns a pseudo-random number uniformly distributed over the half-open interval (0, 1]
function rng.uniform_nonzero_real(random_engine: URNG): prob
...
end
-- Returns a pseudo-random number uniformly distributed over the half-open interval [0, 1)
-- This is similar to std::uniform_real_distribution()(urng)
function rng.uniform_nonunit_real(random_engine: URNG): prob
...
end
-- Returns a pseudo-random number uniformly distributed over the open interval (0, 1)
function rng.uniform_noninteger_real(random_engine: URNG): prob
...
end
-- Returns the sum of all array elements
function rng.sum(nums: {real}): real
...
end
-- Divides all values in array by factor or sum(values)
function rng.normalize(values: {real}, factor: nonzero_real?)
...
end
-- Returns a copied array with all values divided by factor or sum(values)
function rng.normalized(values: {real}, factor: nonzero_real?): {prob}
...
end
-- Returns an array of numbers from 1 to N (inclusive)
function rng.make_index_sequence(N: integer): {index}
...
end
-- Returns an array of partial sums
function rng.partial_sum(nums: {real}): {real}
...
end
-- Convert array values into partial sums
function rng.partial_sum_inplace(nums: {real})
...
end
-- Returns the average value of numbers in an array
function rng.mean(nums: {real}): real
...
end
-- Returns the variance (average squared distance from mean)
function rng.variance(nums: {real}): real
...
end
-- Returns the standard deviation (average distance from mean)
function rng.stddev(nums: {real}): real
...
end
-- Returns the median value of a possibly unsorted array
function rng.median(nums: {real}): real
...
end
-- Returns the median value of a sorted array
function rng.median_presorted(nums: {real}): real
...
end
-- Returns the values that appear most frequently in an array
function rng.mode<T>(items: {T}): {T}
...
end
-- Returns the values that appear most frequently in a sorted array
function rng.mode_presorted<T>(items: {T}): {T}
...
end
-- Generate a standard normal variate with mean = 0 and variance = 1
function rng.standard_normal(random_engine: URNG): real
...
end
-- Find index of the first element that is >= value from a sorted array
function rng.lower_bound(nums: {real}, value: real): index?
...
end
-- Find index of the first element that is > value from a sorted array
function rng.upper_bound(nums: {real}, value: real): index?
...
end
-- Returns the min and max elements in the array
function rng.minmax(nums: {real}): (real, real)
...
end
-- Returns randomly permuted array of indices from 1 to N
function rng.permutation(random_engine: URNG, N: integer): {index}
...
end
-- Returns copied table with array elements randomly shuffled
function rng.shuffled(random_engine: URNG, tb: {})
...
end
-- Returns an array of N samples generated from consecutive calls to distribution(random_engine)
function rng.generate_n<T>(random_engine: URNG, distribution: any, N: integer): {T}
...
end
-- Sample k random items from array without replacement (using Algorithm R)
function rng.sample_without_replacement_r<T>(random_engine: URNG, items: {T}, k: integer): {T}
...
end
-- Sample k random items from array without replacement (using Algorithm L)
function rng.sample_without_replacement_l<T>(random_engine: URNG, items: {T}, k: integer): {T}
...
end
-- Sample k random items from array with replacement
function rng.sample_with_replacement<T>(random_engine: URNG, items: {T}, k: integer): {T}
...
end
Math...
-- Computes an approximated value of the gamma function with Lanczos approximation
-- Domain: R except 0 and negative integers.
-- Code adapted from SciLua (https://scilua.org)
-- Source code: https://github.com/stepelu/lua-sci/blob/master/math.lua
function rng.tgamma(z: real)
...
end
-- Returns log(abs(tgamma(z)))
-- Domain: R except 0 and negative integers.
-- Code adapted from SciLua (https://scilua.org)
-- Source code: https://github.com/stepelu/lua-sci/blob/master/math.lua
function rng.lgamma(z: real)
...
end
3D visualizations
-- Put some objects into the workspace to visualize the cframes' world positions and look vectors
function rng.visualize_cframes(cframes: {CFrame}, length: real?): Folder
...
end
-- Put some objects into the workspace to visualize the world positions given as Vector3s
function rng.visualize_positions(positions: {Vector3}): Folder
...
end
-- Put some objects into the workspace to visualize the given vectors as line segments
function rng.visualize_vectors(origin: Vector3, directions: {Vector3}): Folder
...
end
-- Put some objects into the workspace to visualize the given rays as line segments
function rng.visualize_rays(origins: {Vector3}, directions: {Vector3}): Folder
...
end
-- Put some objects into the workspace to visualize the given line segments defined by position pairs
function rng.visualize_line_segments(origins: {Vector3}, targets: {Vector3}): Folder
...
end
-- Put a BasePart into workspace to visualize an object's current 3D bounding box
function rng.visualize_bounding_box_of(obj: BoundedObject3D): Part
...
end
-- Put a BasePart into workspace to visualize a 3D bounding box
function rng.visualize_bounding_box(cframe: CFrame, size: Vector3): Part
...
end
-- Adorn an instance with a new selection box
function rng.visualize_selection_box_of(inst: Instance): SelectionBox
...
end
EditableMesh
These functions are stored in the submodule rng.mesh
local rng_mesh = rng.mesh
-- Returns the area of a triangle
function rng_mesh.triangle_area(A: Vector3, B: Vector3, C: Vector3): non_negative_real
...
end
-- Returns an outward pointing normal vector of the triangle (assuming winding order is CCW)
function rng_mesh.triangle_normal(A: Vector3, B: Vector3, C: Vector3): Vector3
...
end
-- Returns the outward pointing unit normal vector of the triangle (assuming winding order is CCW)
function rng_mesh.triangle_unit_normal(A: Vector3, B: Vector3, C: Vector3): Vector3
...
end
-- Returns a vararg containing Vector3 positions for each vertex on the given mesh face
function rng_mesh.face_vertex_positions(mesh: EditableMesh, face_id: faceId): (...Vector3)
...
end
-- Returns an outward pointing normal vector of the given mesh face
function rng_mesh.face_normal(mesh: EditableMesh, face_id: faceId): Vector3
...
end
-- Returns the outward pointing unit normal vector of the given mesh face
function rng_mesh.face_unit_normal(mesh: EditableMesh, face_id: faceId): Vector3
...
end
-- Returns the centroid of triangle A, B, C
function rng_mesh.triangle_centroid(A: Vector3, B: Vector3, C: Vector3): Vector3
...
end
-- Returns the point of intersection (if exists) of a ray and the triangle A, B, C
function rng_mesh.ray_and_triangle_intersection(orig: Vector3, dir: Vector3, A: Vector3, B: Vector3, C: Vector3): Vector3?
...
end
-- Determines if camera is looking at the back side of a mesh face
function rng_mesh.is_backface(mesh: EditableMesh, face_id: faceId, camera_orientation: Vector3): boolean
...
end
-- Determines if camera is looking at the front side of a mesh face
function rng_mesh.is_frontface(mesh: EditableMesh, face_id: faceId, camera_orientation: Vector3): boolean
...
end
-- Determines if point P is in the triangle A, B, C
function rng_mesh.is_point_in_triangle(P: Vector3, A: Vector3, B: Vector3, C: Vector3): boolean
...
end
-- Returns the solid angle subtended by triangle A, B, C from point P
function rng_mesh.triangle_signed_solid_angle(P: Vector3, A: Vector3, B: Vector3, C: Vector3): real
...
end
-- Computes the generalized winding number of a given point with respect to mesh by
-- looping over the specified faces or all faces in a triangulated EditableMesh
function rng_mesh.generalized_winding_number_naive(triangulated_mesh: EditableMesh, point: Vector3, face_ids: {faceId}?): real
...
end
-- Constructs a BVH (bounding volume hierarchy) object that can then be used to compute winding numbers
function rng_mesh.construct_bvh(triangulated_mesh: EditableMesh)
...
end
-- Computes the generalized winding number of a given point with respect to mesh,
-- using the method described in the paper:
-- Jacobson, Alec et al. “Robust inside-outside segmentation using generalized winding numbers.”
-- * Use rng.mesh.construct_bvh(mesh) to get a BVH root node for the mesh
function rng_mesh.generalized_winding_number_bvh(triangulated_mesh: EditableMesh, point: Vector3, bvh_root: BvhNode): real
...
end
-- Determines if a given point is on the surface of a triangulated EditableMesh
function rng_mesh.is_point_on_mesh_surface(triangulated_mesh: EditableMesh, point: Vector3): boolean
...
end
-- Determines if a given point is within a specified maximum distance from the surface of an EditableMesh
function rng_mesh.is_point_close_to_mesh_surface(mesh: EditableMesh, point: Vector3, max_distance: non_negative_real): boolean
...
end
-- Determines if a point is inside a triangulated EditableMesh using generalized winding number with naive looping
function rng_mesh.is_point_in_mesh_wn(triangulated_mesh: EditableMesh, point: Vector3, threshold: real?): boolean
...
end
-- Determines if a point is inside a triangulated EditableMesh using generalized winding number with BVH
function rng_mesh.is_point_in_mesh_wb(triangulated_mesh: EditableMesh, point: Vector3, bvh_root: BvhNode, threshold: real?): boolean
...
end
-- Returns an arbitrary set of disjoint polygon loops formed by the boundary edges in a triangulated EditableMesh
function rng_mesh.boundary_loops(triangulated_mesh: EditableMesh, face_ids: {faceId}): {{vertexId}}
...
end
-- Returns the boundary edges in a triangulated EditableMesh
-- Boundary edges are the edges that are adjacent to exactly one triangle
function rng_mesh.boundary_edges(triangulated_mesh: EditableMesh, face_ids: {faceId}): {vertexId}
...
end
Unsigned integer arithmetics
These functions are stored in these submodules:
rng.u128
rng.u64
rng.u53
rng.u32
rng.f64
How to get the module?
Follow link to the module on creator store:
https://create.roblox.com/store/asset/80981260623012/RNG-Module-V2
Change Log
V2.0: initial release
V2.1: added rng.get interface & added documentation to every distribution
Polls
Do you think this module is useful?
- Yes
- No
If you have any suggestions, questions, feature requests, etc., please make sure to leave a comment below!