5. Nested Circles


In this exercise, we will place objects on a decreasing circular path to create nested circles. If you are unfamiliar with the basics, please go through the Circle of Objects and Grid 3D exercises first.

Nested Circles Codepen: https://codepen.io/xrclub/full/RwQGYQo

Getting Started: https://xr.club/exercise/getting-started/

Nested Circles

The scene, camera, lighting, and renderer need to be set up beforehand, as in the Getting Started exercise. If you need help remembering how it all works, check that exercise out before starting. Here, we will just focus on creating the nested circles 3D scene.

Here are the instructions:

  1. define circle radius and cube counts
  2. calculate space between nested circles
  3. set up cube geometry and material  
  4. create cube objects inside nested loop
  5. calculate z position
  6. calculate position angle and current radius
  7. set new x & y position

Step 1: define circle radius and cube counts

Begin by defining the basic parameters necessary, such as the circle radius and cube counts. Use additional parameters, start and end radius, to help create the nested circles. Current circle radius will initially be set to zero and will be updated later.

// Set up nested circle parameters
this.numberOfCubesPerCircle = 30;
this.startRadius = 20;
this.endRadius = 5;
this.currentCircleRadius = 0;

Step 2: calculate space between nested circles

Stacking nested circles will require the number of circles and the depth in the Z Axis to be determined first. The space between each circle can the be calculated by dividing the overall depth in the Z axis by the number spaces in between, which can be identified as the number of circles – 1.

// Define depth in the Z-axis, number of circles and space between each circle
this.totalDepthInZAxis = 40;
this.numberOfCircles = 5;
this.spaceBetweenCircles = this.totalDepthInZAxis / (this.numberOfCircles - 1);

Step 3: set up cube geometry and material   

Create geometry and material for the cube object. Will be referenced in the next step to create the cube object.

// Creating cube geometry and material
const cubeGeometry = new THREE.BoxGeometry( 2, 2, 2 );
const cubeMaterial = new THREE.MeshStandardMaterial( { color: 0xffffff } 

Step 4: create cube objects inside nested loop 

Create an outer loop that iterate through each nested circle, this will be based on the number of circles defined earlier. For each circle, the inner loop will generate a cube object mesh using the cube geometry and material. Add cube objects to the scene.

// Loop through each nested circle 
for (let currentCircleIndex = 0; currentCircleIndex < this.numberOfCircles; currentCircleIndex++) {

    // Loop through each cube in the current circle
    for (let currentCubeIndex = 0; currentCubeIndex < this.numberOfCubesPerCircle; currentCubeIndex++) {
        let cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

Step 5: calculate z position

In the outer loop calculate the cube’s Z position by multiplying the space between circles by the circle index. Set this value to be negative so that each circle moves in the Z direction, where decreasing nested circles are stacked inside the bigger circle. Within the inner loop set the cube’s Z position. Try removing the minus to see the difference !

// Compute the Z position for each circle
let zPosition = -(currentCircleIndex * this.spaceBetweenCircles);

// Set cube's Z position
cube.position.z = zPosition;

Step 6: calculate position angle and current radius

Within the inner loop, calculate the current progress of the loops, by dividing the cube index by the total object count. Next, determine the angle for positioning objects on a circular path. Multiply this value by 2 PI so the output can be measured in radians. Following the same approach, calculate the circle progress. Determine the current radius by multiplying the circle progress by the difference between the start & end radius. Lastly, add this difference to the start radius.

// Calculate the progress of each cube within a circle and each circle within the pattern
let cubeProgressWithinCircle = currentCubeIndex / this.numberOfCubesPerCircle;
let circleProgressWithinPattern = currentCircleIndex / this.numberOfCircles; 

// Calculate the angle in radians and update the current circle radius based on the circle's progress
let cubeAngleInRadians = (Math.PI * 2) * cubeProgressWithinCircle;       
this.currentCircleRadius = this.startRadius + (this.endRadius - this.startRadius) * circleProgressWithinPattern;

Step 7: set new x & y position

Calculate the cube’s X position by multiplying each circle’s radius with the cosine of the angle. Alternatively, use the sine of the angle for calculating the Y position instead. Set new X & Y positions for the cube.

// Calculate the cube's X position by multiplying each circle's radius with the cosine of the angle. Alternatively, use the sine of the angle for calculating the Y position instead. Set cube's X & Y positions
cube.position.x = Math.cos(cubeAngleInRadians) * this.currentCircleRadius;
cube.position.y = Math.sin(cubeAngleInRadians) * this.currentCircleRadius;


See the Pen Loops – 2D Nested Circles by XR Club (@xrclub) on CodePen.

Leave a Reply

Your email address will not be published.