Apple Engine

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

iOS で SceneKit を試す(Swift 3) その86 - SceneKit のカスタムシェーダーについて

SceneKit でのカスタムシェーダーは主に3つ

  • SCNProgram でプリコンパイルしたものを使う
  • SCNShadable の shaderModifiers に Metal / GLSL のスニペットであるテキストデータを使う
  • SCNTechnique で設定し主にポストプロセスのように画面全体の変更する際に使う

基本、シェーダーは導入の説明を書くだけで、 何個か記事を書くことになりそうだから shaderModifiers を今回、SCNTechnique を次回軽く紹介していく。

ちなみに SCNProgram は面倒なので割愛。

 

SCNShadable の shaderModifiers とは?

ノードのマテリアルに対して個別でカスタムシェーダーを適応することができ、
カスタムシェーダーを適応する際は、定義されたエントリポイントを使用することとなる。

エントリポイントは以下の4つとなり、上から実行される。

エントリーポイント名 説明
geometry ジオメトリ形状を変更する
surface サーフェスプロパティ(Diffuse とか Material で設定しているもの)を変更する
lightingModel ライト情報の適応する情報を変更する
fragment 全ての情報を計算後に色を変更する

使い方としては SCNMaterial を初期化して、初期化したものの shaderModifiers に SCNShaderModifierEntryPoint のエントリポイントに設定する。

シェーダーの記述は String 型なので、テキストファイルを読み込む形にしても使用できる。

ちなみに、マテリアルの情報が書き換えられるため、ジオメトリが持つ firstMaterial は無視される。

また、WWDC 2017 の SceneKit のセッションで言っていたように Xcode 9 からは Scene Editor でのシェーダーの実行テストができるようになった。

 

コードを書いてみる

いつも通り、Xcode の Game テンプレートで SceneKit を選択し作成。
GameViewController.swift を開く。

以下のコードを viewDidLoad() 内に書いてビルドすると宇宙船がトゥーンシェーディングされる

let shipMesh = scene.rootNode.childNode(withName: "shipMesh", recursively: true)!

let toonMaterial = SCNMaterial()
toonMaterial.shaderModifiers = [
    SCNShaderModifierEntryPoint.lightingModel:
    "vec3 lDir = normalize(vec3(0.1, 1.0, 1.0));" +
    "float dotProduct = dot(_surface.normal, lDir);" +
    "_lightingContribution.diffuse += (dotProduct * dotProduct * _light.intensity.rgb);" +
    "_lightingContribution.diffuse = floor(_lightingContribution.diffuse * 3.0) / 3.0;"
]

shipMesh.geometry?.materials = [toonMaterial]
shipMesh.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "art.scnassets/texture.png")

f:id:x67x6fx74x6f:20170903033110p:plain

 

コード的には、宇宙船のジオメトリを指定し、SCNMaterial を初期化。
初期化したものの shaderModifiers に SCNShaderModifierEntryPoint の lightingModel をエントリーポイントとし、法線情報から外積を使用しライトの光の色ともに色を平滑化させている。

 

例えば、shaderModifiers を以下のものに変更すると色が反転する。

SCNShaderModifierEntryPoint.fragment:
            "_output.color.rgb = vec3(1.0) - _output.color.rgb;"

 

f:id:x67x6fx74x6f:20170903033353p:plain

色を反転させているが、宇宙船の部分だけが色の反転が行われており、背景は反転していない。

 

と、このような感じでカスタムシェーダーを作成できる。

基本、一連の SceneKit の記事では数学の話を省いているが、 シェーダーに関してはそれなりに数学の知識が必要なのでいつかじっくり説明したい気はする。

 

今回はここまで。