how can I make a grid with 3d objects(box). I already know how to setup scnscene and how to create an object. But I don't know how to make the layout. The grid should look like this one, with 3d object in a 3D space.
Here's what I tried:
convenience init(create: Bool) {
self.init()
let geometry = SCNBox(width: 0.8 , height: 0.8,
length: 0.1, chamferRadius: 0.005)
geometry.firstMaterial?.diffuse.contents = UIColor.red
geometry.firstMaterial?.specular.contents = UIColor.white
geometry.firstMaterial?.emission.contents = UIColor.blue
let offset: Int = 10
for xIndex:Int in 0...2 {
for yIndex:Int in 0...2 {
// create a geometry copy
let geoCopy = geometry.copy() as! SCNGeometry
var images:[UIImage]=[]
for i in 1...5 {
if let img = UIImage(named: "\(i)"){
images.append(img)
let material = SCNMaterial()
material.diffuse.contents = img
geoCopy.firstMaterial = material
}
}
let boxnode = SCNNode(geometry: geoCopy)
let boxCopy = boxnode.copy() as! SCNNode
boxCopy.position.x = Float(xIndex - offset)
boxCopy.position.y = Float(yIndex - offset)
self.rootNode.addChildNode(boxCopy)
}
}
}
But I only see one box.
Thanks!
Picture of my Images:
You need to create one geometry, one box node and then copy that boxNode. You use clone when you have node with children and flattenedClone when you want to merge geometries/materials of the entire subtree at the node. In your case, copy should suffice. Just change the position of your copied node.
GameScene
import Foundation
import SceneKit
class GameScene: SCNScene {
override init() {
super.init()
let geometry = SCNBox(width: 0.6 , height: 0.6,
length: 0.1, chamferRadius: 0.005)
geometry.firstMaterial?.diffuse.contents = UIColor.red
geometry.firstMaterial?.specular.contents = UIColor.white
geometry.firstMaterial?.emission.contents = UIColor.blue
let boxnode = SCNNode(geometry: geometry)
let offset: Int = 16
for xIndex:Int in 0...32 {
for yIndex:Int in 0...32 {
let boxCopy = boxnode.copy() as! SCNNode
boxCopy.position.x = Float(xIndex - offset)
boxCopy.position.y = Float(yIndex - offset)
self.rootNode.addChildNode(boxCopy)
}
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
In your view controller, viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
// create a new scene
let scene = GameScene()
// retrieve the SCNView
let scnView = self.view as! SCNView
// set the scene to the view
scnView.scene = scene
scnView.pointOfView?.position = SCNVector3Make(0, 0, 100)
// allows the user to manipulate the camera
scnView.allowsCameraControl = true
// show statistics such as fps and timing information
scnView.showsStatistics = true
// configure the view
scnView.backgroundColor = UIColor.white
}
Note that I have just pushed the camera point of view back on the +Z axis to have a better view of your grid.
The grid screenshot
Edit: New material for each geometry
If you want to assign a new material to each geometry, you need to create a copy of the geometry and assign a new material to that geometry copy. See the code below which randomly assign a UIImage for each diffuse property, from a set of seven images named 1.png to 8.png.
import Foundation
import SceneKit
class GameScene: SCNScene {
override init() {
super.init()
let geometry = SCNBox(width: 6 , height: 6,
length: 6, chamferRadius: 0.5)
for xIndex:Int in stride(from: 0, to: 32, by:8) {
for yIndex:Int in stride(from: 0, to: 32, by: 8) {
// create a geometry copy
let geoCopy = geometry.copy() as! SCNGeometry
// create a random material
let r = arc4random_uniform(7) + 1
let img = UIImage(named: "\(r).png")
let mat = SCNMaterial()
mat.diffuse.contents = img
geoCopy.firstMaterial = mat
// create a copy node with new material and geo copy
let boxnode = SCNNode(geometry: geoCopy)
let boxCopy = boxnode.copy() as! SCNNode
boxCopy.position.x = Float(xIndex - offset)
boxCopy.position.y = Float(yIndex - offset)
self.rootNode.addChildNode(boxCopy)
}
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Screenshot