Help us understand the problem. What is going on with this article?

SceneKitでベジェ曲線から3Dモデルを作ろう

More than 1 year has passed since last update.

3DモデルをXcodeで作る方法は、

  • プリミティブなジオメトリを組み合わせて作る方法
  • カスタムジオメトリを作る方法

の大きく分けて2つだと思います。

昨日は、SceneKitでプリミティブなジオメトリから3Dモデルを作ろうという記事で、前者の方法を紹介しました。

今回は後者のカスタムジオメトリを作る方法の中でも、BezierPathを使って行う方法を紹介したいと思います。

目標

こんな感じのシンプルなダイヤモンドを作ってみましょう。

IMG_299955A9F155-1.jpeg

コードでSCNNodeを作成するときの基本

まず、コードでSCNNodeを作成するときの基本は以下ような形です。

  1. ジオメトリ作成
  2. マテリアルを当てる
  3. SCNNode作成
// ジオメトリ作成
let geometry = SCNBox(width: 0.5, height: 0.5, length: 0.01, chamferRadius: 0)

// マテリアルを当てる
geometry.firstMaterial?.diffuse.contents = UIColor.yellow

// Nodeに渡してNodeをイニシャライズ
let node = SCNNode(geometry: geometry)

BezierPathでジオメトリを作る

SCNShapeというSCNGeometryを継承した型があって、以下のようにinitすることができます。

convenience init(path: UIBezierPath?, 
  extrusionDepth: CGFloat)

https://developer.apple.com/documentation/scenekit/scnshape/1523432-init

つまり流れとしては

// path作成
let path = UIBezierPath()

// pathを渡してジオメトリ作成
let geometry = SCNShape(path: path, extrusionDepth: 0.2)

// マテリアルを当てる
geometry.firstMaterial?.diffuse.contents = UIColor.yellow

// Nodeに渡してNodeをイニシャライズ
let node = SCNNode(geometry: geometry)

という感じです。

ダイヤモンドのBezierPathを作成する

ベジェ曲線とは

まずは、ベジェ曲線とは何か確認しときましょう。

コンピューターで図形の曲線を描くために使われている数式。曲線を始点、終点とそれぞれの方向点の4つの点の座標をもとに描画する。自由度が高く、ほとんどすべての曲線を表現できる。アドビ システムズ社のIllustratorやコーレル社のCorelDRAWなどのドロー系ソフトで曲線の表現方法として採用されているほか、PostScriptのフォントの記述方法にも採用されている。
https://kotobank.jp/word/%E3%83%99%E3%82%B8%E3%82%A7%E6%9B%B2%E7%B7%9A-8655

ベジェ曲線を使うと、点と点から曲線を描くことができます。

iOS、Swiftでもこれを使うことができます。

Swiftでベジェ曲線

以下のように4点を結んで、ダイヤモンドを作ります。

  1. 始点にmoveする
  2. addLineして線を繋いでいく
  3. closeして線を閉じる

IMG_67426123B7B4-1.jpeg

これをコードで示すと以下のようになります。

let path = UIBezierPath()
path.move(to: CGPoint(x: 1, y: 0))
path.addLine(to: CGPoint(x: 0, y: -1))
path.addLine(to: CGPoint(x: -1, y: 0))
path.addLine(to: CGPoint(x: 0, y: 1))
path.close()

作ったUIBezierPathをSCNShapeに渡す

ダイヤモンドのUIBezierPathができたのでこれをSCNShapeに渡して立体的にしていきましょう。

// path作成
let path = UIBezierPath()
path.move(to: CGPoint(x: 1, y: 0))
path.addLine(to: CGPoint(x: 0, y: -1))
path.addLine(to: CGPoint(x: -1, y: 0))
path.addLine(to: CGPoint(x: 0, y: 1))
path.close()

// pathを渡してジオメトリ作成
let geometry = SCNShape(path: path, extrusionDepth: 0.2)

// マテリアルを当てる
geometry.firstMaterial?.diffuse.contents = UIColor.yellow

// Nodeに渡してNodeをイニシャライズ
let node = SCNNode(geometry: geometry)

extrusionDepthは厚さです。上記コードでは0.2(m)の厚さです。

アウトプット

デバッグして、SceneKitやARKitで空間に置くと以下のようになるはずです。

IMG_299955A9F155-1.jpeg

応用

UIBezierPathで作れる形は何でも立体にできます。

例えば、iOS で星型の図形を UIBezierPath で作る
を参考に星型のUIBezierPathを作ることができれば、星の立体を作成することもできます。

star.gif

僕のARKitのサンプルコード集の中でもやってみましたので気になる方は参考にしてください。
https://github.com/kboy-silvergym/ARKit-Emperor

まとめ

  • geometryをNodeに渡すのがコードで3Dモデルを作る基本
  • UIBezierPathはmoveしてaddLineしてcloseして作る
  • SCNShapeというgeometryはUIBezierPathを渡して好きな形状を作れる
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away