SceneKitでオブジェクト表面に背景画像を表示する
タイトルだけだとよくわからないよな、やっぱり。

↑そもそもはこのようにオブジェクトを輪郭線だけ描いてるような表現をしたいのです。
SceneKitでは背景の設定はこれでOK↓

↑ここにトーラス(SCNTorusで作成)を描くとこんな感じ。
↓単にオブジェクトを透過にすると、、、

↑どちらの方法でも全体が透過してしまうし、隠れてほしい向こう側が透けてしまっている(赤い矢印部分)。
↓シェーダで透過が有効になるようにして、

↑さっきと同じで、自分も透過して見えて欲しくない向こう側が見えてしまう。
結局フラグメントシェーダに背景画像を渡してやって、表示する座標からテクスチャ上の座標を得て背景画像を描画するようにした。オブジェクトを透過させてるのではなく背景画像を貼り付けてる。
シェーダはこんな感じで↓
macOSの場合だとiOSと上下逆になるっぽい。
輪郭線は単に黒で表示してる。

↑やっと意図するのになった!(一番最初の画像と同じのだけど)😄
↑ちょっと動かしてみた場合。正しく背景を表示していることが確認できる。
壁紙素材はこちらからお借りしました↓
タイル調の壁紙クロス|ぱくたそフリー素材
追記
↓カエルに適用するとこんな感じ

↑そもそもはこのようにオブジェクトを輪郭線だけ描いてるような表現をしたいのです。
SceneKitでは背景の設定はこれでOK↓
{ scene.background.contents = @“kabegami.jpg"; }sceneはSCNSceneオブジェクト。

↑ここにトーラス(SCNTorusで作成)を描くとこんな感じ。
↓単にオブジェクトを透過にすると、、、
{ // node.geometry.firstMaterial.transparency = 0.5; node.opacity = 0.5; }

↑どちらの方法でも全体が透過してしまうし、隠れてほしい向こう側が透けてしまっている(赤い矢印部分)。
↓シェーダで透過が有効になるようにして、
{ program.opaque = NO; }フラグメントシェーダ内で法線との内積から輪郭に近いとこは黒、そうでないところは透過させる(アルファ値ゼロ)にしてやると、、、

↑さっきと同じで、自分も透過して見えて欲しくない向こう側が見えてしまう。
結局フラグメントシェーダに背景画像を渡してやって、表示する座標からテクスチャ上の座標を得て背景画像を描画するようにした。オブジェクトを透過させてるのではなく背景画像を貼り付けてる。
シェーダはこんな感じで↓
{ if (n_dot_l <= LowLimitDot) { float2 backTexCoords = float2( in.aPosition.x / in.aPosition.w , in.aPosition.y / in.aPosition.w); //backTexCoords =float2(backTexCoords.x*0.5+0.5 , backTexCoords.y*0.5+0.5);//iOS backTexCoords =float2(backTexCoords.x*0.5+0.5 , -backTexCoords.y*0.5+0.5);//macOS color = backTexture.sample(sampler2d, backTexCoords); } else { color = float4(float3(0),1.0);//outline } return half4(color); }↑表示する点の座標を-1〜1 → 0〜1に変換してテクスチャ座標を得ている。
macOSの場合だとiOSと上下逆になるっぽい。
輪郭線は単に黒で表示してる。

↑やっと意図するのになった!(一番最初の画像と同じのだけど)😄
↑ちょっと動かしてみた場合。正しく背景を表示していることが確認できる。
壁紙素材はこちらからお借りしました↓
タイル調の壁紙クロス|ぱくたそフリー素材
追記
↓カエルに適用するとこんな感じ
トゥーンレンダリングでオブジェクトのテクスチャに背景画像を使って線画っぽい表現を試してる。 pic.twitter.com/D4CDWUqY1p
— Tatsuya (@yt) 2018年10月1日
スポンサーサイト