Apple Engine

Apple, iPhone, iOS, その周辺のことについて

iOS で SceneKit を試す(Swift 3) その49 - Scene Editor の Spot Light と Cast Shadow (Shadow Mapping)

舞台照明で使用されているスポットライトを模した Spot Light のご紹介。

設置位置から円錐状に光の影響を与え、任意で遮るジオメトリがあった場合に影を与えるキャストシャドウが使用できる。

 

その前にキャストシャドウとは?

シャドウマップというライトから影の情報を持ったテクスチャを作成し、
シーンにあるジオメトリにそれ適応させることで、物体に影が落ちている表現する。

 

さっくり説明すると、
ライトをカメラにしてジオメトリを映しベタ塗をする。
(下の画像では、ライトはジオメトリの上、X方向-90度に回転)

f:id:x67x6fx74x6f:20170802153403p:plain

 

ライトから照射される光の方向に他のジオメトリがあった場合、先ほどのベタ塗りをテクスチャをライトから影として適応するとディテールを持った影ができる。

f:id:x67x6fx74x6f:20170802174110p:plain

 

ジオメトリと他のジオメトリが遠い場合は、
ベタ塗りをテクスチャのサイズを変更したり、薄くしたり、ぼかしたりすることで遠くから影が落ちていることを表現する。

f:id:x67x6fx74x6f:20170802153423p:plain

 

影の演算処理はマシンパワーを使用するる為、リアルタイムの CG ではこのような工夫がされている。

 

シーン設定

Omni Light で作成したシーンをそのまま使用する。

適当なシーンに Object Library から Spot Light をドラッグ&ドロップしても可。
Floor や Plane を下に敷いておくとわかりやすいと思われる。

Scene Editor 上で動作を見ていくが、実機で動かす場合は GameViewController.swift にあるライトの記述をすべて消す。

 

Spot Light の設定

Scene Graph View から Omni Light を選択し、Attributes Inspector (Command + Option + 4) を開く。

Type が Omni になっているので Spot に変更する

f:id:x67x6fx74x6f:20170802151739p:plain

 

照明が宇宙船に当たるよう X 軸を -90 度傾ける。

f:id:x67x6fx74x6f:20170802152038p:plain

 

Spot Light の Attrubutes Inspector

以前紹介した共通の設定以外では以下のもの。

f:id:x67x6fx74x6f:20170802151951p:plain

 

Spot Parameters

円錐の円の大きさと光の減衰設定。

Outer angle

円錐の円の大きさを決める。
デフォルト値は 45 度。

65 度に設定したもの

f:id:x67x6fx74x6f:20170802152124p:plain

 

Inner angle

内側の円を決めることで光の減退を設定する デフォルト値は 0 度。

55 度に設定したもの。

f:id:x67x6fx74x6f:20170802152147p:plain

 

Inner angle、Outer angle の値が同じ場合は減退が起きない。

f:id:x67x6fx74x6f:20170802152206p:plain

 

Attenuation

スポットライトの始点から終点間での光の減衰を設定する。
(円錐の尖ったところから底の円の部分まで)

設定方法は Omni Light で紹介しているので割愛。

f:id:x67x6fx74x6f:20170802152250p:plain

 

Shadow

ジオメトリに影を与えるキャストシャドウの設定を行う。

Casts Shadows

チェックを入れると、スポットライトの光の進行方向にジオメトリがあった場合に影が落ちる。

デフォルト値は false でチェックが入っていない。

f:id:x67x6fx74x6f:20170802152400p:plain

 

Color

影に色をつける。
半透明も使用でき、デフォルト値は黒で、アルファは 1 の不透明になっている。

後ほど説明する Mode で「Deferred」を選択しないと設定した色は反映されず、影は黒になる。

 

Sample radius

影の輪郭のシャープさを設定する。
値を小さくするとシャープになり、大きくすると輪郭がぼやける。

デフォルト値は 3.0。

 

Near clipping, Far clipping

影の適応範囲。 デフォルト値は Near が 1.0、Far が 100.0。

例えば Far で 10 を設定するとそれ以降は影が乗り、 Near で 10 を設定するとスポットライトから 10 離れたジオメトリの影を描画し始める

 

Far: 10.0

f:id:x67x6fx74x6f:20170802152451p:plain

 

Near: 10.0

f:id:x67x6fx74x6f:20170802152508p:plain

 

Sample count

シャドウマップに重み付けを行い複数か処理しソフトエッジのシャドウを生成する。 サンプル数が多くなれば影はソフトになるが、処理が重くなる。

デフォルト値は 1。(macOS は 16) Scene Editor では表示上は 0。

 

Sample count: 1

f:id:x67x6fx74x6f:20170802152613p:plain

 

Sample count: 4

f:id:x67x6fx74x6f:20170802152642p:plain

 

Bias

複雑な形状の物体ではシャドウマップがうまく表示されない可能性がある。
それを補正するためのパラメーター。

デフォルト値は 1.0。

 

Map Size (width, height)

シャドウマップの画像の大きさ。
小さな画像にすると処理が軽くなるがそのぶん画像が荒くなる。

デフォルト値は縦横共に 0.0 で自動的サイズが調整される。

 

試しにかなり粗めの 100 x 100 px 描画したもの。

f:id:x67x6fx74x6f:20170802152721p:plain

 

Baking

Light Map 焼き込み時に、直接的な照明 Direct Light や間接的な照明 Indirect Light を使用するか設定する。

Scene Editor 上のパラメーターであるため、SCNLight のクラスでこのプロパティは存在しない。

 

Mode

影をつける処理のモード

説明
Forward デフォルト値。そのままシャドウマップを表示する。color で設定しても色は適応されないが透明度は適応される。
Deferred 最終画像をレンダリングした後に color で設定している影の色を適応する
Modulated 任意の画像の影(gobo)を使用し影を描画するモード。画像設定はコードから行う

 

コード

let light = SCNLight()
light.name = "spot"
light.type = .spot
light.intensity = 1000

light.castsShadow = true
light.shadowRadius = 3.0
light.color  = UIColor(red: 1.0, green: 0.0, blue: 0.502, alpha: 1.0)
light.zNear = 1.0
light.zFar  = 100.0
light.shadowSampleCount = 1
light.shadowBias = 1
light.shadowMapSize = CGSize(width: 0.0, height: 0.0)
light.shadowMode = .forward

let lightNode = SCNNode()
lightNode.light = light
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)

 

今回はここまで