1. Home
2. Docs
3. PopcornFX v2.8
4. Scripting reference
5. Builtin functions

# Builtin functions

Function parameters enclosed in square brackets mean they are optional, and the function can be called without specifying that parameter.
The `#` character used when specifying types can either mean ‘any type’ when it is used alone, or ‘any dimension’ if it is after a scalar type.
For example, `float# lerp(float# a, float# b, float #t)` means the following overloads of `lerp` are available:

```float  lerp(float a, float b, float t);
float2 lerp(float2 a, float2 b, float2 t);
float3 lerp(float3 a, float3 b, float3 t);
float4 lerp(float4 a, float4 b, float4 t);```

Most functions on that page will appear with that notation, as they can be used with multiple types.

## Interpolation

Return typeDescription
`float#``step(float# x, float# y)`

Step function. evaluates to `0.0` if `x < y`, and evaluates to `1.0` if `x >= y`

[-∞, +∞] ⟶ [0, 1]

`float#``linearstep(float# a, float# b, float# x)`

Linearstep function. linearly evaluates between `0.0` to `1.0` the position of `x` between `a` and `b`.

[-∞, +∞] ⟶ [0, 1]

`float#``smoothstep(float# a, float# b, float# x)`

Smoothstep function. smoothly evaluates between `0.0` to `1.0` the position of `x` between `a` and `b`.

[-∞, +∞] ⟶ [0, 1]

`float#``lerp(float# a, float# b, float# t)`

Lineary blends between `a` and `b` based on the value of `t`.
`t` is an interpolation factor in the `[0, 1]` range. when `t` equals `0.0`, `a` is returned, when `t` equals `1.0`, `b` is returned. values in between return values between `a` and `b`.

Ex: `lerp(float3(0), float3(1,2,3), 0.5);` will return `float3(0.5, 1, 1.5)`.

`float#``smoothlerp(float# a, float# b, float# t)`

Smoothly blends between `a` and `b` based on the value of `t`.
`t` is an interpolation factor in the `[0, 1]` range. when `t` equals `0.0`, `a` is returned, when `t` equals `1.0`, `b` is returned. values in between return values between `a` and `b`.

Ex: `smoothlerp(float3(0), float3(1,2,3), 0.5);` will return `float3(0.5, 1, 1.5)`.

Equivalent to

`lerp(a, b, smoothstep(0, 1, t));`

Or

`lerp(a, b, 3*t*t - 2*t*t*t);`

## Random numbers

Return typeDescription
`float#``rand(a, b)`

Random function, returns a random value `r` uniformly distributed in the range `[a, b[`

`a <= r < b`

`#`
`#`
`randsel(a, b)`
`randsel(a, b, float# k)`

Randomly returns `a` or `b`.

The two-argument version of `randsel` has equal probability to return `a` or `b`, and calling `randsel(a, b);` is equivalent to calling `randsel(a, b, 0.5);`.
You can specify a custom probability to get either `a` or `b` by using the the three-argument version of `randsel`:
`randsel(a, b, 0.1);` will have a 10% chance of returning `b`, and a 90% chance of returning `a`
`randsel(a, b, 0.75);` will have a 75% chance of returning `b`, and a 25% chance of returning `a`The order of the parameters can be counter-intuitive, but you can think of it like `lerp(a,b,k)`, a value of `k` close to 0 will return values close to `a`, a value of `k` close to 1 will return values close to `b`. Same with `randsel(a,b,k)`, low values of `k` return `a` more often, high values return `b` more often.logic:

`select(a, b, rand(0,1) < k);`
`float`
`float#`
`randsign()`
`randsign(float# k)`

