Created
January 3, 2018 18:11
-
-
Save mbaranowski/7312694198dd13a1efeaefa5020bc4fb to your computer and use it in GitHub Desktop.
Make a Cylinder using SceneKit in swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// GameViewController.swift | |
// SceneKitTest | |
// | |
// Created by Matt Baranowski on 12/19/17. | |
// Copyright © 2017 Matt Baranowski. All rights reserved. | |
// | |
import SceneKit | |
import QuartzCore | |
class GameViewController: NSViewController { | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
// create a new scene | |
let scene = SCNScene(named: "art.scnassets/ship.scn")! | |
// create and add a camera to the scene | |
let cameraNode = SCNNode() | |
cameraNode.camera = SCNCamera() | |
scene.rootNode.addChildNode(cameraNode) | |
// place the camera | |
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15) | |
// create and add a light to the scene | |
let lightNode = SCNNode() | |
lightNode.light = SCNLight() | |
lightNode.light!.type = .omni | |
lightNode.position = SCNVector3(x: 0, y: 10, z: 10) | |
scene.rootNode.addChildNode(lightNode) | |
// create and add an ambient light to the scene | |
let ambientLightNode = SCNNode() | |
ambientLightNode.light = SCNLight() | |
ambientLightNode.light!.type = .ambient | |
ambientLightNode.light!.color = NSColor.darkGray | |
scene.rootNode.addChildNode(ambientLightNode) | |
// retrieve the ship node | |
let ship = scene.rootNode.childNode(withName: "ship", recursively: true)! | |
ship.isHidden = true | |
let cyclinderNode = SCNNode(geometry: buildCylinder(numSlices: 12, numStacks: 1)) | |
cyclinderNode.name = "cyclinder" | |
scene.rootNode.addChildNode(cyclinderNode) | |
let cubeGeometry = SCNBox(width: 1.0, height: 1.0, length: 1.0, chamferRadius: 0.0) | |
let cubeNode = SCNNode(geometry: cubeGeometry) | |
cubeNode.position = SCNVector3(x: 2.0, y: 0, z: 0) | |
scene.rootNode.addChildNode(cubeNode) | |
// animate the 3d object | |
//ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1))) | |
// retrieve the SCNView | |
let scnView = self.view as! SCNView | |
// set the scene to the view | |
scnView.scene = scene | |
// allows the user to manipulate the camera | |
scnView.allowsCameraControl = true | |
// show statistics such as fps and timing information | |
scnView.showsStatistics = true | |
scnView.debugOptions.insert(SCNDebugOptions.showWireframe) | |
// configure the view | |
scnView.backgroundColor = NSColor.lightGray | |
// Add a click gesture recognizer | |
let clickGesture = NSClickGestureRecognizer(target: self, action: #selector(handleClick(_:))) | |
var gestureRecognizers = scnView.gestureRecognizers | |
gestureRecognizers.insert(clickGesture, at: 0) | |
scnView.gestureRecognizers = gestureRecognizers | |
} | |
func buildCylinder(numSlices: Int, numStacks: Int) -> SCNGeometry { | |
var verts: [SCNVector3] = [] | |
var normals: [SCNVector3] = [] | |
var texCoords: [CGPoint] = [] | |
var indices: [Int32] = [] | |
let sliceStep: CGFloat = (CGFloat.pi * 2) / CGFloat(numSlices) | |
var sliceAngle: CGFloat = 0 | |
var capCenterVert: Int32 = 0 | |
verts.append(SCNVector3(x: 0, y: 0, z: 0)) | |
normals.append(SCNVector3(x: 0, y: 0, z: -1)) | |
texCoords.append(CGPoint(x: 0, y: 0)) | |
for index in 1...Int32(numSlices) { | |
verts.append(SCNVector3(x: cos(sliceAngle), y: sin(sliceAngle), z: 0)) | |
normals.append(SCNVector3(x: 0, y: 0, z: -1)) | |
texCoords.append(CGPoint(x: cos(sliceAngle), y: sin(sliceAngle))) | |
let triangle: [Int32] = [capCenterVert, index, index == numSlices ? (capCenterVert+1) : index+1 ] | |
indices.append(contentsOf: triangle) | |
sliceAngle += sliceStep | |
} | |
// top cap | |
capCenterVert = Int32(verts.count) | |
verts.append(SCNVector3(x: 0, y: 0, z: 1)) | |
normals.append(SCNVector3(x: 0, y: 0, z: 1)) | |
texCoords.append(CGPoint(x: 0, y: 0)) | |
sliceAngle = 0 | |
for index in 1...Int32(numSlices) { | |
verts.append(SCNVector3(x: cos(sliceAngle), y: sin(sliceAngle), z: 1)) | |
normals.append(SCNVector3(x: 0, y: 0, z: 1)) | |
texCoords.append(CGPoint(x: cos(sliceAngle), y: sin(sliceAngle))) | |
let triangle: [Int32] = [capCenterVert, capCenterVert + index, index == numSlices ? (capCenterVert+1) : capCenterVert+index+1 ] | |
indices.append(contentsOf: triangle) | |
sliceAngle += sliceStep | |
} | |
// TODO: sides | |
let vertSrc = SCNGeometrySource(vertices: verts) | |
let normalSrc = SCNGeometrySource(normals: normals) | |
let texCoordSrc = SCNGeometrySource(textureCoordinates: texCoords) | |
let elementSrc = SCNGeometryElement(indices: indices, primitiveType: .triangles) | |
let geometry = SCNGeometry(sources: [vertSrc, normalSrc, texCoordSrc], elements: [elementSrc]) | |
let material = SCNMaterial() | |
material.diffuse.contents = NSColor.red | |
material.isDoubleSided = true | |
material.emission.contents = NSColor.red | |
geometry.firstMaterial = material | |
return geometry | |
} | |
@objc | |
func handleClick(_ gestureRecognizer: NSGestureRecognizer) { | |
// retrieve the SCNView | |
let scnView = self.view as! SCNView | |
// check what nodes are clicked | |
let p = gestureRecognizer.location(in: scnView) | |
let hitResults = scnView.hitTest(p, options: [:]) | |
// check that we clicked on at least one object | |
if hitResults.count > 0 { | |
// retrieved the first clicked object | |
let result = hitResults[0] | |
// get its material | |
let material = result.node.geometry!.firstMaterial! | |
// highlight it | |
SCNTransaction.begin() | |
SCNTransaction.animationDuration = 0.5 | |
// on completion - unhighlight | |
SCNTransaction.completionBlock = { | |
SCNTransaction.begin() | |
SCNTransaction.animationDuration = 0.5 | |
material.emission.contents = NSColor.black | |
SCNTransaction.commit() | |
} | |
material.emission.contents = NSColor.red | |
SCNTransaction.commit() | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment