SceneKit Practice - juniverse1103/ARKitStudy GitHub Wiki

SceneKit Practice

1. Scene Preparation

  1. ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ํ•˜๊ธฐ

    SceneKit์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ์šฐ์„  ์ƒˆ๋กœ์šด Swift Project๋ฅผ ์—ด์–ด์ค๋‹ˆ๋‹ค.

    ์œ„์— ๋ณด์ด๋Š” Application Template ์ค‘ Game ์„ ์„ ํƒํ•˜๋ฉด ๊ธฐ๋ณธ์ ์ธ SceneKit์ด ์ ์šฉ๋œ ํ…œํ”Œ๋ › ํ”„๋กœ์ ํŠธ๊ฐ€ ๋‚˜์˜ค์ง€๋งŒ, ์ด๋ฒˆ ๋ชฉํ‘œ๋Š” ๋นˆ ํ”„๋กœ์ ํŠธ์—์„œ Game Template๋ฅผ ๊ทธ๋Œ€๋กœ ๊ตฌํ˜„ํ•ด ๋ณด๋Š”๊ฒƒ์ž…๋‹ˆ๋‹ค.

    Single View App ํ…œํ”Œ๋ ›์„ ์„ ํƒํ•ด ์ฃผ์„ธ์š”.

  2. Single View App ํ…œํ”Œ๋ ›์„ ์„ ํƒํ•˜๋ฉด ์œ„์™€ ๊ฐ™์ด ๋นˆ ํ”„๋กœ์ ํŠธ ํ™”๋ฉด์ด ๋‚˜ํƒ€๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

    SceneKit์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ณ ๋ คํ•ด์•ผ ํ•  ์‚ฌํ•ญ์€ ํฌ๊ฒŒ ์„ธ๊ฐ€์ง€ ์ž…๋‹ˆ๋‹ค.

    1. View Controller
    2. Asset
    3. StoryBoard

    ์ด ์ค‘ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์ž‘์—…์€ ๋ทฐ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ด๋ฃจ์–ด์ง€๋ฉฐ, Asset์—๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์—์„œ ์‚ฌ์šฉํ•  scnํŒŒ์ผ๊ณผ ํ…์Šค์ณ ํŒŒ์ผ์„ ๋„ฃ์–ด์ฃผ๊ณ , ์Šคํ† ๋ฆฌ๋ณด๋“œ์—๋Š” ์ž‘์„ฑํ•œ 3D Scene์„ ๋ Œ๋”๋งํ•ด์„œ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•œ SCNView ๊ฐ์ฒด๋ฅผ ๋„์›Œ์ฃผ๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  3. SceneKit Catalog ์ถ”๊ฐ€ํ•˜๊ธฐ

    ๊ธฐ์กด ๋นˆ ํ”„๋กœ์ ํŠธ์— ์ƒ์„ฑ๋œ Asset ํด๋”๋Š” Xcode์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ด๋ฏธ์ง€๋“ค์„ ๋ณด๊ด€ํ•˜๊ธฐ ์œ„ํ•œ xcassets ์นดํƒˆ๋กœ๊ทธ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์—๊ฒŒ ํ•„์š”ํ•œ ๊ฒƒ์€ SceneKit์— ์‚ฌ์šฉ๋  .scn ํŒŒ์ผ์„ ๋ณด๊ด€ํ•  scnassets ์นดํƒˆ๋กœ๊ทธ์ด๋ฏ€๋กœ, ์ƒ๋‹จ์˜ ๋ฉ”๋‰ด ๋ฐ”์—์„œ File ํƒญ์„ ํด๋ฆญํ•œ ํ›„ New -> File -> SceneKit Catalog ๋ฅผ ํด๋ฆญํ•ด scnassets ์นดํƒˆ๋กœ๊ทธ๋ฅผ ํด๋ฆญํ•˜์—ฌ ์ถ”๊ฐ€ํ•ด ์ค๋‹ˆ๋‹ค.

  4. Scene File ์ถ”๊ฐ€ํ•˜๊ธฐ

    ์ƒ์„ฑ๋œ scnassets ํด๋”๋กœ ์ด๋™ํ•œ ํ›„ ์ƒ๋‹จ์˜ ๋ฉ”๋‰ด๋ฐ”์—์„œ ์ƒˆ๋กœ์šด ํŒŒ์ผ์„ ์—ด์–ด์ฃผ๊ฑฐ๋‚˜, command + N ํ‚ค๋ฅผ ๋ˆŒ๋Ÿฌ์ฃผ๋ฉด scnassets ํด๋” ๋‚ด์— ์ƒˆ๋กœ์šด .scn ํŒŒ์ผ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

  5. Scene object ์ถ”๊ฐ€ํ•˜๊ธฐ

    Scene์— ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ถ”๊ฐ€ํ•  ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Apple์—์„œ ARKit์— ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ƒˆ๋กญ๊ฒŒ ๊ณต๊ฐœํ•œ ํŒŒ์ผ ํฌ๋งท์ธ usdz ํฌ๋งท ํŒŒ์ผ์„ ๋ฐ›์•„ ์™€์„œ SceneKit์— ์˜ฌ๋ ค๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

    https://developer.apple.com/arkit/gallery/ ์— ๋“ค์–ด๊ฐ€์„œ ๋งˆ์Œ์— ๋“œ๋Š” usdz ํŒŒ์ผ์„ ๋ฐ›์•„์˜ต๋‹ˆ๋‹ค. ์ €๋Š” ๋ ˆํŠธ๋กœ TV์™€ ์ผ๋ ‰ ๊ธฐํƒ€ ๋‘๊ฐ€์ง€ ํŒŒ์ผ์„ ๋ฐ›์•„์˜ค๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

    command + O ํ‚ค๋ฅผ ๋ˆŒ๋Ÿฌ ๋‹ค์šด๋กœ๋“œ ํด๋”์—์„œ ํŒŒ์ผ์„ ์—ด์–ด .scnassets ํด๋”์— ๋„ฃ์–ด์ค๋‹ˆ๋‹ค. ์ €๋Š” .scnassets ํด๋”์— practice.scn ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ์šฐ์„  ๋ ˆํŠธ๋กœ TV ํŒŒ์ผ ๋งŒ์„ practice.scn ํด๋”์— ์ถ”๊ฐ€ํ•ด ์ฃผ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