Randomly returns `-1.0` or `1.0`.
`randsign()` is equivalent to `randsel(-1.0, 1.0)`, or to `sign(rand(-1,1))`
The version of `randsign()` with no arguments has equal probability to return `-1.0` or `1.0`, and calling `randsign()` is equivalent to calling `randsign(0.5)`You can specify a custom probability to get either `-1.0` or `1.0` by using the the one-argument version:
`randsign(0.1);` will have a 10% chance of returning `1.0`, and a 90% chance of returning `-1.0`
`randsign(0.75);` will have a 75% chance of returning `1.0`, and a 25% chance of returning `-1.0`logic:

`select(-1.0, 1.0, rand(0,1) < k);`
`float3`
`float3`
`float3`
`vrand()`
`vrand(float inner, float outer)`
`vrand(float inner, float outer, curveResource probabilityCurve)`

Random function, stands for “vector-rand”, returns a random `float3` vector uniformly distributed on the unit sphere surface.
Very useful to generate nicely distributed random normals, random 3D offsets, or other unit vectors to give a bit of randomization to particle velocities, etc..      60k samples of vrand() vrand()*rand(0,1) vrand()*rand(0.5,1)

`vrand(inner, outer)` allows you to generate a point in a spherical shell instead of a sphere surface. ‘inner’ is the radius of the inner shell, ‘outer’ is the radius of the outer shell.

`vrand(1,1)` will give the same results as calling the classic `vrand()`. To generate a point inside the volume of a whole sphere, use `vrand(0,1)`.
It keeps correct uniform distribution of samples per unit volume.    vrand(0,1) vrand(0.5,1)

`vrand(inner, outer, probabilityCurve)` expects the name of a 1D curve sampler as third argument, which should have its `IsProbabilityCurve` property checked. It will use that curve as a probability distribution between the ‘inner’ and ‘outer’ radius and distribute the random samples accordingly.      vrand(0,1,MyCurve) vrand(0.5,1,MyCurve) ‘MyCurve’ Probability curve

## Noise

Return typeDescription
`float`
`float`
`noise(float# t)`
`fast.noise(float# t)`

Evaluates a coherent noise field. `t` can be a `float`, `float2`, `float3`, or `float4` cursor.

All functions return a single `float` value in the `[-1,1]` range.

`noise()` computes a high quality simplex-noise.
`fast.noise()` computes a slightly lower quality, but faster, noise.Ex:
`noise(LifeRatio);` will sample a 1D noise
`noise(uv * 100);` will sample a 2D noise
`noise(Position);` will sample a 3D noise
`noise(float4(Position, scene.Time));` will sample a 4D noise

`float#`
`float#`
`dnoise(float# t)`
`fast.dnoise(float# t)`

Evaluates the derivative of the coherent noise field returned by `noise(t)` or `dnoise(t)`.
`t` can be a `float`, `float2`, `float3`, or `float4` cursor.

The returned value is a vector of the same dimension as `t`, and is in the `]-∞,+∞[` range.

## Math constants

 Type Description `float` `pi`Constant pi π ~= 3.14159265359 `float` `phi`Constant phi φ ~= 1.61803398875 `float` `infinity`infinity: +∞

## Math functions

Return typeDescription
`float``dot(float# u, float# v)`

vector dot-product
`]-∞, +∞[ ⟶ ]-∞, +∞[`

`float3``cross(float3 u, float3 v)`

3D vector cross-product
`]-∞, +∞[ ⟶ ]-∞, +∞[`

`float3``reflect(float3 v,float3 n)`

Reflects (mirrors) the vector `v` on the plane defined by the normal `n`.
`]-∞, +∞[ ⟶ ]-∞, +∞[`

`#``abs(x)`

Returns the absolute value of `x` `[-∞, +∞] ⟶ [0, +∞]`

