頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


iOSでキューブマッピング

オフスクリーンレンダリングを調べていた時にキューブマッピングなるものを知ったんだわ。環境マッピングとも言ったりするみたい。
これを使えばオブジェクトへの映り込みを表現できるとか。これは面白そうだと挑戦してみたんだよ。

ところがこれ、やろうとするとなかなかややこしくてね。OpenGLだとよくあることだけど説明する人によって環境も違うしさ。iOSでのOpenGLだとどうなるんだろう?と最初は戸惑ったんだけど、結局のところ、このキューブマッピングというのはオブジェクトを’世界’の中心に置いて視線と法線だけで周辺画像(上下左右前後6枚用意するでしょ)のどこを拾うかを決定するんだよね(周辺は無限遠にあると仮定するので)。

するとフラグメントシェーダはこんなのになる。
{
    highp vec3 ref = reflect(vPosition - eyePosition, vNormal);
    gl_FragColor = textureCube(uTexture, ref);
}
これだけで物体表面のテクスチャに周辺の画像(6枚の画像)が映り込む。単にテクスチャの表示方法を指定してるだけで、オフスクリーンレンダリングも必要なし。
ちょっとこれすごくない?

実際にやってみたところ、、、

キューブマッピングの結果

↑こんな感じになる。
このトーラス、頂点の数が221,184個あるんだわ、、、もっとキレイに映り込みさせようとするならどんなけ必要なんだよー?!って感じ。
iPhone 5sだと60fps出てたけど、touch(5G)だと35fps程度。静止画ならともかくリアルタイムで動かそうとするならちょっと使いどころが難しいかな。

wgld.org | WebGL: キューブ環境マッピング |
↑なお、6枚のテクスチャはここから借りたよ。


Blenderで穴を開けるのはBooleanのDifference

Blenderで例えば板に穴を開けたい時にどうするのか随分と戸惑ったのでメモ。

平面と円柱

↑こんな感じで平面と穴を開ける用の円柱があるとするよ。開けたいところに円柱を動かしておいて、、、


Booleanモディファイア

↑平面を選択してAdd ModifierのBooleanを選択、OperationはDifferenceにしてObjectに円柱を選択する(名前で指定するので名前を調べておくこと)。


穴加工

↑Apply後に円柱を動かすとちゃんと穴が開いてるのがわかる。


メッシュの複雑化

↑ちなみにメッシュがこんな感じになってるので3Dデータで出力する場合なんかはいちいち手動でメッシュを結合させたりしてる。この辺りがちょっとなんとかならないのかなあと思うんだけどさ。


OpenGLでテクスチャの上下ひっくり返す

OpenGLなんだけどGLKitは使わない場合のお話。
GLKitを使うとテクスチャ設定だけでなくいろいろとラクなんだけど、ネット上で見つけられるOpenGLがらみのサンプルなんかはGLKitを使っていないのが多いのでGLKitを使わない場合でも記述できるに越したことはないよね。
GLKitを使わないでテクスチャの設定をしてみたところどうもおかしい。オブジェクトに貼付けられる画像が意図しないのになってる。

反転前の描画

↑こんな感じ。ぱっと見はわかんないだろうけど、GLKit使っていた時のと違うので気が付いたのよ。字が反転してたし。

GLKitを使わない場合のコードはここを参考にしてた。
OpenGL Tutorial for iOS: OpenGL ES 2.0 | Ray Wenderlich
というかそもそもOpenGLの勉強はこのチュートリアルから始めたんだっけな。
このチュートリアルのPart2にテクスチャを読み込んで設定する
- (GLuint)setupTexture:(NSString *)fileName
ってメソッドがあるんだ。リンク先のチュートリアルの内容だと関係ないんだろうけど、どうやらGLKitで作る場合と上下が反転してるみたい(というかGLKitでは反転させてくれてたんだろう)。座標の取り方で生じる問題だそうな。

そんなわけで修正しようとしたらこういう記事が
ios - In UIImage to Texture conversion, Texture is flipped vertically - Stack Overflow
この通りにすればこの通り。

反転後の描画

めでたし、めでたし。


UIImageをOpenGLのテクスチャに使う

OpenGLでオブジェクトに貼付けるテクスチャは今までこんな感じで作っていたのよ。GLKitを使う場合ね。
{
    NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft: @YES};
    NSError *error;
    NSString *path = [[NSBundle mainBundle] pathForResource:@"texture.png" ofType:nil];
    GLKTextureInfo *texture = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error];
}
png画像ファイルをXcodeに持ってきといてから↑のようなコードで作成、使う時は
{
    glBindTexture(GL_TEXTURE_2D, texture.name);
}
といった感じでOK。

ふと、動的な画像を使う場合にはどうすればいいのかな、、、例えばUIImageなんかをテクスチャとして使うとか。ネットで調べてみるとstackoverflowあたりにややこしい処理でやってるのがあるなあ、、、なんて思っていたんだけど、ふとGLKitにあるんじゃないの?と思ってリファレンスを確認したら、ちゃんとあるじゃない!
{
    NSError *error;
    NSDictionary* options = @{GLKTextureLoaderOriginBottomLeft: @YES};
    GLKTextureInfo *texture = [GLKTextureLoader textureWithCGImage:image.CGImage  options:options error:&error];
}
ここでimageはUIImageオブジェクト。ありがたや、GLKit。

UILabelをテクスチャにしたスクショ
↑こんな感じでUILabelで書いた文字なんかをテクスチャとして貼付けてみたところ。


Blenderで面取りはモディファイアのBevelで

Doc:JA/2.6/Manual/Modeling/Meshes/Editing/Subdividing/Bevel - BlenderWiki

Blenderでオブジェクトの面取りをしたくてどうするのかなと調べてみたところモディファイアでいけるっぽい。
(ver2.68)

ところがモディファイアのBevelを適用するとオブジェクト全ての辺が丸くなる。

BlenderのModifier/Bevel

↑Width:0.1, Segments:4の場合。これはこれでいいんだけど。

それじゃ一辺だけとかやるにはどうするのよ?ってしばらく困ったんだけど、、、
どうやら面取りしたい辺にweightなるものを設定するといいらしい。

Bevelの設定でWeightにする

↑モディファイア/Bevelの画面のLimit MethodをWeightに(デフォルトはNone)。

Weightを付ける

↑Editモードで丸めたい辺のみ選択しておいて、control + e の Edge Bevel Weight を選択、カーソルの移動でweightを設定できる。

Bevel設定後のオブジェクト

↑無事一辺だけ丸くなった。


ただ、一つの頂点のみ丸める方法は不明、、、




Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.