Lua scripting

SpaceSim allows you to create custom objects or simulation systems using the Lua language.

Scripted objects

Example:

You can try adding a scripted object by copying the script below, or by downloading it.
require("math")

-- Name of this object. This will be the label of the button added to 'Custom objects'.
objectName = "Color cloud";

-- Table of object parameters that will be shown in the UI.
parameters = {}

parameters.radius = Constants.R_Earth;
parameters.density = 10000;
parameters.spinRate = 0.0004;
parameters.particleScale = 0.01;

-- Returns the total volume of the object. This function is used to determine 
-- how many particles are assigned to the object.
function getVolume()
    return 0.02 * math.pi * math.pow(parameters.radius, 3);
end

-- Returns the total mass of the object.
function getTotalMass()
    return getVolume() * parameters.density;
end

math.randomseed(os.time())

-- Main entry point of the script. The function will create a table containing 
-- all particle data of the object.
function generate(n)
    state = {}
    state.position = {};
    state.velocity = {};
    state.mass = {};
    state.density = {};
    state.radius = {};
    state.color = {};

    phi = 2 * math.pi / n;
    for i=1,n
    do
        r = math.pow(math.random(), 0.66) * parameters.radius;
        v = r * parameters.spinRate;
        state.position[i] = { r * math.cos(phi * i),
                              r * math.sin(phi * i),
                              0.01 * parameters.radius * (math.random(-1, 1)) };
        state.velocity[i] = { v * math.sin(phi * i),
                              -v * math.cos(phi * i),
                              0 };
        state.radius[i] = parameters.particleScale * Constants.R_Earth;
        state.density[i] = parameters.density;
        state.mass[i] = parameters.density * 4.0/3.0 * math.pi * math.pow(state.radius[i], 3);
        state.color[i] = { state.position[i][1] / r,
                           0.5,
                           state.position[i][2] / r };
    end
    
    return state;
end

Script functions

The script must define the following mandatory functions.
generate(N)Function creating particles. Takes the number of particles as an input parameter.
getTotalMassReturns the total mass of the object.
getVolumeReturn the total volume of the object.

Quantities

Script function generate has to return a table containing the particle quantities. All quantities are assumed to be in SI units (meters, kilograms, Joules, etc.). The following quantities are mandatory and have to be returned by the function for the object to work:
positionPositions of all particles
velocityVelocities of all particles
massParticle masses
radiusParticle radii
Optionally, the script can also return additional quantities, namely:
densityParticle densities
colorDiffuse color of particles
temperatureTemperatures, used to calculate the glow color
energyInitial specific internal energy, used by the SPH solver
normalInitial surface normal of particles
uvTexturing coordinates, a table containing two values in the interval [0, 1].
If the density specified, the object enables the hydrodynamic solver and handles particle collisions, otherwise a pure gravity solver solver is used for the simulation.

Variables

Optionally, the script can define a global table named parameters, containing key-value pairs. If used, the values will appear in the object panel and can be modified along other object properties, such as position or rotation. Currently, only number parameters are supported. Values of different types are ignored.
The script can also define the following variables:
objectNameName of the object in the "Add object" panel

Constants

The script can use a few useful constants, defined in the global table Constants.
R_EarthEarth radius
R_SunSolar radius
auAstronomical unit
M_EarthEarth mass
M_SunSolar mass

Object repository

List of Lua objects you can use as a starting point for your own experiments:
spherical_planet.luaSimple spherical planet, set up similarly to the built-in SpaceSim planets.

Scripted simulation systems

Example:

You can try adding a scripted system by copying the script below, or by downloading it.
require("math")

-- Simple system that explodes the largest object in the simulation.

-- Initialize all quantities used by the script.
-- These quantities will be updated by the simulation every time the script is run.
-- All quantities are in SI units (meters, kilograms, Kelvins, ...).
-- For the list of available quantities, see https://pavelsevecek.github.io/lua.html
-- This is a mandatory field.
particles = {};
particles.mass = {}
particles.position = {}
particles.velocity = {}
particles.island_index = {}
particles.temperature = {}

-- Names of all quantities changed by the script.
-- These quantities are copied back to the simulation after the script returns.
-- This is a mandatory field.
update_quantities = {"velocity", "temperature" }; 

-- Optional parameters of the system.
-- The parameters can be changed in the simulation settings after compiling the script.
parameters = {}
parameters.explosion_velocity = 0.005;
parameters.heating = 2000;

-- Main entry point of the script.

-- Called with period set in the simulation settings. If the period is 0,
-- the function is called every time step.
-- Parameters:
-- t - Current simulation time (in seconds)
-- dt - Current time step (in seconds);
function onTimeStep(t, dt)
    local island_counts = {};
    for i = 1, #particles.island_index
    do
        local island = particles.island_index[i];
        if island_counts[island] == nil then
            island_counts[island] = 1;
        else
            island_counts[island] = island_counts[island] + 1;
        end
    end
    local largest_island = 0;
    local max_count = 0;
    for island, count in pairs(island_counts) do
        if count > max_count then
            largest_island = island;
            max_count = count;
        end
    end
    
    local x_com = 0;
    local y_com = 0;
    local z_com = 0;
    local mass = 0;
    for i = 1, #particles.island_index
    do
        if particles.island_index[i] == largest_island then
            local m = particles.mass[i];
            local r = particles.position[i];
            x_com = x_com + m * r[1];
            y_com = y_com + m * r[2];
            z_com = z_com + m * r[3];
            mass = mass + m;
        end
    end
    x_com = x_com / mass;
    y_com = y_com / mass;
    z_com = z_com / mass;
    local v = parameters.explosion_velocity;
    for i = 1, #particles.island_index
    do
        if particles.island_index[i] == largest_island then
            local r = particles.position[i];
            particles.velocity[i] =
            {
              (r[1] - x_com) * v,
              (r[2] - y_com) * v,
              (r[3] - z_com) * v
            };
            particles.temperature[i] = particles.temperature[i] + parameters.heating;
        end
    end
end

Script functions

The script must define the following mandatory function.
onTimeStep(t, dt)Function called with the period set in the script settings.

Particles

Particle quantities can be read from (and written into) the global table particles. The script can read and modify any of the following quantities:
positionPositions of all particles
velocityVelocities of all particles
accelerationAccelerations of all particles
massParticle masses
radiusParticle radii
densityParticle densities
pressurePressure at the particle position
colorDiffuse color of particles
temperatureTemperatures, used to calculate the glow color
energyInitial specific internal energy, used by the SPH solver
phaseCurrent particle phase, 0 for solid and 1 for gas.
normalInitial surface normal of particles
uvTexturing coordinates, a table containing two values in the interval [0, 1].
body_indexIndex of the original object.
island_indexIndex of the current object.
material_indexMaterial index.

Rigid bodies

The script can also read and modify the state of rigid (non-deformable) objects by accessing the global table rigid. Each rigid object has the following quantities:
positionObject position.
velocityObject velocity.
rotationObject rotation given by Euler angles (in degrees).
spin_rateCurrent spin vector (in units deg/s).
temperatureSurface temperature.