OK, took a while. Here is a greatly reduced bit of code that should, but does not show my nodes.
// ContentView.swift
// SendToForum
//
// Created on 1/25/25.
//
import SwiftUI
import SceneKit
struct ContentView: View {
@State private var fs_cv = "2"
private let scene = makeAScene()
private struct box: Identifiable {
let radius: Int
let position: [simd_float3]
var id: String { String(radius) }
}
private let boxFlake:[box] = [
box(radius: 0, position: [ simd_float3(0, 0, 0)]),
box(radius: 1, position: [ simd_float3(0, 1, 0),
simd_float3(0, -1, 0),
simd_float3(1, 0, 0),
simd_float3(-1, 0, 0) ]),
box(radius: 2, position: [ simd_float3(0, 2, 0),
simd_float3(0, -2, 0),
simd_float3(2, 0, 0),
simd_float3(-2, 0, 0) ]),
box(radius: 3, position: [ simd_float3(3, 3, 0),
simd_float3(3, -3, 0),
simd_float3(-3, 3, 0),
simd_float3(-3, -3, 0) ])
]
var body: some View {
ZStack(alignment: .topTrailing) {
SceneView(scene: scene, options: [.autoenablesDefaultLighting,
.allowsCameraControl, .rendersContinuously])
Picker(""
, selection: self.$fs_cv) {
let boxFlakeList: [String] = ["0","1","2","3"]
ForEach( boxFlakeList, id: \.self ) { Num in Text(Num) }
}.fixedSize()
.onChange(of: fs_cv, {
let selected_boxFlake:[box] = boxFlake.dropLast( 3 - (fs_cv as
NSString).integerValue )
redraw_animate_scene(boxFlake: selected_boxFlake)
} // .onChange(of: fs_cv
) // .onChange
}
} // var body: some View
private func redraw_animate_scene(boxFlake: [box]) {
for box in boxFlake {
for position in box.position {
position.pNode(drawIntoNode: scene.rootNode.childNode(withName: "Spin",
recursively: true)!, radius: String(box.radius))
}
}
animate(node: scene.rootNode)
} // func redraw_animate_scene()
} // struct ContentView: View
func makeAScene() -> SCNScene {
let precessionNode = SCNNode()
let SpinNode = SCNNode()
precessionNode.name = "precession"
precessionNode.simdPosition = SIMD3<Float>(0,0,0)
precessionNode.simdTransform =
float4x4([Float(0.5.squareRoot()),Float(0.5.squareRoot()),0,0],
[-Float(0.5.squareRoot()),Float(0.5.squareRoot()),0,0],[0,0,1,0],[0,0,0,0])
SpinNode.name = "Spin"
SpinNode.simdPosition = SIMD3<Float>(0, 0, 0)
let newScene = SCNScene()
newScene.rootNode.addChildNode(precessionNode)
newScene.rootNode.childNode(withName: "precession", recursively:
true)?.addChildNode(SpinNode)
// newScene.fogDensityExponent = 0.0
newScene.background.contents = NSColor.black
newScene.rootNode.camera = SCNCamera()
newScene.rootNode.camera?.usesOrthographicProjection = true // @abstract
Determines whether the receiver uses an orthographic projection or not.
Defaults to NO. INVISIBLE WITHOUT IT!
newScene.rootNode.camera?.orthographicScale = 20 // the bigger
the number the smaller the image Without specifying 20 view is too close to
nucleus Defaults to 1.
newScene.rootNode.camera?.zNear = -20 // The default
value is 1.0
newScene.rootNode.camera?.zFar = 100 // The
default value is 100.0
// newScene.rootNode.camera?.fieldOfView = 45 // defaults
to 60 degrees
// newScene.rootNode.camera?.automaticallyAdjustsZRange = true
newScene.rootNode.camera?.automaticallyAdjustsZRange = false /* @discussion
When set to YES, the near and far planes are automatically set to fit the
bounding box of the entire scene at render time. */
return newScene
}
extension simd_float3 {
func pNode(drawIntoNode: SCNNode, radius: String) {
let myBox = SCNBox(width: 0.5, height: 0.5, length: 0.5, chamferRadius: 0.1)
let newNode = SCNNode(geometry: myBox)
newNode.name = "box_\(radius)"
newNode.simdPosition = self
newNode.scale = SCNVector3(x: 1.0, y: 1.0, z: 1.0)
newNode.isHidden = false
newNode.opacity = 1.0 // "A value of 0 means 100%
transparency, while a value of 1 means 100% opacity."
assignMaterials(newNode)
drawIntoNode.addChildNode(newNode)
}
}
func animate(node: SCNNode) {
let precession_action = SCNAction.rotate(by: CGFloat(Double.pi*2), around:
SCNVector3Make(0, 1, 0), duration: 79.17)
let Spin_action = SCNAction.rotate(by: CGFloat(Double.pi*2), around:
SCNVector3Make(0, 1, 0), duration: 4)
let boxSpin_action = SCNAction.rotate(by: -CGFloat(Double.pi*2), around:
SCNVector3Make(0, 1, 0), duration: 0.5)
var childNodeList:[SCNNode] = node.childNodes(passingTest: { (anyNode, stop)
-> Bool in anyNode.name == "precession" } )
for kids in childNodeList {
if !kids.hasActions {
kids.runAction(SCNAction.repeatForever(precession_action)) }
}
childNodeList = node.childNodes(passingTest: { (anyNode, stop) -> Bool in
anyNode.name == "Spin" } )
for kids in childNodeList {
if !kids.hasActions { kids.runAction(SCNAction.repeatForever(Spin_action)) }
}
childNodeList = node.childNodes(passingTest: { (anyNode, stop) -> Bool in
anyNode.name!.hasPrefix("box") } )
for kids in childNodeList {
if !kids.hasActions {
kids.runAction(SCNAction.repeatForever(boxSpin_action)) }
}
}
func assignMaterials(
node: SCNNode) {
_
for (index,_) in zip((node.geometry?.elements.indices)!,
node.geometry!.elements) { // see enumerated() for zero based e.g.,
Array() and ContiguousArray() only else zip(_:_:)
node.geometry?.materials[index].diffuse.contents = NSColor.red }
}