`#``sign(x)`
Sign function.
If `x` is a floating-point scalar or vector, returns `-1.0` when `x <= -0.0`, and `+1.0` when `x >= +0.0`
If `x` is an integer scalar or vector, returns `-1` when `x < 0`, and `+1` when `x >= 0` `[-∞, +∞] ⟶ [-1], [+1]`
`float#``ceil(float# x)`
Ceiling rounding: rounds to the closest integer value >= `x` `[-∞, +∞] ⟶ [-∞, +∞]`
`float#``floor(float# x)`
Floor rounding: rounds to the closest integer value <= `x` `[-∞, +∞] ⟶ [-∞, +∞]`
`float#``frac(float# x)`
Extracts the fractional part of `x` `[-∞, +∞[ ⟶ [0, 1[`
`float#``fracSign(float# x)`
Extracts the fractional part of `x`, preserving the sign. `[0, +∞[ ⟶ [0, 1[`
`]-∞, 0[ ⟶ ]-1, 0]`
`float#``wavesq(float# x)`
Square wave function `]-∞, +∞[ ⟶ [-1, 1]`
`float#``wavetri(float# x)`
Triangular wave function `]-∞, +∞[ ⟶ [0, 1]`
`float#``wavesaw(float# x)`
Sawtooth wave function `]-∞, +∞[ ⟶ [0, 1]`
`float#``discretize(float# x, float# y)`

Discretization function, snaps `x` to the nearest step, given a step size `y` `[-∞, +∞] ⟶ [-∞, +∞]`

`#``min(x,y)`

Minimization function: if `x < y`, returns `x`, otherwise, returns `y` `[-∞, +∞] ⟶ [-∞, y]`

`#``max(x,y)`

Maximization function: if `x > y`, returns `x`, otherwise, returns `y` `[-∞, +∞] ⟶ [y, +∞]`

`float#``clamp(x,a,b)`

Clamp function: if `x < a`, returns `a`, otherwise, if `x > b`, returns `b`, otherwise, returns `x` `[-∞, +∞] ⟶ [a, b]`

`float#``saturate(float# x)`

Clamps `x` in the `[0, 1]` range `[-∞, +∞] ⟶ [0, 1]`

`float#`
`float#`
`float#`
`sqrt(float# x)`
`fast.sqrt(float# x)`
`accurate.sqrt(float# x)`

Square-root function
The `fast` version is faster, but gives a lower precision result. `[0, +∞] ⟶ [0, +∞]`
`float#`
`float#`
`float#`
`rsqrt(float# x)`
`fast.rsqrt(float #x)`
`accurate.rsqrt(float #x)`

Reverse square-root
The `fast` version is faster, but gives a lower precision result. `[0, +∞] ⟶ [0, +∞]`
`float#`
`float#`
`float#`
`cbrt(float# x)`
`fast.cbrt(x)`
`accurate.cbrt(x)`

Cube root
The `fast` version is faster, but gives a lower precision result. `[0, +∞] ⟶ [0, +∞]`
`float`
`float`
`float`
`length(float# v)`
`fast.length(float# v)`
`accurate.length(float# v)`

Returns the length of vector `v`. Works with vectors from 1 to 4 dimensions.
The `fast` version is faster, but gives a lower precision result.
`[-∞, +∞] ⟶ [0, +∞]`
`float#`
`float#`
`float#`
`normalize(float# v)`
`fast.normalize(float# v)`
`accurate.normalize(float# v)`

Normalizes vector `v` (returns the unit vector pointing in the same direction). Works with vectors from 1 to 4 dimensions.
The `fast` version is faster, but gives a lower precision result.
`[-∞, +∞] ⟶ [-1, 1]`
`float#`
`float#`
`float#`
`exp(float# x)`
`fast.exp(float# x)`
`accurate.exp(float# x)`

Natural exponential.
Uses the fast namespace by default.
The `fast` version is faster, but gives a lower precision result.
`[-∞, +∞] ⟶ [0, +∞]`
`float#`
`float#`
`float#`
`exp2(float# x)`
`fast.exp2(float# x)`
`accurate.exp2(float# x)`

