Tutorial: Dynamic Object Formations in MiniScript – A Case Study

1. Introduction

This tutorial covers the implementation of dynamic object formations in the MiniScript environment with XRXplorer. The goal is to demonstrate the transformation of a set of 3D objects (cubes) from an initial grid structure into a spherical arrangement and back. In doing so, fundamental concepts of 3D graphics programming, such as transformations, time management, and mathematical interpolation, will be explored in depth.

MiniScript is a lightweight scripting language designed for embedded applications. It offers clear syntax and fundamental mathematical functions that are essential for manipulating objects in a 3D environment.

2. Fundamentals of 3D Transformations

In 3D environments, objects are positioned, oriented, and scaled through transformations in space. Each object has a “transformation matrix” that defines its position (translation), rotation, and scale in world space.

  • Position (Translation): Describes an object’s location in 3D space (X, Y, Z coordinates).
  • Scale: Defines an object’s size along its axes.
  • Rotation: Describes an object’s orientation in space.

In XRXplorer these transformations are directly applied using specific commands such as moveObject and scaleObject. Understanding whether these commands operate in the global world coordinate system or in a local, hierarchical system (parenting) is crucial. In this case study, we assume that moveObject positions objects directly in global space.

3. The Concept of Interpolation (Lerp)

To achieve a smooth transition between two states (here: grid formation and sphere formation), linear interpolation (often referred to as “Lerp”) is used. Lerp calculates an intermediate value between two given values based on an interpolation factor, which typically ranges from 0 to 1.

The formula for linear interpolation between two values A and B with a factor t is: Value=Acdot(1−t)+Bcdott

  • If t=0, the Value=A.
  • If t=1, the Value=B.
  • For 0\<t\<1, the Value is proportionally between A and B.

This can be applied to 3D vectors (positions) by interpolating each component (X, Y, Z) separately.

4. Mathematical Foundations of Sphere Distribution

To distribute 100 cubes approximately evenly on the surface of a sphere, a method based on the Golden Angle is used. This is an efficient way to distribute points spirally on a sphere’s surface without requiring complex algorithms for exact sphere packing.

The formulas for the position of a point (x, y, z) on a sphere with radius R for the i-th point (out of N points) are:

  • Golden Angle (phi): phi=picdot(3−sqrt5)
  • Y-Coordinate: y=1−(i/(N−1))cdot2 (distributes y from 1 to −1)
  • Radius in XY-Plane (r_xy): r_xy=sqrt1−y2cdotR
  • Angle around the Y-axis (alpha): alpha=phicdoti
  • X-Coordinate: x=r_xycdotcos(alpha)
  • Z-Coordinate: z=r_xycdotsin(alpha)

These calculations allow the cubes to be placed in an appealing spherical arrangement.

5. Analysis of the MiniScript Code

Let’s now examine the MiniScript code for the “Cube-Sphere Formation Animation” in detail:

numCubes = 100
cubeBaseName = "Cube"
cubeScale = 0.25 // Uniform scaling for all cubes

// Grid Parameters (Start/End Position)
gridSize = 10 // 10x10 Grid
initialSpacing = 0.5 // Spacing between cubes in the grid
gridYPos = 0.5 // Fixed Y-position of the grid

// Sphere Parameters (Target Formation)
sphereRadius = 4 // Radius of the sphere formation
sphereYPos = 2   // Y-position of the sphere formation

// Animation Parameters
animationDuration = 5 // Duration of an animation phase (Grid to Sphere or Sphere to Grid)
animationSpeed = 1    // Overall animation speed

cubeNames = []
for i in range(1, numCubes)
    cubeNames.push(cubeBaseName + i)
end for

// Initial scaling of all cubes
for i in range(0, numCubes - 1)
    currentCubeName = cubeNames[i]
    scaleObject currentCubeName, cubeScale, cubeScale, cubeScale
end for

// Main animation loop for the sphere formation

while true
    currentTime = time

    // Phase Calculation: Switch between Grid -> Sphere and Sphere -> Grid
    // Modulo 2 * animationDuration to divide time into phases

    phaseTime = currentTime * animationSpeed % (2 * animationDuration)

    // Interpolation factor (from 0 to 1 and back)
    // If phaseTime < animationDuration: Grid to Sphere (factor from 0 to 1)
    // If phaseTime >= animationDuration: Sphere to Grid (factor from 1 to 0)

    interpFactor = 0
    if phaseTime < animationDuration then
        interpFactor = phaseTime / animationDuration
    else
        interpFactor = 1 - ((phaseTime - animationDuration) / animationDuration)
    end if

    for i in range(0, numCubes - 1)
        currentCubeName = cubeNames[i]

        // 1. Grid Start Position (independent of expansion)

        row = floor(i / gridSize)
        col = i % gridSize
        gridPosX = (col - (gridSize - 1) / 2) * initialSpacing
        gridPosZ = (row - (gridSize - 1) / 2) * initialSpacing

        // 2. Sphere Target Position
        // Even distribution of cubes on a sphere surface
        // (Approximation: Fibonacci grid or spiral arrangement on sphere)
        // Here, a simple spiral arrangement for 100 points on a sphere

        goldenAngle = pi * (3 - sqrt(5)) // Golden angle in radians
        y = 1 - (i / (numCubes - 1)) * 2 // Y from 1 to -1
        radiusAtY = sqrt(1 - y*y) * sphereRadius
        angle = goldenAngle * i

        spherePosX = radiusAtY * cos(angle)
        spherePosY = y * sphereRadius
        spherePosZ = radiusAtY * sin(angle)

        // Interpolation between grid and sphere position
        // lerp = linear interpolation

        finalPosX = gridPosX * (1 - interpFactor) + spherePosX * interpFactor
        finalPosY = gridYPos * (1 - interpFactor) + spherePosY * interpFactor
        finalPosZ = gridPosZ * (1 - interpFactor) + spherePosZ * interpFactor

        moveObject currentCubeName, finalPosX, finalPosY, finalPosZ
    end for
