ARKitやSceneKitの図形を自由に変形させる方法を紹介します。
なお、この手法を使って最終的にはARで空中に水を浮かべるといった処理も作りましたので、こちらの記事もご覧下さい。
やり方
今回はこんな感じの球体を変形させていきます。
※下の画像は球体にライトを当てていないのでのっぺりしていますが球体です。
SceneKitのマテリアルをMetalシェーダーで描画させる方法
球体のノードを作り、SCNProgramを使ってMetalのシェーダーの関数を設定すると、シェーダーに描画させることができます。
// 球体をノードに追加する
let sphereNode = SCNNode()
sphereNode.geometry = SCNSphere(radius: 2)
sphereNode.position.y += Float(0.05)
sphereNode.name = "my_node"
// Metalのシェーダーを指定する
let program = SCNProgram()
program.vertexFunctionName = "vertexShader"
program.fragmentFunctionName = "fragmentShader"
sphereNode.geometry?.firstMaterial?.program = program
// 経過時間の情報をシェーダーに渡す
let time = Float(Date().timeIntervalSince(startDate))
globalData.time = time
let uniformsData = Data(bytes: &globalData, count: MemoryLayout<GlobalData2>.size)
sphereNode.geometry?.firstMaterial?.setValue(uniformsData, forKey: "globalData")
このあたりを詳しく知りたい方はこちらを読むと良いと思います。
Vertexシェーダーで変形してみる
まずは、簡単な変形をしてみます。
x座標にy座標分を足してみます。
vertex ColorInOut vertexShader(VertexInput2 in [[ stage_in ]],
constant SCNSceneBuffer& scn_frame [[buffer(0)]],
constant NodeBuffer& scn_node [[ buffer(1) ]],
device GlobalData2 &globalData [[buffer(2)]])
{
// 出力用変数
ColorInOut out;
// 頂点の座標情報
float3 pos = in.position;
// 頂点のxにyを足している。ここが変形処理の実体
pos.x += pos.y;
// SceneKit用のMVP変換をする
float4 transformed = scn_node.modelViewProjectionTransform * float4(pos, 1.0);
// 変換後の座標を出力変数に入れる
out.position = transformed;
// テクスチャー座標は何もせずに出力変数に入れる
out.texCoords = in.texCoords;
// 出力する
return out;
}
y座標の値が大きくなるほど(y座標は下から上に大きくなる)、x座標が大きくなっている(左から右に大きくなる)のがわかります。
なお、シェーダーの宣言の方法や、modelViewProjectionTransform
については、先程紹介したMetal入門に詳しくありますので、そちらをご覧ください。
cosを与えて変形させてみる。
さきほど、pos.x += pos.y;
としていたところを、次のように変更してみます。
pos.x += cos(pos.y);
面白いですね。cosを与えると-1〜1の範囲で波打つようになります。
こうした数式の考え方はこちらの本にわかりやすく書いてありました。
経過時間を与えてアニメーションさせてみる
さきほど、pos.x += cos(pos.y);
としていたところを、次のように変更してみます。
pos.x += cos(pos.y + globalData.time);
最初に紹介した空中に水を浮かべる方法では、x, y, zのそれぞれについてこのような処理をすることで水のような感じを出しています。
NoteではiOS開発について定期的に発信していますので、フォローしていただけますと幸いです。
https://note.com/tokyoyoshida
Twitterでは簡単なtipsを発信しています。
https://twitter.com/jugemjugemjugem