Base-2 exponential.
Uses the fast namespace by default.
The `fast` version is faster, but gives a lower precision result.
`[-∞, +∞] ⟶ [0, +∞]`
`float#`
`float#`
`float#`
`pow(float# x, float# y)`
`fast.pow(float# x,float# y)`
`accurate.pow(float# x,float# y)`

Power function.
The `fast` version is faster, but gives a lower precision result.
`{[0, +∞], [-∞, +∞]} ⟶ [-∞, +∞]`
`float#`
`float#`
`float#`
`log(float# x)`
`fast.log(float# x)`
`accurate.log(float# x)`

Natural logarithm.
The `fast` version is faster, but gives a lower precision result.
`[-∞, +∞] ⟶ [-∞, +∞]`
`float#`
`float#`
`float#`
`log2(float# x)`
`fast.log2(float# x)`
`accurate.log2(float# x)`

Base-2 logarithm.
The `fast` version is faster, but gives a lower precision result.
`[-∞, +∞] ⟶ [-∞, +∞]`
`float#`
`float#`
`float#`
`rcp(float# x)`
`fast.rcp(float# x)`
`accurate.rcp(float# x)`

Reciprocal function.
The `fast` version is faster, but gives a lower precision result.
`[-∞, +∞] ⟶ [-∞, +∞]`
`#``within(x, lower, upper)`

Returns `1.0` if `x` is within the `[lower, upper]` range, returns `0.0` otherwise.
All the function’s arguments can be either scalars, or vectors. if some arguments are vectors, they must have the same dimension. The return value will be a vector as large as the largest input vector.
IE: you cannot call `within(float2, float3, float4)`, but you can call `within(float, float, float4)` or `within(float3, float, float3)`

Ex:
`within(0.5, -1.2, 3.0);` will return `1.0`.
`within(float3(-2,0,2.5), -1.2, 3.0);` will return `float3(0.0, 1.0, 1.0)`.
`within(1.5, -1.0, float4(0,1,2,3));` will return `float4(0.0, 0.0, 1.0, 1.0)`.

`float#`
`float#`
`remap(value, newMin, newMax)`
`remap(value, oldMin, oldMax, newMin, newMax)`

Remaps `value` from the `[oldMin, oldMax]` range to the `[newMin, newMax]` range.
all the function’s arguments can be either scalars, or vectors. If some arguments are vectors, they must have the same dimension. The return value will be a vector as large as the largest input vector.
IE: you cannot call `remap(float2, float3, float4)`, but you can call `remap(float, float, float4)` or `remap(float3, float, float3)`
the version that has no ‘oldMin’ and ‘oldMax’ assumes the original range is `[0,1]`Ex:
`remap(0.5, 1.0, 3.0);` will return `2.0`.
`remap(0.5, 0, 0.5, 1.0, 3.0);` will return `3.0`.

`bool``all(bool# c)`

Returns `true` if ALL elements of vector `c` are `true`
`c` can be a boolean scalar or vector of any dimension.

Ex:
`all(float3(0) < float3(1,2,3));` will return `true`.
`all(float3(0) < float3(1,-2,3));` will return `false`.

`bool``any(bool# c)`

Returns `true` if ANY element of vector `c` is `true`
`c` can be a boolean scalar or vector of any dimension.

Ex:
`any(float3(0) > float3(1,2,3));` will return `false`.
`any(float3(0) > float3(1,-2,3));` will return `true`.

`#``bias(float# x, float# e)`

De-linearizes the input `x` by applying a power function based on value `e`.

`x` is expected to be in the `[0,1]` range, `e` has to be in the `[-1,1]` range.  `e = 0` : black (x) `e = +-0.3` : green `e = +-0.6` : yellow `e = +-0.85` : orange `e = +-0.99` : red
`float#`
`float#`
`safe_normalize(v[, vz, epsilon])`
`fast.safe_normalize(v[, vz, epsilon])`

