'Arrange SCNNodes in Circle

I'm creating multiple nodes automatically and I want to arrange them around me, because at the moment I'm just increasing of 0.1 the current X location.

capsuleNode.geometry?.firstMaterial?.diffuse.contents = imageView
capsuleNode.position = SCNVector3(self.counterX, self.counterY, self.counterZ)
capsuleNode.name = topic.name
self.sceneLocationView.scene.rootNode.addChildNode(capsuleNode)
self.counterX += 0.1

So the question is, how can I have all of them around me instead of just in one line?

Did someone of you have some math function for this? Thank you!



Solution 1:[1]

Use this code (macOS version) to test it:

import SceneKit

class GameViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let scene = SCNScene()
        let scnView = self.view as! SCNView
        scnView.scene = scene
        scnView.allowsCameraControl = true
        scnView.backgroundColor = NSColor.black

        for i in 1...12 {  // HERE ARE 12 SPHERES

            let sphereNode = SCNNode(geometry: SCNSphere(radius: 1))
            sphereNode.position = SCNVector3(0, 0, 0)

            // ROTATE ABOUT THIS OFFSET PIVOT POINT
            sphereNode.simdPivot.columns.3.x = 5
            sphereNode.geometry?.firstMaterial?.diffuse.contents = NSColor(calibratedHue: CGFloat(i)/12, 
                                                                              saturation: 1, 
                                                                              brightness: 1,                
                                                                                   alpha: 1)

            // ROTATE ABOUT Y AXIS (STEP is 30 DEGREES EXPRESSED IN RADIANS)
            sphereNode.rotation = SCNVector4(0, 1, 0, (-CGFloat.pi * CGFloat(i))/6)
            scene.rootNode.addChildNode(sphereNode)
        }
    }
}

enter image description here

enter image description here

P.S. Here's a code for creating 90 spheres:

for i in 1...90 {

    let sphereNode = SCNNode(geometry: SCNSphere(radius: 0.1))
    sphereNode.position = SCNVector3(0, 0, 0)
    sphereNode.simdPivot.columns.3.x = 5
    sphereNode.geometry?.firstMaterial?.diffuse.contents = NSColor(calibratedHue: CGFloat(i)/90, saturation: 1, brightness: 1, alpha: 1)
    sphereNode.rotation = SCNVector4(0, 1, 0, (-CGFloat.pi * (CGFloat(i))/6)/7.5)
    scene.rootNode.addChildNode(sphereNode)
}

enter image description here

Solution 2:[2]

You need some math here

How I prepare the circle nodes

    var nodes = [SCNNode]()
    for i in  1...20 {
        let node = createSphereNode(withRadius: 0.05, color: .yellow)
        nodes.append(node)
        node.position = SCNVector3(0,0,-1 * 1 / i)
        scene.rootNode.addChildNode(node)
    }

    DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
        self.arrangeNode(nodes: nodes)
    }


   func createSphereNode(withRadius radius: CGFloat, color: UIColor) -> SCNNode {
        let geometry = SCNSphere(radius: radius)
        geometry.firstMaterial?.diffuse.contents = color
        let sphereNode = SCNNode(geometry: geometry)
        return sphereNode
   }

Math behind arrange the view into circle

func arrangeNode(nodes:[SCNNode]) {

        let radius:CGFloat = 1;

        let angleStep = 2.0 * CGFloat.pi / CGFloat(nodes.count)

        var count:Int = 0

        for node in nodes {
            let xPos:CGFloat = CGFloat(self.sceneView.pointOfView?.position.x ?? 0) + CGFloat(cosf(Float(angleStep) * Float(count))) * (radius - 0)
            let zPos:CGFloat = CGFloat(self.sceneView.pointOfView?.position.z ?? 0) + CGFloat(sinf(Float(angleStep) * Float(count))) * (radius - 0)

            node.position = SCNVector3(xPos, 0, zPos)

            count = count + 1
        }


    }

Note: In third image I have set.

            let xPos:CGFloat =  -1 + CGFloat(cosf(Float(angleStep) * Float(count))) * (radius - 0)
            let zPos:CGFloat = -1 + CGFloat(sinf(Float(angleStep) * Float(count))) * (radius - 0)

That means if you need view around the camera then

use CGFloat(self.sceneView.pointOfView?.position.x ?? 0) or at the random place then provide the value

Output

enter image description here enter image description here

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2