SceneKit
SCNNode : 씬 그래프에서 3D객체를 나타내는 것
A structural element of a scene graph, representing a position and transform in a 3D coordinate space, to which you can attach geometry, lights, cameras, or other displayable content.
- AR로 디스플레이되는 물체들은 node라고 칭한다.
- rootNode : scene내에서 Scenekit에 의해 그려지는 것들의 좌표체계를 정의한다. 즉 기준점이 된다는 뜻. rootNode에 추가되는 childNode는 rootNode를 기준으로 좌표체계가 형성된다.
The rootNode object in a scene defines the coordinate system of the world rendered by SceneKit.
node의 position, rotation, scale 속성을 이용하거나 trasform 속성을 이용하여 transformation구현한다.
rootNode와 childNode는 node계층(scene graph)로 묶여있지만 그렇다고 해서 visual적인 부분들까지 계층을 이루는 것은 아니다(예를들어 root node를 이루는 색이 빨간색이라고 해서 cildNode도 빨간색이 되진 않는다.)
노드에 SCNGeometry객체를 추가해서 2D, 3D 물체가 화면에 보이도록 한다.
// 예시
let pyramid = SCNNode(geometry: SCNPyramid(width: 0.1,
height: 0.1,
length: 0.1))
SceneKit로 표현한 2D, 3D물체자체를 회전시키거나 SCNAction등을 이용해 물체를 회전전 시키고 싶을 때 x, y, z축에 따른 다음과 같은 분류를 이용해 구현한다.
pitch
: rotation around X-axis
Yaw
: rotation around Y-axis
Roll
: rotation around Z-axis
예를들어 튜브모양의 물체를 x축기준 시계방향으로 45도 ,y 축 기준 반시계방향으로 20도, z축기준 반시계방향으로 45보 만큼 회전시켜서 화면에 표시하고 싶을 때 다음과 같이 메소드를 구현할 수 있다.
extension Int {
func floatToRadius() -> CGFloat {
return CGFloat(self) * CGFloat.pi / 100.0
}
}
// viewcontroller내부에서 구현한 메서드
func drawTube() {
let tube = SCNNode(geometry: SCNTorus(ringRadius: 0.05,
pipeRadius: 0.03))
tube.geometry?.firstMaterial?.diffuse.contents = UIColor.gray
tube.geometry?.firstMaterial?.specular.contents = UIColor.white
tube.position = SCNVector3(0.0, 0.2, -0.2)
tube.eulerAngles = SCNVector3(-45.floatToRadius(), 20.floatToRadius(), 45.floatToRadius())
sceneView.scene.rootNode.addChildNode(tube)
}
SceneKit에서 객체의 비쥬얼적인 부분을 애니메이션형태로 바꿀 수 있도록 하는 것 (growing, shrinking, 명도조절 등등)
객체에 액션
을 붙이고 특정 타임에 그 액션
을 실행하라고 하는 것
만약 액션 객체가 없다면?
- 애니메이션 구현하려면 매 트랙마다 애니메이션이 되도록 구현해야됨. 여러가지 자잘한 일들이 많음.
- 하지만
액션
을 붙이면 알아서 잘 구현되도록 해결해줌
//1. 액션객체 만들기
let tubeAction = SCNAction.rotate(by: 360.floatToRadius(),
around: SCNVector3(x: 0, y: 1, z: 0),
duration: 8)
//2. 액션객체를 AR객체에 붙이기
tube.runAction(indefinitelyRotate) {
print("회전이끝났습니다.")
}
run
let tubeAction = SCNAction.rotate(by: 360.floatToRadius(),
around: SCNVector3(x: 0, y: 1, z: 0),
duration: 8)
let indefinitelyRotate = SCNAction.repeatForever(tubeAction)
tube.runAction(indefinitelyRotate) {
print("회전이끝났습니다.")
}
func drawOrbitingShip() {
//SCNScene 객체 생성
let scene = SCNScene(named: "art.scnassets/ship.scn")
//childNode가져오기
let ship = (scene?.rootNode.childNode(withName: "ship", recursively: false))!
//childNode가 어떻게 보여질지 결정
ship.position = SCNVector3(1, 0, 0)
ship.scale = SCNVector3(0.3, 0.3, 0.3)
ship.eulerAngles = SCNVector3(0, 100.floatToRadius(), 0)
sphere.addChildNode(ship)
}