SCNConstraintを使って必ず上から光が当たる様にする


はじめに

ARKitで飛行機を飛ばしたときに光の当て方(SCNLightの配置方法)に困ったのでその対処方法を残しておく。

何も考えず下記の様に飛行機のSCNNodeのchildNodeとしてライトをaddすると絵の様に飛行機の上から光を当てることができる。

if let ship = SCNScene(named: "art.scnassets/ship.scn")!.rootNode.childNode(withName: "ship", recursively: true) {
    let light = SCNLight()
    light.type = .omni

    let lightNode = SCNNode()
    lightNode.light = light
    lightNode.position = SCNVector3(ship.position.x,ship.position.y + 2,ship.position.z)

    ship.addChildNode(lightNode)
}

しかし、単純にライトを飛行機の子ノードとして追加しているので飛行機をグルっと回転させたときにライトも同様に回転してしまう。

SCNConstraintを使う

SCNConstraintとはSCNNode間の位置関係に制約を与えるための設定であり、StoryBoadを使ってUI部品を配置するときに設定するConstraintのSCNKit版に相当する物。
この場合、ライトは必ず飛行機のY座標の+0.5に位置することという制約を設ければ、飛行機の向きに関わらず上から光を当てる事ができる。

if let ship = SCNScene(named: "art.scnassets/ship.scn")!.rootNode.childNode(withName: "ship", recursively: true) {
    let light = SCNLight()
    light.type = .omni

    let lightNode = SCNNode()
    lightNode.light = light

    let positionConstraint = SCNTransformConstraint(inWorldSpace: true, with: { (node, transform) -> SCNMatrix4 in
        let pos = node.position
        return SCNMatrix4MakeTranslation(pos.x, pos.y + 2, pos.z)
    })

    lightNode.constraints = [positionConstraint]

    ship.addChildNode(lightNode)
}