9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ARKit、SceneKitのtransform(4x4行列)の使い方を簡単に確認できるPlayground Code

Last updated at Posted at 2021-02-08

ARKit、SceneKitでは、transformプロパティを使って、3D変換(回転、拡大縮小、投影、移動)をすることがあります。このプロパティの設定を確認できるPlayground Codeを作りました。

<仕上がり>
XcodeのPlaygroud上でSceneKitの描画をしています。

transformプロパティとは

4x4行列で、SCNMatrix4型になっています。

node.transform = SCNMatrix4(
    m11:  0, m12:  0, m13:  0, m14:  0,
    m21:  0, m22:  1, m23:  0, m24:  0,
    m31:  0, m32:  0, m33:  1, m34:  0,
    m41:  0, m42:  0, m43:  0, m44:  1
)

4x4行列を用いた3D変換

単位行列(Identity)・・・掛けても変化しない。他の行列を作るときのテンプレートとしてよく利用される。

\begin{pmatrix}
    m11:  1 & m12:  0 & m13:  0 & m14:  0 \\
    m21:  0 & m22:  1 & m23:  0 & m24:  0 \\
    m31:  0 & m32:  0 & m33:  1 & m34:  0 \\
    m41:  0 & m42:  0 & m43:  0 & m44:  1
\end{pmatrix}

移動(Translate)

\begin{pmatrix}
    m11:  1 & m12:  0 & m13:  0 & m14:  0 \\
    m21:  0 & m22:  1 & m23:  0 & m24:  0 \\
    m31:  0 & m32:  0 & m33:  1 & m34:  0 \\
    m41: tx & m42: ty & m43: tz & m44:  1
\end{pmatrix}

拡大縮小(Scale)

\begin{pmatrix}
    m11: sx & m12:  0 & m13:  0 & m14:  0 \\
    m21:  0 & m22: sy & m23:  0 & m24:  0 \\
    m31:  0 & m32:  0 & m33: sz & m34:  0 \\
    m41:  0 & m42:  0 & m43:  0 & m44:  1
\end{pmatrix}

X軸にそって回転(Rotate around X axis)

\begin{pmatrix}
    m11:  1 & m12: 0 & m13: 0 & m14:  0 \\
    m21:  0 & m22:cosθ & m23: sinθ & m24:  0 \\
    m31:  0 & m32: -sinθ & m33:cosθ & m34:  0 \\
    m41:  0 & m42: 0 & m43: 0 & m44:  1
\end{pmatrix}

Y軸にそって回転(Rotate around Y axis)

\begin{pmatrix}
    m11:  cosθ & m12:  0 & m13:  0 & m14: -sinθ \\
    m21:  0 & m22:  1 & m23:  0 & m24:  0 \\
    m31: sinθ & m32:  0 & m33: cosθ & m34:  0 \\
    m41:  0 & m42:  0 & m43:  0 & m44:  1
\end{pmatrix}

Z軸にそって回転(Rotate around Z axis)

\begin{pmatrix}
    m11:cosθ & m12: sinθ & m13: 0 & m14:  0 \\
    m21: -sinθ & m22: cosθ & m23:  0 & m24:  0 \\
    m31:  0 & m32:  0 & m33:  1 & m34:  0 \\
    m41:  0 & m42:  0 & m43:  0 & m44:  1
\end{pmatrix}

Playground Code

上の変換を適用したコードです。XCodeのPlaygroundに貼り付ければそのまま動作します。

Playground
import SceneKit
import QuartzCore
import XCPlayground
import PlaygroundSupport

// 行列内容を見やすく表示する関数
// 行ベクトル表示
func printMatrixByRow(_ matrix: SCNMatrix4) {
    print("---")
    print("m11: \(matrix.m11) m21: \(matrix.m21) m31: \(matrix.m31) m41: \(matrix.m41)")
    print("m12: \(matrix.m12) m22: \(matrix.m22) m32: \(matrix.m32) m42: \(matrix.m42)")
    print("m13: \(matrix.m13) m23: \(matrix.m23) m33: \(matrix.m33) m43: \(matrix.m43)")
    print("m14: \(matrix.m14) m24: \(matrix.m24) m34: \(matrix.m34) m44: \(matrix.m44)")
}

// 列ベクトル表示
func printMatrix2ByCol(_ matrix: SCNMatrix4) {
    print("---")
    print("m11: \(matrix.m11), m12: \(matrix.m12), m13: \(matrix.m13), m14: \(matrix.m14),")
    print("m21: \(matrix.m21), m22: \(matrix.m22), m23: \(matrix.m23), m24: \(matrix.m24),")
    print("m31: \(matrix.m31), m32: \(matrix.m32), m33: \(matrix.m33), m34: \(matrix.m34),")
    print("m41: \(matrix.m41), m42: \(matrix.m42), m43: \(matrix.m43), m44: \(matrix.m44)")
}