2. Storyboard Preparation

  1. Scene์„ ๋ Œ๋”๋งํ•ด์„œ ํ‘œ์‹œํ•ด์ค„ SCNView ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ธฐ ์œ„ํ•ด Interface Builder๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์Šคํ† ๋ฆฌ๋ณด๋“œ์— SCNView๋ฅผ ์ถ”๊ฐ€ํ•ด์ค€ ํ›„ constraint๋ฅผ safe area ์— ๋งž์ถฐ์„œ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.

    ์ด๋ฒˆ์—๋Š” ARKit๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  SceneKit View๋ฅผ ์—ฐ์Šตํ•ด๋ณผ ๊ณ„ํš์ด๊ธฐ์— SceneKit View๋ฅผ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

    Constraint ๋ฅผ Safe Area์— ๋Œ€ํ•˜์—ฌ ๊ฐ๊ฐ 0์”ฉ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.

    ์Šคํ† ๋ฆฌ๋ณด๋“œ ์ค€๋น„๊ฐ€ ๋๋‚ฌ์Šต๋‹ˆ๋‹ค.

3. View Controller

  1. Framework Import
  • import SceneKit ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด SceneKit Framework๋ฅผ import ํ•ด ์ค๋‹ˆ๋‹ค.

  • import QuartzCore ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด QuartzCore Framework๋ฅผ import ํ•ด ์ค๋‹ˆ๋‹ค.

    • QuartzCore๋Š” ์ด๋ฏธ์ง€ ํ”„๋กœ์„ธ์‹ฑ๊ณผ ๋น„๋””์˜ค ์ด๋ฏธ์ง€ ์กฐ์ž‘์„ ์ง€์›ํ•˜๋Š” Objective - C ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค.
    • Core Animation Framework ์™€ ๋™์˜์–ด์ž…๋‹ˆ๋‹ค.
  1. viewDidLoad ์—์„œ ์ฝ”๋“œ๋ฅผ ํ†ตํ•œ Scene ๊ตฌ์„ฑ
  • scene ์ƒ์„ฑํ•˜๊ธฐ: SCNScene ํƒ€์ž… ๊ฐ์ฒด์ธ scene์„ ์„ ์–ธํ•ด ์ค๋‹ˆ๋‹ค. ์ด ๋•Œ, ์ด๋‹ˆ์…œ๋ผ์ด์ €์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์•ž์—์„œ ์ƒ์„ฑํ•ด ์ฃผ์—ˆ๋˜ scnassets ํด๋”์— ์žˆ๋Š” scn ํŒŒ์ผ์„ ํฌํ•จํ•˜์—ฌ ์ค๋‹ˆ๋‹ค.

    //create a new scene
    let scene = SCNScene(named: "art.scnassets/[scene์„ ๊ตฌ์„ฑํ•˜๊ณ ์ž ํ•˜๋Š” scn ํŒŒ์ผ ์ด๋ฆ„]")
    
  • camera ์ƒ์„ฑํ•˜๊ธฐ: ์นด๋ฉ”๋ผ๋ฅผ ๋ถ™์ผ node๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ SCNNode ํƒ€์ž… ๊ฐ์ฒด์ธ cameraNode๋ฅผ ์ƒ์„ฑํ•ด ์ค๋‹ˆ๋‹ค.

    ๊ทธ ํ›„, cameraNode์˜ .camera ํ”„๋กœํผํ‹ฐ์— SCNCamera()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์นด๋ฉ”๋ผ๋ฅผ ๋ถ™์—ฌ์ค๋‹ˆ๋‹ค.

    scene์˜ rootNode์— ์ƒ์„ฑํ•ด์ค€ cameraNode๋ฅผ ChildNode๋กœ์„œ ์ถ”๊ฐ€ํ•ด ์ค๋‹ˆ๋‹ค.

    //create and add a camera to see the scene
    let cameraNode = SCNNode()
    cameraNode.camera = SCNCamera()
    scene.rootNode.addChildNode(cameraNode)
    
  • ์นด๋ฉ”๋ผ ์œ„์น˜์‹œํ‚ค๊ธฐ: cameraNode๋Š” ํ˜„์žฌ rootNode์˜ ChildNode์ด๊ธฐ ๋•Œ๋ฌธ์—, rootNode๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ•˜๋Š” ๊ณต๊ฐ„๋ฒกํ„ฐ๋ฅผ ํ†ตํ•ด ์œ„์น˜์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•ด ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    cameraNode์˜ ์œ„์น˜๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ์ˆ˜์ •ํ•ด ์ค๋‹ˆ๋‹ค.

    //place the camera
    cameraNode.position = SCNVector3(x:0,y:0,z:15)
    
  • ์กฐ๋ช… ์ƒ์„ฑํ•˜๊ธฐ: ์กฐ๋ช…์„ ๋ถ™์ผ node ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ SCNNode ํƒ€์ž… ๊ฐ์ฒด์ธ lightNode๋ฅผ ์ƒ์„ฑํ•ด ์ค๋‹ˆ๋‹ค.

    ๊ทธ ํ›„, lightNode์˜ .light ํ”„๋กœํผํ‹ฐ์— SCNLight()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์กฐ๋ช…์„ ๋ถ™์—ฌ์ค๋‹ˆ๋‹ค.

    ligntNode.light์˜ .type ํ”„๋กœํผํ‹ฐ๋ฅผ ์ด์šฉํ•ด ์กฐ๋ช…์˜ ํƒ€์ž…์„ ์ง€์ •ํ•ด ์ค๋‹ˆ๋‹ค.

    • ์กฐ๋ช…์˜ ํƒ€์ž…์€ ambient, directional, IES, probe, spot, omni๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
      • Ambient: A light that illuminates all objects in the scene from all directions.
        • scene ๋‚ด์˜ ๋ชจ๋“  ๊ฐ์ฒด๋ฅผ ๋ชจ๋“  ๋ฐฉํ–ฅ์œผ๋กœ ๋น„์ถ”๋Š” ์กฐ๋ช…์ž…๋‹ˆ๋‹ค.
      • Directional: A light source with a uniform direction and constant intensity.
        • ์ผ์ •ํ•œ ์ฑ„๋„์™€ ์ •ํ•ด์ง„ ๋ฐฉํ–ฅ์„ ๊ฐ–๋Š” ๊ด‘์›์ž…๋‹ˆ๋‹ค.
      • IES: A light source whose shape, direction, and intensity of illumination is determined by a photometric profile.
        • Photometric profile์— ์˜ํ•ด ๋ชจ์–‘, ๋ฐฉํ–ฅ, ๊ทธ๋ฆฌ๊ณ  ์ฑ„๋„๊ฐ€ ์ •ํ•ด์ง€๋Š” ๊ด‘์›์ž…๋‹ˆ๋‹ค.
      • Probe: A sample of the environment around a point in a scene to be used in environment-based lighting.
        • Environment-based lighting์— ์‚ฌ์šฉ๋˜๊ธฐ ์œ„ํ•œ scene ๋‚ด์˜ ํ•œ ์ ์„ ๋‘˜๋Ÿฌ์‹ธ๋Š” ์ƒ˜ํ”Œ ํ™˜๊ฒฝ์ž…๋‹ˆ๋‹ค.
      • Spot: A light source that illuminates a cone-shaped area.
        • ์›๋ฟ” ๋ชจ์–‘์˜ ์˜์—ญ์„ ๋น„์ถ”๋Š” ๊ด‘์›์ž…๋‹ˆ๋‹ค.
      • Omni: An omnidirectional light, also known as a point light.
        • ๋ชจ๋“  ๋ฐฉํ–ฅ์œผ๋กœ ๋น›์„ ๋น„์ถ”๋Š” ์กฐ๋ช…์ž…๋‹ˆ๋‹ค. ์ ๊ด‘์›์ด๋ผ๊ณ ๋„ ๋ถˆ๋ฆฝ๋‹ˆ๋‹ค.
    // 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)
    
  • ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ambient light ์—ญ์‹œ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

    // create and add an ambient light to the scene
    let ambientLightNode = SCNNode()
    ambientLightNode.light = SCNLight()
    ambientLightNode.light!.type = .ambient
    ambientLightNode.light!.color = UIColor.darkGray
    scene.rootNode.addChildNode(ambientLightNode)
    
  • ์˜ค๋ธŒ์ ํŠธ ๋…ธ๋“œ ์ถ”๊ฐ€ํ•ด์ฃผ๊ธฐ: ํ˜„์žฌ ์šฐ๋ฆฌ๊ฐ€ ๋‹ค๋ฃจ๊ณ  ์žˆ๋Š” scene ๋ณ€์ˆ˜๋Š” .scnassets ํด๋” ๋‚ด์˜ practice.scn ํŒŒ์ผ์„ ๋‚˜ํƒ€๋‚ด๋Š” SCNScene ์ž…๋‹ˆ๋‹ค. practice.scn ํŒŒ์ผ ๋‚ด์˜ retrotv ์˜ค๋ธŒ์ ํŠธ๋ฅผ scene ๋ณ€์ˆ˜์˜ rootNode์˜ childNode์— ์ถ”๊ฐ€ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

    // retrieve the retrotv node
    let retrotv = scene.rootNode.childNode(withName: "retrotv", recursively: true)!
    
  • ์˜ค๋ธŒ์ ํŠธ ๋…ธ๋“œ์— ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ถ”๊ฐ€ํ•˜๊ธฐ: ์˜ค๋ธŒ์ ํŠธ ๋…ธ๋“œ์˜ runAction ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋…ธ๋“œ์— ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” y์ถ•์„ ๊ธฐ์ค€์œผ๋กœ ๋ฐ˜๋ณต๋˜๋Š” ํšŒ์ „ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ถ”๊ฐ€ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

    // animate the 3D object
    retrotv.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x:0, y:50,z:0,duration:1)))
    
  • Scene ๋ Œ๋”๋งํ•˜๊ธฐ: ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค์–ด ์ค€ scene์„ ๋””๋ฐ”์ด์Šค ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•œ SCNView ํ”„๋กœํผํ‹ฐ๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ์–ด ์œ„์—์„œ ์„ ์–ธํ•œ scene์„ ํ• ๋‹นํ•ด ์ค๋‹ˆ๋‹ค.

    // retrieve the SCNView
    let scnView = self.view as! SCNView
    
    // set the scene to the view
    scnView.scene = scene
    
  • Camera control, Statistics, Background color ๋“ฑ์˜ ์„ค์ •์„ ์„ค์ •ํ•ด์ค๋‹ˆ๋‹ค.

    // allows the user to manipulate the camera
    scnView.allowsCameraControl = true
    
    // show statistics such as fps and timing information
    scnView.showStatistics = true
    
    // configure the view
    scnView.backgroundColor = UIColor.black
    
  • ๋งˆ์ง€๋ง‰์œผ๋กœ, TapGestureRecognizer๋ฅผ ์ถ”๊ฐ€ํ•ด ์ค๋‹ˆ๋‹ค.

    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
    scnView.addGestureRecognizer(tapGesture)