Blender でインテリアマッピング
インテリアマッピングは板ポリゴンに、奥行きのある仮想の部屋を描画するアルゴリズムだ。
床と天井のみのインテリアマッピング
I : オブジェクト空間での単位視線ベクトル
d : グリッド間距離
hit : 計算によって求める仮想の衝突位置
まず床と天井との衝突位置を計算したあとに、他の面の計算を説明する。以下の計算式から、係数 t がわかれば衝突位置 hit がきまる。P はオブジェクト空間でのシェーディング位置で、I はオブジェクト空間での単位視線ベクトルだ。
hit = P + t * I
インテリアマッピングは固定幅のグリッドで部屋が分割されるので、シェーディング位置の端数を切り捨てることにより衝突位置の高さを計算できる。視点が上向きなら天井、下向きなら床の位置を計算する。計算するコードは以下のようになる。
hit.z = (I.z > 0) ? ceil(P.z/d) * d : (ceil(P.z/d)-1) * d
高さがわかると係数 t がきまり、衝突位置 hit を計算できる。
hit.z = P.z + t * I.z
t = (hit.z - P.z) / I.z
OSL のソースコードは以下のようになる。.blend ファイルの interior-mapping-z.osl でテストできる。
shader InteriorMapping( point Position = P, vector Incoming = I, float d = 1.0, output vector texcoord = vector(0,0,0), ) { point p = transform("world", "object", Position); vector incoming = -transform("world", "object", Incoming); float hit_height = (incoming[2] > 0.0) ? ceil(p[2]/d)*d : (ceil(p[2]/d)-1)*d; float t = (hit_height - p[2]) / incoming[2]; point hit = p + t * incoming; texcoord = hit / 8; }
5面すべてを計算するインテリアマッピング
上記の計算を残りの軸に対しても計算する。係数 t は XYZ 軸の中で最も小さいものを採用する。.blend ファイルの interior-mapping.osl でテストできる。
うまく見えないときはオフセットを調整する。
shader InteriorMapping( point Position = P, vector Incoming = I, float d = 1.0, vector offset = vector(0,0,0), output vector texcoord = vector(0,0,0), ) { point p = transform("world", "object", Position) + offset; vector incoming = -transform("world", "object", Incoming); float min_t = 1e10; int id; // 0:+X, 1:-X, 2:-Y, 3:+Y, 4:-Z, 5:+Z for (int i = 0; i < 3; ++i){ int is_flip = incoming[i] > 0.0; float hit_height = is_flip ? ceil(p[i]/d)*d : (ceil(p[i]/d)-1)*d; float t = (hit_height - p[i]) / incoming[i]; if (t < min_t){ min_t = t; id = i * 2 + is_flip; } } point hit = p + min_t * incoming; if (0 <= id && id <= 1){ // X texcoord = vector(hit[1], hit[2],0) / 8; } else if(2 <= id && id <= 3){ // Y (Depth) texcoord = vector(hit[0], hit[2],0) / 8; } else{ // Z (Up) texcoord = hit / 8; } }
最適化
t = (ceil(P.z/d)*d - P.z) / I.z の ceil(P.z/d)*d - P.z の部分は、切り捨てられた端数を取得しているので -mod(P.z, d) で置き換えられる。つまり t = -mod(P.z, d) / I.z になる。
t = ((ceil(P.z/d)-1)*d - P.z) / I.z は -(mod(P.z, d) + d) / I.z に置き換えられる。
最適化されたコードは以下のようになる。
shader InteriorMapping( vector distance = vector(1.0, 1.0, 1.0), vector offset = vector(0,0,0), output vector texcoord = vector(0,0,0), ) { vector incoming = -transform("world", "object", I); point p = transform("world", "object", P) + offset; vector mod_p = mod(p + offset, -distance); float min_t = 1e10; int id; // 0:+X, 1:-X, 2:-Y, 3:+Y, 4:-Z, 5:+Z for (int i = 0; i < 3; ++i){ int is_flip = incoming[i] < 0.0; float t = -(mod_p[i] + is_flip * distance[i]) / incoming[i]; if (t < min_t){ min_t = t; id = i * 2 + is_flip; } } point hit = p + min_t * incoming; int table_x[6] = {1,1,0,0,0,0}; int table_y[6] = {2,2,2,2,1,1}; texcoord = vector(hit[table_x[id]], hit[table_y[id]],0) / 8; }
UV の計算
衝突位置と id とを使って UV 座標を計算する。UV 座標はテクスチャの配置によって計算方法が変わる。今更ながらOSLでこんなものを作っていた。3Dテクスチャ的なやつと視差マッピング的なやつ。に OSL のサンプルがある。
そのほか
オブジェクト空間ではなく UV 座標を使ったインテリアマッピングも可能だ。
OSL では transform("world", "object", Position) のようにしてワールド空間をオブジェクト空間に変換できる。またベクトル変換(Vector Transform)ノードを使うことでベクトルをオブジェクト空間に変換できる。
外部リンク
Interior Mapping A new technique for rendering realistic buildings (pdf)
OSL
今更ながらOSLでこんなものを作っていた。3Dテクスチャ的なやつと視差マッピング的なやつ。https://t.co/8pFe9BC6fp pic.twitter.com/QZP2ecFcal
— Pentan (@c5h12) 2018年9月23日
Eevee
Simulation of the “Interior Mapping” technique through Nodes で Eevee で実行可能な .blend ファイルがダウンロードできる。
今更ですがインテリアマッピングのプロジェクトファイル公開します~見たい人どうぞ₍₍🐵⁾⁾https://t.co/gA7aK3993F #b3d pic.twitter.com/ZbikVvWBru
— 大城🐈 (@Magryllia) 2019年2月18日
interior mapping test with Eevee #b3d pic.twitter.com/GUgWm3htKr
— irieぐぬー (@iRi_E) 2018年9月28日
Procedurally generated hole in Blender3D
https://t.co/TuX6QIpRLN
— Hans Chiu (@chiu_hans) July 24, 2019
Just wrote an article about how I create the procedurally generated hole for who is interested in what's going on behind the scene, with some weird drawing tying to explain the complex math.#b3d #b280 pic.twitter.com/Wr4gS1xUnf
Creating virtual faces using shader
creating stairs with ... nodes.🤔
— Hans Chiu (@chiu_hans) 2019年7月26日
turns out it's possible to make a node group for creating faces and another node group to combine those faces.#b3d #eevee #procedural #geometry #timelapse pic.twitter.com/iyspYtAi0S
BlenderのOSLを使ってShader Editerで穴を開けたりとか
そのほか
使い物になるかも分からないけど.blendファイル置いておきますね
— 雪見月 (@yukimituki11) 2018年11月5日
テクスチャもファイル内にパックしてあります。
もっと面白い使い方思い付く人がいないかな~https://t.co/UpkXIBaKoE
インテリアマッピング(interior mapping)~その1~
有料マテリアル
Interior Mapping For Blender 3d($5)