Play around with the Chaos game in 3D!

3D Controls:

• Orbit: Left click + drag
• Zoom: Mouse wheel
• Pan: Right click + drag
Customize the "next point" code
Write your own code to calculate where the next point should be, by setting the nextPoint variable to vector, ex. nextPoint = [100, 200, 300]. The default code simply picks one of the targets at random and moves the current point halfway there, but you can change that using functions, operators, and whatever else you can find in MathJS. You can use the coordinates of the current point, currentPoint, and the coordinates of each target, targetPoints. Both are matrices.

In the default initialization code you will see uses of the createSlider() function. This creates a slider that controls a number. This function should usually be used in the initialization code. Example: t = createSlider("some number", -1, 4, 2) will create a slider ranging over -1 to 4 and starting at 2. Then ex. nextPoint = currentPoint + t in your code gives your end user 'live' control over the scalar value, t.

Show examples

Examples:

Add 1 to x, y, and z:
nextPoint = currentPoint + 1
Go to midpoint, then rotate around z axis:
nextTargetIndex = math.randomInt(1, targetPointsLength+1)
nextTarget = targetPoints[nextTargetIndex, :]
midpoint = (currentPoint + nextTarget) / 2
# Rotation around Z axis
rotation = [[math.cos(math.pi/4), -math.sin(math.pi/4), 0],
            [math.sin(math.pi/4), math.cos(math.pi/4), 0],
            [0, 0, 1]]
nextPoint = math.multiply(midpoint, rotation)
Show advanced
  • write()   Write text to the page. Example: write("currentPoint:", currentPoint)
  • Advanced use of createSlider()   Optionally you can specifiy a 5th parameter which, when false, prevents the existing points from being cleared when the user slides the slider. Example: slider = createSlider("rotation", 0, pi*2, 0, false). You can also pass arbitrary arguments to noUiSlider.create() by using a Javascript object as the 5th parameter, like {step: 0.01} to set a custom step increment.
  • Saving data for the next iteration   Variables set in one iteration are available in subsequent iterations. See "Avoid previous target" in the advanced examples, below.
  • opacity   Setting this variable controls point transparency. Range: 0.0 (fully transparent) to 1.0 (fully opaque). Lower values help visualize point density. Example: opacity = 0.3.
  • pointsCount   Setting this variable in the initialization code controls the total number of points to generate. Higher values produce more detailed fractals. Example: pointsCount = 2000000.
  • targetsCount   Setting this variable in the initialization code controls the number of target vertices in targetPoints. Default targets are distributed evenly on the unit sphere. Example: targetsCount = 6.
  • nextPointColor   If you set this variable to, ex. [255, 0, 0], the next point will be plotted in red. Example: nextPointColor = [111, 200, 15]. You can optionally add a fourth element, the opacity (aka alpha), a number between 0 and 1. Example: nextPointColor = [111, 200, 15, 0.3]. The default opacity is 1.0.
Advanced example - Avoid previous target:
# IMPORTANT! Put these two lines in the "Initialization code" pane.
previous_target = -1  # start with a non-existing target
slider = createSlider("how far to go toward the target", -2, 1.4, 0.5)

# Put the rest of the code in the main pane

# Get all possible indices except the target we used in the last iteration
possibleTargetIndices = math.range(1, targetPointsLength+1)
possibleTargetIndices = possibleTargetIndices[possibleTargetIndices != previous_target]

nextTargetIndex = math.pickRandom(possibleTargetIndices)
nextTarget = targetPoints[nextTargetIndex, :]
nextPoint = currentPoint + (nextTarget - currentPoint) * slider

# Store current target for next iteration
previous_target = nextTargetIndex
Advanced example - The Corcoran Attractor:
# Put this chunk in the "Initialization code" pane.
currentPoint = [100, 100, 100]  # arbitrary starting point
targetsCount = createSlider("Targets", 1, 16, 6, {step: 1, display: "inline"})
pointsCount = createSlider("Points", 0, 300000, 100000, {step: 1, display: "inline"})
opacity = createSlider("Opacity (0.0 - 1.0)", .01, 1, 1, {step: 0.01, display: "inline"})
phase_offset = createSlider("Phase offset", 0, 2*math.pi, 5/2)
amplitude = createSlider("Amplitude", -3/2, 4, 1/2, {display: "inline"})
bias = createSlider("Bias", -1, 7/4, 1/2, {display: "inline"})

# Put the rest of the code in the main pane
nextTargetIndex = math.randomInt(1, targetPointsLength+1)
nextTarget = targetPoints[nextTargetIndex, :]
displacement_factors = math.matrix([math.sin(nextTarget[2] + phase_offset) * amplitude + bias,   math.sin(nextTarget[1] + phase_offset) * amplitude + bias, math.sin(nextTarget[3] + phase_offset) * amplitude + bias])
# Apply the factors to the displacement
displacement_to_target = nextTarget - currentPoint
nextPoint = currentPoint + math.dotMultiply(displacement_to_target, displacement_factors)



source   2D version