end while

5.1. Initialization and Parameters (Lines 1-28)

  • numCubes, cubeBaseName, cubeScale: Define the number, name prefix, and size of the cubes.
  • gridSize, initialSpacing, gridYPos: Set the dimensions and Y-position of the initial grid formation.
    • gridSize = 10 means a 10×10 grid for 100 cubes.
    • initialSpacing is the spacing between cubes in the grid.
  • sphereRadius, sphereYPos: Determine the radius and Y-position of the target sphere formation.
  • animationDuration, animationSpeed: Control the duration of a single transformation phase (e.g., grid to sphere) and the overall animation speed.
  • The loops for populating cubeNames and for initial scaleObject application are standard procedures.

5.2. Main Animation Loop and Phase Calculation (Lines 31-44)

  • while true: An infinite loop that continuously runs the animation.
  • currentTime = time: Retrieves the current system time. time is an intrinsic MiniScript function that returns seconds since program start.
  • phaseTime = currentTime * animationSpeed % (2 * animationDuration):
    • currentTime * animationSpeed: Scales time to control the overall animation speed.
    • % (2 * animationDuration): The modulo operator ensures that phaseTime always remains in the range of 0 to 2 * animationDuration. This divides the animation into recurring cycles (e.g., 0–10 seconds for one cycle if animationDuration is 5).
  • Interpolation Factor (interpFactor):
    • This factor controls the transition between the grid and sphere formations.
    • If phaseTime is less than animationDuration (first half of the cycle: grid to sphere), interpFactor increases linearly from 0 to 1.
    • If phaseTime is greater than or equal to animationDuration (second half of the cycle: sphere to grid), interpFactor decreases linearly from 1 to 0.

5.3. Position Calculation for Grid and Sphere (Lines 46-70)

Within the for loop for each cube, two target positions are calculated:

  • Grid Position (gridPosX, gridPosZ):
    • row = floor(i / gridSize) and col = i % gridSize: Calculate the row and column of the current cube in the grid.
    • The formulas (col - (gridSize - 1) / 2) * initialSpacing and (row - (gridSize - 1) / 2) * initialSpacing center the grid around the origin (0,0) of the XZ plane.
  • Sphere Position (spherePosX, spherePosY, spherePosZ):
    • goldenAngle = pi * (3 - sqrt(5)): Defines the Golden Angle for spiral distribution.
    • y = 1 - (i / (numCubes - 1)) * 2: Calculates the Y-coordinate of the point on the sphere, distributed linearly from 1 to -1 over the number of cubes.
    • radiusAtY = sqrt(1 - y*y) * sphereRadius: Calculates the radius of the circle on the Y-plane, used for the XZ position of the point on the sphere.
    • angle = goldenAngle * i: Calculates the angle around the Y-axis for the current point in the spiral.
    • spherePosX = radiusAtY * cos(angle) and spherePosZ = radiusAtY * sin(angle): Calculate the X and Z coordinates on the circle at the respective Y-plane.
    • spherePosY = y * sphereRadius: Scales the Y-coordinate to the sphere radius.

5.4. Interpolation and Application of Transformation (Lines 72-78)

  • finalPosX = gridPosX * (1 - interpFactor) + spherePosX * interpFactor (and similarly for Y and Z):
    • This is the application of linear interpolation. The final position of each cube is a blend of its grid position and its sphere position, controlled by the interpFactor.
    • Note that finalPosY is also interpolated between gridYPos and spherePosY to control the Y-transition.
  • moveObject currentCubeName, finalPosX, finalPosY, finalPosZ: Moves the cube to the calculated interpolated position.

6. Implementation and Customization

  1. Galaxies Preparation: Ensure that 100 cubes are present in your scene and are named exactly from Cube1 to Cube100. Their initial position is not critical for this script, as they will be immediately repositioned.
  2. Insert Script: Copy the entire MiniScript code into the designated editor of your galaxy.
  3. Parameter Adjustment: Experiment with the values of the variables in the upper section of the script (gridSize, initialSpacing, sphereRadius, animationDuration, animationSpeed). Smaller animationDuration values lead to faster transitions, higher values to slower ones.
  4. Execution: Start the script in your galaxy. The cubes should now continuously move between the grid and sphere formations.

7. Conclusion

This tutorial has demonstrated how complex dynamic object formations can be realized in MiniScript by combining mathematical principles (sine, cosine, Golden Angle) and the concept of linear interpolation. Such effects can be achieved through precise mathematical calculations in global space. Understanding the underlying algorithms is crucial for creating compelling and dynamic 3D scenes.

8. Download

data string: formation.txt

Scroll to Top