Normalizes the input vector `v` and returns the resulting unit-vector. Unlike the `normalize` and `safe_normalize` builtins, these safe versions check for null vectors.
This will prevent normalizing a null vector and getting an Infinity or NaN vector in return.
Works on any vector dimensions.

Ex:
`safe_normalize(vector3);` returns `normalize(vector3)`, but if `length(vector3) < 1.0e-8`, returns `float3(0,0,0)`.
`safe_normalize(vector3, float3(0,1,0));` returns `normalize(vector3)`, but if `length(vector3) < 1.0e-8`, returns `float3(0,1,0)`.
`safe_normalize(vector3, float3(0,1,0), 1.0e-6);` returns `normalize(vector3)`, but if `length(vector3) < 1.0e-6`, returns `float3(0,1,0)`.`safe_normalize(vector3)`
is equivalent to:
`select(normalize(vector3), float3(0), length(vector3) < 1.0e-8);`

`float3`
`float3`
`float3`
`float3`
`float3suf(side, up, forward)`
`float3suf(...)`
`float3sfu(side, forward, up)`
`float3sfu(...)`

Takes the `side`, `up`, and `forward` components and permutes/swizzles them based on the current axis-System.
Accepts the same kind of arguments as the regular `float3` construction: you can pass a `float2` and a `float`, a `float3`, or three floats.Ex:

`float3suf(0, 18, 0);`
• Y-Up axis-system: `float3(0, 18, 0);`
• Z-Up axis-system: `float3(0, 0, 18);`

```float3 vec = float3(1, 2, 3);
res = float3suf(vec);```
• Y-Up axis-system: `res = vec;` (no changes)
• Z-Up axis-system: `res = vec.xzy;` (so: `float3(1, 3, 2)`)
`bool#``isfinite(float# v)`

Useful to detect infinite or invalid values.

`isfinite(v)` returns `true` if `v` is a finite value, `false` if not.

```isfinite(42);      --> true
isfinite(1.0/0.0); --> false
isfinite(0.0/0.0); --> false```

This function can be used to check the return values of some functions that return infinite values as a way to report en empty result.
For example, scene raycasts:

```float4 isec = scene.intersect(pos, dir, len);
float3 reflPos = pos + dir * isec.w + reflect(dir, isec.xyz) * (len - isec.w); // Bounced pos, will be invalid if no collision, as isec.w will be +inf
float3 endPos = pos + dir * len; // Unblocked end pos
pos = select(endPos, reflPos, isfinite(isec.w)); // If invalid, fallback to unblocked end pos```
`bool#``isinf(float# v)`

Useful to detect infinite or invalid values.
`isinf(v)` returns `true` if `v` is an infinite value, `false` if not (either finite or NaN).

```isinf(42);        --> false
isinf(1.0/0.0);   --> true
isinf(0.0/0.0);   --> false```

This function can be used to check the return values of some functions that return infinite values as a way to report en empty result.
For example, scene raycasts:

```float4 isec = scene.intersect(pos, dir, len);
float3 reflPos = pos + dir * isec.w + reflect(dir, isec.xyz) * (len - isec.w); // Bounced pos, will be invalid if no collision, as isec.w will be +inf
float3 endPos = pos + dir * len; // Unblocked end pos
pos = select(reflPos, endPos, isinf(isec.w)); // If invalid, fallback to unblocked end pos```
`bool#``isnan(float# v)`

Useful to detect infinite or invalid values.
`isnan(v)` returns `true` if `v` is a NaN value (NaN = “Not a Number”), `false` if not.

```isnan(42);        --> false
isnan(1.0/0.0);   --> false
isnan(0.0/0.0);   --> true```

`float#``asfloat(v)`

Reinterprets the input as a float. If given a float, does nothing. If given an int, will reinterpret its bits as if it was a float.
works on any vector, float to float4, int to int4, or orientation.