// ビューを用意
var sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
var scene = SCNScene()
sceneView.scene = scene

PlaygroundPage.current.liveView = sceneView

sceneView.autoenablesDefaultLighting = true

// カメラを設置
var cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0.6, y: 1.2, z: 3)
scene.rootNode.addChildNode(cameraNode)

// 基本となる図形を用意
func buildNode(_ text: String) -> SCNNode {
    let text = SCNText(string: text, extrusionDepth: 0.2)
    text.font = UIFont.systemFont(ofSize: 0.3)
    text.firstMaterial?.diffuse.contents  = UIColor.red
    return SCNNode(geometry: text)
}


// ここから様々な位置に表示

// 変換なし
_ = {
    let node = buildNode("変換なし")
    printMatrixByRow(node.transform)
    scene.rootNode.addChildNode(node)
}()


// positionを使って移動
_ = {
    let node = buildNode("拡大して、右に1メートル、上に2メートル、奥に3メートル")
    node.position = SCNVector3(1, 2, -3)
    node.scale = SCNVector3(2, 2, 2)
    printMatrixByRow(node.transform)
    scene.rootNode.addChildNode(node)
    printMatrix2ByCol(node.transform)
}()

// position, rotationを使って移動・回転
_ = {
    let node = buildNode("左に1m、奥に3m、Z軸方向に45度回転")
    node.position = SCNVector3(-1, 0, -3)
    node.rotation = SCNVector4(0, 0, 1, Float.pi/4)
    printMatrixByRow(node.transform)
    scene.rootNode.addChildNode(node)
}()

// transformを使って移動
_ = {
    let node = buildNode("拡大して、右に1メートル、下に2メートル、奥に3メートル")
    node.transform = SCNMatrix4(
        m11: 2.0, m12:  0.0, m13:  0.0, m14: 0.0,
        m21: 0.0, m22:  2.0, m23:  0.0, m24: 0.0,
        m31: 0.0, m32:  0.0, m33:  2.0, m34: 0.0,
        m41: 1.0, m42: -2.0, m43: -3.0, m44: 1.0
    )
    printMatrixByRow(node.transform)
    scene.rootNode.addChildNode(node)
}()

// transformを使って移動・回転
_ = {
    
    let rad = Float.pi/4
    
    let node = buildNode("左に1m、下に2m、奥に3m,Z軸に45度回転")
    node.transform = SCNMatrix4(
        m11:  cos(rad), m12: sin(rad), m13:  0.0, m14: 0.0,
        m21: -sin(rad), m22: cos(rad), m23:  0.0, m24: 0.0,
        m31:       0.0, m32:      0.0, m33:  1.0, m34: 0.0,
        m41:      -1.0, m42:     -2.0, m43: -3.0, m44: 1.0
    )
    printMatrixByRow(node.transform)
    scene.rootNode.addChildNode(node)
}()

番外編

transformを掛け合わせることで、変換を合成することができます。
これは、例えば15度の回転を3回掛け合わせています。結果は45度の回転になります。

Playground
_ = {

    let rad = Float.pi/12

    let node = buildNode("Z軸に15度を3回回転(=45度の回転)")
    let t1 = SCNMatrix4(
        m11:  cos(rad), m12: sin(rad), m13:  0.0, m14: 0.0,
        m21: -sin(rad), m22: cos(rad), m23:  0.0, m24: 0.0,
        m31:       0.0, m32:      0.0, m33:  1.0, m34: 0.0,
        m41:       0.0, m42:      0.0, m43:  0.0, m44: 1.0
    )
    let t2 = SCNMatrix4(
        m11:  cos(rad), m12: sin(rad), m13:  0.0, m14: 0.0,
        m21: -sin(rad), m22: cos(rad), m23:  0.0, m24: 0.0,
        m31:       0.0, m32:      0.0, m33:  1.0, m34: 0.0,
        m41:       0.0, m42:      0.0, m43:  0.0, m44: 1.0
    )
    let t3 = SCNMatrix4(
        m11:  cos(rad), m12: sin(rad), m13:  0.0, m14: 0.0,
        m21: -sin(rad), m22: cos(rad), m23:  0.0, m24: 0.0,
        m31:       0.0, m32:      0.0, m33:  1.0, m34: 0.0,
        m41:       0.0, m42:      0.0, m43:  0.0, m44: 1.0
    )
    node.transform = SCNMatrix4Mult(SCNMatrix4Mult(t1, t2),t3)
    printMatrixByRow(node.transform)
    scene.rootNode.addChildNode(node)
}()

最後に

NoteではiOS開発、AR、機械学習などについて定期的に発信しています。
https://note.com/tokyoyoshida

Twitterでも発信しています。
https://twitter.com/jugemjugemjugem

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?