```asfloat(0x3F800000);     --> 1.0
asfloat(42.0);           --> 42.0
asfloat(int4(0x40490FDB, 0, 0xC0200000, -1071644672)) --> float4(3.141593, 0, -2.5, -2.5)```
`int#``asint(v)`

Reinterprets the input as an int. If given an int, does nothing. If given a float, will reinterpret its bits as if it was an int.
works on any vector, float to float4, int to int4.

```asint(1.0);              --> 0x3F800000
asint(42);               --> 42
asint(float4(3.141593, 0, -2.5, -2.5)) --> int4(0x40490FDB, 0, 0xC0200000, 0xC0200000)```
`orientation``asorientation(float4 v)`

Reinterprets the input as an orientation. If given an orientation, does nothing. If given a float4, will reinterpret its bits as if it was an orientation.

## Trigonometric functions

All trigonometric functions below are also available in the `fast` and `accurate` namespaces. `fast` versions are faster, but give a lower precision result. `accurate` versions are slower but give a higher-precision results. Functions in the root namespace without an explicit precision namespace will use the accurate namespace unless otherwise stated.

All trigonometric functions below are also available in the `degrees` and `radians sub-namespaces`, and will use the corresponding angle units. If an angle namespace isn’t explicitly specified, the functions will use `degrees` by default.

 Return type Description `float#` `sin(float# x)`Sine function.Uses the fast namespace by default. `]-∞, +∞[ ⟶ [-1, 1]` `float#` `cos(float# x)`Cosine functionUses the fast namespace by default. `]-∞, +∞[ ⟶ [-1, 1]` `float#` `tan(float# x)`Tangent function. `]-∞, +∞[ ⟶ [-∞, +∞]` `float#` `asin(float# x)`Arc-sine : returns the inverse of the `sin()` function : `asin(sin(x)) = x` The `fast` version is faster, but gives a lower precision result. `[-1, 1] ⟶ [-180, +180] | [-π, +π]` `float#` `acos(float# x)`Arc-cosine : returns the inverse of the `cos()` function : `acos(cos(x)) = x` `[-1, 1] ⟶ [-180, +180] | [-π, +π]` `float#` `atan(float# x)`Arc-tangent : returns the inverse of the `tan()` function : `atan(tan(x)) = x` `[-∞, +∞] ⟶ [-180, +180] | [-π, +π]` `float#` `atan2(float# x,float# y)`Signed arc-tangent: like `atan()`, but uses the sign of `y` to determine which quadrant the angle lies on `]-∞, +∞[ ⟶ [-180, +180] | [-π, +π]`

## Rotation, orientation, & angles

Return typeDescription
`float3`
`float3`
`float3`
`rotate(float3 v, float3 axis, float angle)`
`degrees.rotate(float3 v, float3 axis, float angle)`
`radians.rotate(float3 v, float3 axis, float angle)`

Returns the vector `v` rotated around `axis` by `angle`.
`v` and `axis` are float3 vectors, `angle` is the angle in degrees by default (can be negative).The functions in the `degrees` and `radians` namespace expect the `angle` input to be in that respective unit.Ex:
`rotate(float3(1,0,0), float3(0,1,0), 180);` will return `float3(-1,0,0)` (rotates `float3(1,0,0)` along the `y` axis `float3(0,1,0)` by 180 degrees, leading to the opposite vector `float3(-1,0,0)`.
`rotate(float3(1,0,0), float3(0,1,0), 90);` will return `float3(0,0,1)`.
`radians.rotate(float3(1,0,0), float3(0,1,0), pi);` will return `float3(-1,0,0)` (180 degrees rotation).
`radians.rotate(float3(1,0,0), float3(0,1,0), pi/2);` will return `float3(0,0,1)` (90 degrees rotation).

`float#``deg2rad(float# angle)`

`deg2rad(a)` converts the input angle `a` from degrees to radians.
`deg2rad(90);` will return `pi/2`.
`deg2rad(123.456);` will return `2.1547137`.

`float#``rad2deg(float# angle)`

`rad2deg(a)`converts the input angle `a` from radians to degrees.
`rad2deg(pi/2);` will return `90`.
`rad2deg(1.23456);` will return `70.735`.

`orientation``orientation_mult(orientation a, orientation b)`

Combines orientations `a` and `b`.
Transforming a vector by the returned orientation will be equivalent to transforming it by orientation `b`, then transforming the result by orientation `a`.

```float3 x = rotate(v, orientation_mult(a, b));
// Is equivalent to:
float3 x = rotate(rotate(v, b), a);```

It is useful to combine orientations coming from different sources, for example:

```orientation a = scene.orientation_f(Velocity); // rotation to orient "forward" to point towards "Velocity"
orientation b = scene.orientation_ea(float3suf(0, self.lifeRatio * 360*4, 0)); // spin along the Y axis over the lifetime of the particle
orientation x = orientation_mult(a, b); // combine both to get the final orientation
```

To create orientations, see the scene namespace.

`orientation``orientation_invert(orientation a)`

Inverts orientations `a`.
The returned orientation cancels out orientation `a`. Transforming a vector by `a`, then transforming the result by `orientation_invert(a)` will give back the original vector.
Multiplying orientation `a` with `orientation_invert(a)` will give the identity orientation (`scene.orientation_from_ea(0,0,0)`).
To create orientations, see the scene namespace.

## Colors

Return typeDescription
`float#`
`float#`
`float#`
`float#`
`linear2srgb(c)`
`srgb2linear(c)`
`fast.linear2srgb(c)`
`fast.srgb2linear(c)`

`linear2srgb(c)` converts the input color `c` from linear space to sRGB space.

`srgb2linear(v)`converts the input color `c` from sRGB space to linear space.

The ‘fast’ versions use an approximation (the absolute precision is under 0.001), whereas the non-fast versions use the real sRGB piecewise-curve conversion.Works for both `float3` RGB and `float4` RGBA values.

`float#`
`float#`
`rgb2hsv(c)`
`hsv2rgb(c)`
.`rgb2hsv(c)` converts the input color `c` from RGB space to HSV space.`hsv2rgb(v)`converts the input color `c` from HSV space to RGB space.The converters support HDR values.For the HSV color-space, the H-value (hue) is wrapped from 0 to 1 (1 means 360°), the S-value (saturation) is clipped from 0 to 1 and the V-value (intensity) is positive.Works for both `float3` RGB and `float4` RGBA values.
`float3`
`float3`
`blackbody(t)`
`fast.blackbody(t)`

Returns the normalized RGB chromaticity color of the emission spectrum of a blackbody at the specified temperatureThe input value should be a temperature in degrees kelvin. For example, 800 will give a red color, 3000 will give an orange/yellow color, 5000/6000 will give a white color, and higher temperatures will give a blue color. RGB colors returned are in linear space‘, not in sRGB space.
Can be very useful for ‘physically correct’ lava/fire effects.

The ‘fast’ version uses a different algorithm (a polynomial fit on the final RGB curves) than the regular version (which uses a polynomial fit of the chromaticity-space planckian locus), is roughly twice faster, but much less precise (although it’s probably fine for most applications).

Here’s the RGB comparison between the regular and fast versions: The two are virtually identical. Only when plotting the actual RGB curves you start seeing a difference:      `blackbody()` `fast.blackbody()` Rel. error times 10

## Conditional selection

Return typeDescription
`#``select(a, b, bool# c)`

Returns `a` or `b` depending on the value of `c`.

`c` should be the boolean result of a compare operation, or function returning `bool`.
`c` can a `bool`, `bool2`, `bool3`, or `bool4`.

Ex: `select(float3(0), float3(1,2,3), x <= y);` will return `float3(1,2,3)` if `x <= y`, otherwise it will return `float3(0)`.

`#``iif(bool# c, b, a)`

`iif`: Inline IFReturns `a` or `b` depending on the value of `c`. Like `select`, but reversed, syntactically closer to the syntax of an `if/else` block.`c` should be the boolean result of a compare operation, or function returning `bool`.
`c` can a `bool`, `bool2`, `bool3`, or `bool4`.Ex: `iif(x <= y, float3(1,2,3), float3(0));` will return `float3(1,2,3)` if `x <= y`, otherwise it will return `float3(0)`.

## Z-order curves

Return typeDescription
`int``morton_encode2(int2 a)`

Returns the 32-bit integer morton-encoded (z-order) representation of the 2D integer vector `a`.
Interleaves the bits from the 2 lanes of the input vector into groups of 2 bits in the output value.
As the return value is 32-bits, the input value should be in the `[0, 65535]` range.

`int``morton_encode3(int3 a)`

Returns the 32-bit integer morton-encoded (z-order) representation of the 3D integer vector `a`.
Interleaves the bits from the 3 lanes of the input vector into groups of 3 bits in the output value.
As the return value is 32-bits, the input value should be in the `[0, 1023]` range.

`int2``morton_decode2(int a)`

Returns the 2D integer vector resulting from decoding the morton-encoded (z-order) 32-bit integer value `a`.
De-interleaves groups of 2 bits into the 2 lanes of the output vector.
As the input value is 32-bits, the return value will be in the `[0, 65535]` range.

`int3``morton_decode3(int a)`

Returns the 3D integer vector resulting from decoding the morton-encoded (z-order) 32-bit integer value `a`.
De-interleaves groups of 3 bits into the 3 lanes of the output vector.
As the input value is 32-bits, the return value will be in the `[0, 1023]` range.

## Derivation & integration

Return typeDescription
`float#``dxdt(float# a)`

Returns the analytical time-based partial derivative of `a`.
It is a similar concept to `ddx()` and `ddy()` in shader languages, except it’s based on time instead of screen position.

Treats `a` as a function, finds all its parameters that vary based on time, and computes the partial derivative of that function over time.
It will walk all the expressions used to compute `a`, so this can walk back the script, and go back out into the nodegraph as well.

Example: Plugging the particle position into a script node, and doing `dxdt(Position)` will give the particle velocity.

If the compiler isn’t able to analytically derive `a`, it will fallback to the finite-difference `dxdT` function.
If the compiler is able to analytically integrate `a`, no additional per-particle storage will be created.

`float#``dxdT(float# a)`

Returns the finite-difference time-based partial derivative of `a`.
It is a similar concept to `ddx()` and `ddy()` in shader languages, except it’s based on time instead of screen position.

Treats `a` as a function with a time parameter, and computes `(a(t) - a(t - dt)) / dt`
Can be implemented manually by `dxdF(a) / scene.dt` (dxdT performs extra-checks when dt is zero)

Creates an additional per-particle storage to store the previous frame’s value of `a`: `a(t - dt)`.
Used as a fallback for `dxdt()` when the compiler is not able to compute an analytical derivative.

`float#``dxdF(float# a)`

Returns the frame-based partial derivative of `a`.
It is a similar concept to `ddx()` and `ddy()` in shader languages, except it’s based on frames instead of screen position.

Returns the value of `a` at the current frame, minus the value of `a` at the previous frame.

Example: Plugging the particle position into a script node, and doing `dxdF(Position)` will give the particle move-offset vector for this frame.

Creates an additional per-particle storage to store the previous frame’s value of `a`.

`float#``ixdt(float# a)`

Returns the analytical time-based integral of `a`.

If the compiler isn’t able to analytically integrate `a`, it will fallback to the `ixdT` function.
If the compiler is able to analytically integrate `a`, no additional per-particle storage will be created.

`float#``ixdT(float# a)`

Returns the time-based integral of `a` computed with cumulative summations each frame.

Creates an additional per-particle storage to store the accumulator.