Papervision3Dでウォークスルーの実験中。
今回は島を作ってテクスチャ貼ってみたよ。
足元の高さ判定の処理はまだちゃんと組んでないので
穴が開いた地形の下もくぐれないし、高い所から落ちると一瞬で着地します。

今回は島を作ってテクスチャ貼ってみたよ。
足元の高さ判定の処理はまだちゃんと組んでないので
穴が開いた地形の下もくぐれないし、高い所から落ちると一瞬で着地します。

矢印キー:移動
SHIFT+矢印キー:カメラ回転
F:FPSの限界切り替え
W:ワイヤーフレームON/OFF
M:テクスチャの歪み補正ON/OFF
1~4:レンダラ切り替え(デフォルトは1)
PAGE UP:カメラズームイン
PAGE DOWN:カメラズームアウト
HOME:カメラズームリセット
SHIFT+矢印キー:カメラ回転
F:FPSの限界切り替え
W:ワイヤーフレームON/OFF
M:テクスチャの歪み補正ON/OFF
1~4:レンダラ切り替え(デフォルトは1)
PAGE UP:カメラズームイン
PAGE DOWN:カメラズームアウト
HOME:カメラズームリセット
島のモデリング

島は3dsMaxでモデリング。全部で689△ポリゴンです。
Shockwave3Dだったらキャラクター1体に使えるポリ数だね・・・
ポリゴンはもっと減らすこともできたんだけど
ポリゴン大きいとデフォルトのレンダラでテクスチャの歪みとポリゴン欠けが激しいから
平坦な部分も分割しちゃってます。それでもカメラが近いと歪んじゃうけど。

Shockwave3Dだったらキャラクター1体に使えるポリ数だね・・・
ポリゴンはもっと減らすこともできたんだけど
ポリゴン大きいとデフォルトのレンダラでテクスチャの歪みとポリゴン欠けが激しいから
平坦な部分も分割しちゃってます。それでもカメラが近いと歪んじゃうけど。

Papervision3Dで表示するとこんな感じ。
Shaderマテリアルとかは速度を優先して使いませんでした。
バンプマップとか使いたかったな。
DAEデータ内にある各メッシュモデル(TriangleMesh3D)を探す必要があったんですよ。
今まではmax内でつけたモデル名がそのままIDとして使われていて、
DAEファイルを覗かなくても
DAE内部の構成がどうなってるのか気になってトレースするスクリプトを作ってみました。

データは<名前>(クラス名)[座標]の並びになってます。
*はDisplayObject3D以外につきます。見分けやすくする為のただのマークです。
で、赤線部分のTriangleMesh3Dクラスのオブジェクトが今回必要だったメッシュモデルなんですが・・・
maxでつけた名前は「field」「river」「waterfall」です。
でも実際はその1つ下に見覚えのない数字のノードができていて、そっちがメッシュモデルになってしまっています。
原因はわからないけど、とにかくここの<名前>でアクセスすればメッシュモデルが取得できるんで、
実際これでテストしたらうまくいってしまったので問題ないと思っていたんですが・・・
この<数字>と表示されている部分、DAEファイルを覗いてみるとそもそも数字がIDになったノードなんて見当たりません。
おかしいなーと思って該当するメッシュモデルのノードを見ると、名前もIDもついてない。。
つまりこれは、IDが設定されていないノードに勝手に名前がつけられていただけで、
43とか47とかはたまたまその数字になっていただけって事・・・?
何度かテストするとモデルが取得できない事があってその時は数字が違っていたので
ここの名前でアクセスするのはまずい事がわかりました。
これ気づくのにえらい時間かかった。。
自分の環境ではmaxでつけたモデル名のノードの中にメッシュモデル(TriangleMesh3D)があるのは確実だったので、
DisplayObject3Dが内包している全てのTriangleMesh3Dクラスをリストアップするスクリプトを作って解決しました。
実際はこんな感じに使います↓
今回はこれで解決したとはいえ、そもそもなんでIDなしのノードが
余計に作られるようになったのかが謎のままだし
根本的な解決にはなってないけどね。。
テクスチャの歪み補正とレンダラを切り替えられるようにしてあります。
テクスチャの歪み補正は、BitmapMaterialを生成する時に

左がデフォルトの補正無し。カメラに近いところがなんか伸びちゃってるね。
早速補正有りを試してみたところ・・・なんかものすっごい分割されてる。。
てっきりいつもよりちょっと重い処理でテクスチャ描画する程度かなーって考えてたけど
こんなに分割されるんじゃローポリにした意味がない気がするよ。。
ただ、この分割で増えたポリゴンが全ての処理で使われるわけではないようで、
実際こんなに細切れになってもポリゴンの欠け方が補正無しの時と同じでした。
細かくなった分欠けにくくなるわけでもないらしい。うーん
当然分割数に応じて重くなるんだけど、この分割数がカメラの位置にかなり影響されるんで
モデルが沢山見えても軽い時もあればポリゴン数枚で激重になる事もありました。
ウォークスルー系コンテンツでは使いどころが難しい・・・。

こっちはレンダラの切り替えテスト。
デフォルトのBasicRenderは軽い代わりにポリゴン欠けが酷い(左)
ので、QuadrantRenderEngineという高機能レンダラに切り替えてみました(右)
QuadrantRenderEngineに関してはnote.xさんの記事でお勉強しました。
何種類か試したところ、地面に足が潜り込まないようにするだけなら
交差したポリゴンを分割してくれるフィルタ(QUAD_SPLIT_FILTER)もあるんだけど
テクスチャの歪み補正と併用しないと分割時にテクスチャが断層みたいにずれて
しかもカメラが動くたびに再分割するのでピクピク動いてしまいます。
で、当然これ使うと重くなるんですが、問題なのは実は重さの件だけではなくて・・・
カメラが地面に近いところを動く事が多いので
手前のポリゴンが消えてしまうのを防いでいるんですが、
何故かQuadrantRenderEngineとFrustumClippingを組み合わせると
エラーを吐いてFlashが止まってしまう。。
FrustumClippingがQuadrantRenderEngineでは使えないものなのか、それとも設定方法が悪いのか・・・
原因はわからなかったんですが、どうしようもなかったので
サンプルではBasicRender以外クリッピングを無効のままにしてあります。
結局、足元のポリゴン欠けが解消しても手前のポリゴンが消えるという事態に。
クリッピングのやり方が分かるまではこれも使うの難しいな・・・。
ウーンなんか長くなっちゃったね。
水の表現に関してはエントリー分けておきます。
PV3D: 水の流れの表現
Shaderマテリアルとかは速度を優先して使いませんでした。
バンプマップとか使いたかったな。
DAEデータからモデルを探す時にはまった事
そういえば、今回collada(dae)モデル内に複数のモデルが混在していて、DAEデータ内にある各メッシュモデル(TriangleMesh3D)を探す必要があったんですよ。
今まではmax内でつけたモデル名がそのままIDとして使われていて、
DAEファイルを覗かなくても
var mesh:TriangleMesh3D = dae.getChildByName("maxでつけたモデル名", true) as TriangleMesh3D;こうするだけで特定のモデルを探す事ができていたのに今回は何故かうまくいかず。DAE内部の構成がどうなってるのか気になってトレースするスクリプトを作ってみました。
import flash.utils.describeType;
import org.papervision3d.core.proto.DisplayObjectContainer3D;
import org.papervision3d.objects.DisplayObject3D;
public function getObjectTree(obj:DisplayObjectContainer3D):String {
return scanObjectTree(obj, [], 0);
}
private function scanObjectTree(obj:DisplayObjectContainer3D, indents:Array, lv:int = 0):String {
var str:String = "";
var line:String = (lv == 0)? "" : indents.map(function(d:int, i:int, a:Array):String { return (i>=1 && i < lv)? [" │", " "][d] : "" } ).join("") + [" ├", " └"][indents[lv]];
var className:String = describeType(obj).@name.split("::")[1];
var mark:String = (className == "DisplayObject3D")? "" : "*";
var disp:DisplayObject3D = obj as DisplayObject3D;
if (disp != null) {
str = line + "<" + disp.name +">(" +mark + className + ") [" + String(disp.position) + "]\n";
} else {
str = line + "(" + className + ")\n";
}
var count:int = 0;
for each(var d:DisplayObject3D in obj.children) {
indents[lv + 1] = (++count == obj.numChildren)? 1 : 0;
str += scanObjectTree(d, indents, lv+1);
}
return str;
}
DAEファイルのロードが完了した後にtrace(getObjectTree(調べたいDAEオブジェクト));ってやると、↓こんな感じにトレースしてくれます。フォントによっては線がずれるかも。

データは<名前>(クラス名)[座標]の並びになってます。
*はDisplayObject3D以外につきます。見分けやすくする為のただのマークです。
で、赤線部分のTriangleMesh3Dクラスのオブジェクトが今回必要だったメッシュモデルなんですが・・・
maxでつけた名前は「field」「river」「waterfall」です。
でも実際はその1つ下に見覚えのない数字のノードができていて、そっちがメッシュモデルになってしまっています。
原因はわからないけど、とにかくここの<名前>でアクセスすればメッシュモデルが取得できるんで、
dae.getChildByName("43", true);//field取得
dae.getChildByName("47", true);//river取得
dae.getChildByName("49", true);//waterfall取得
これで一件落着かなって思ってました。実際これでテストしたらうまくいってしまったので問題ないと思っていたんですが・・・
この<数字>と表示されている部分、DAEファイルを覗いてみるとそもそも数字がIDになったノードなんて見当たりません。
おかしいなーと思って該当するメッシュモデルのノードを見ると、名前もIDもついてない。。
つまりこれは、IDが設定されていないノードに勝手に名前がつけられていただけで、
43とか47とかはたまたまその数字になっていただけって事・・・?
何度かテストするとモデルが取得できない事があってその時は数字が違っていたので
ここの名前でアクセスするのはまずい事がわかりました。
これ気づくのにえらい時間かかった。。
自分の環境ではmaxでつけたモデル名のノードの中にメッシュモデル(TriangleMesh3D)があるのは確実だったので、
DisplayObject3Dが内包している全てのTriangleMesh3Dクラスをリストアップするスクリプトを作って解決しました。
import org.papervision3d.objects.DisplayObject3D;
public static function getTriangleMeshList(obj:DisplayObject3D):Array {
var list:Array = new Array();
for each(var d:DisplayObject3D in obj.children) {
var childs:Array = getTriangleMeshList(d);
if (childs.length == 0) {
if (describeType(d).@name.split("::")[1] == "TriangleMesh3D") list.push(d);
} else {
list = list.concat(childs);
}
}
return list;
}
引数にDisplayObject3Dを渡すとTriangleMesh3Dを配列で返してくれます。実際はこんな感じに使います↓
//まずモデル名でDisplayObject3Dを取得
var node:DisplayObject3D = dae.getChildByName("モデル名", true);
//その中にあるTriangleMesh3Dを抽出
var field:TriangleMesh3D = getTriangleMeshList(node)[0];
これでやっと目的のモデルが取れるようになりました。ふー。今回はこれで解決したとはいえ、そもそもなんでIDなしのノードが
余計に作られるようになったのかが謎のままだし
根本的な解決にはなってないけどね。。
テクスチャの歪み補正
あと今回色々と重さの比較をしようと思ってテクスチャの歪み補正とレンダラを切り替えられるようにしてあります。
テクスチャの歪み補正は、BitmapMaterialを生成する時に
var mat:BitmapMaterial = new BitmapMaterial(bitmapData, true);こんな感じに第2引数をtrueにしたり、
mat.precise = true;BitmapMaterialオブジェクトのpreciseプロパティをtrueにする事で設定できます。

左がデフォルトの補正無し。カメラに近いところがなんか伸びちゃってるね。
早速補正有りを試してみたところ・・・なんかものすっごい分割されてる。。
てっきりいつもよりちょっと重い処理でテクスチャ描画する程度かなーって考えてたけど
こんなに分割されるんじゃローポリにした意味がない気がするよ。。
ただ、この分割で増えたポリゴンが全ての処理で使われるわけではないようで、
実際こんなに細切れになってもポリゴンの欠け方が補正無しの時と同じでした。
細かくなった分欠けにくくなるわけでもないらしい。うーん
当然分割数に応じて重くなるんだけど、この分割数がカメラの位置にかなり影響されるんで
モデルが沢山見えても軽い時もあればポリゴン数枚で激重になる事もありました。
ウォークスルー系コンテンツでは使いどころが難しい・・・。
レンダラの比較

こっちはレンダラの切り替えテスト。
デフォルトのBasicRenderは軽い代わりにポリゴン欠けが酷い(左)
ので、QuadrantRenderEngineという高機能レンダラに切り替えてみました(右)
QuadrantRenderEngineに関してはnote.xさんの記事でお勉強しました。
何種類か試したところ、地面に足が潜り込まないようにするだけなら
renderer = new QuadrantRenderEngine(QuadrantRenderEngine.CORRECT_Z_FILTER);だけでいける気がします。
交差したポリゴンを分割してくれるフィルタ(QUAD_SPLIT_FILTER)もあるんだけど
テクスチャの歪み補正と併用しないと分割時にテクスチャが断層みたいにずれて
しかもカメラが動くたびに再分割するのでピクピク動いてしまいます。
で、当然これ使うと重くなるんですが、問題なのは実は重さの件だけではなくて・・・
カメラが地面に近いところを動く事が多いので
renderer.clipping = new FrustumClipping(FrustumClipping.NEAR);でレンダラのclippingプロパティにFrustumClippingを設定して
手前のポリゴンが消えてしまうのを防いでいるんですが、
何故かQuadrantRenderEngineとFrustumClippingを組み合わせると
エラーを吐いてFlashが止まってしまう。。
FrustumClippingがQuadrantRenderEngineでは使えないものなのか、それとも設定方法が悪いのか・・・
原因はわからなかったんですが、どうしようもなかったので
サンプルではBasicRender以外クリッピングを無効のままにしてあります。
結局、足元のポリゴン欠けが解消しても手前のポリゴンが消えるという事態に。
クリッピングのやり方が分かるまではこれも使うの難しいな・・・。
ウーンなんか長くなっちゃったね。
水の表現に関してはエントリー分けておきます。
PV3D: 水の流れの表現
自前でライブラリ作っていて他の3D描画ライブラリを参考にしているのですが、
自分では使って調べる気にならずに関連記事あさっていたらたどり着きました。
興味がそそられる記事で面白かったです。
テクスチャの歪みはパースがきつくなったときに出てくるので、
多分PV3D内部でポリゴンを分解してUV値のずれ補正しているのだと思います。
参考→http://www.d-project.com/flex/009_FreeTransform/
PV3Dはクリッピングは出来るのでしょうかね?
色々サンプルを見てるのですがクリッピングというよりカリング的な処理しかしていないモノが多いので何か良いサンプル知っていたら教えて下さいー。
#これからもがんばってくださいな
どうもありがとうございます。
歪む理由と内部でやってる処理はああなってたんですね。>参考サイト
あとクリッピングの定義がイマイチ把握できてなかったりするんですが、
PV3DではカメラのプロパティにnearClippingとfarClippingがあって、
これで近くや遠くのポリゴンを消したりできるようなんですけど
レンダラの方にあるclippingプロパティでシザリング処理をさせないと
近い位置のポリゴンとかを分割してくれずにまるごと消しちゃうみたいなんですよ。
でも自分の環境だとfarClippingを設定すると表示がバグったりで
なんだか色々と不具合がありそうな気がします・・・
PV3Dの勉強をする時に色々参考にさせてもらってるnote.xさんの
http://blog.r3c7.net/?p=229
http://blog.r3c7.net/?p=133
こちらのエントリにPV3Dでのクリッピング周りの事が書かれてました。
しかし自前でライブラリ作るって凄いな~。開発がんばってくださいね。
ちゃんとクリッピングされてると思われるサンプル初めて見ました。
ありがとうございます。>参考サイト
クリッピング(シザリングも同義語みたいです)は
描画領域外にはみ出したポリゴンを切り落とす処理みたいです。
なので、ポリゴンが欠ける時点でクリッピングでは無いと言う事になっちゃいます。
そしてポリゴンが欠けるという事は
おそらくポリゴンを構成する頂点が一つでも描画領域外にはみ出した時点で
ポリゴンそのものを描画対象外にしてしまう処理
=カリングに似た処理しか出来ないのかと思っていたため
前回のコメントで「カリング的」と表現してみました。
しかし面白いですね。クリッピングするのに上下左右前で指定できるなんて。
限定的なアングルのみの3D表現も想定しているからなんでしょうかね。
本来なら描画領域外にはみ出たポリゴンは全てクリッピングするべきだと思うのですが。
常に全方向クリッピングだとやはり重いんですかね(笑
昨日からクリッピングの実装にチャレンジしてますが、
私の妄想ではクリッピング対象のポリゴンは分解する必要がある為、
UV値も補正が入るので極端なテクスチャの歪みはでないと考えているのですが、
このエントリのFrustumClippingを有効にした画像を見ると
FrustumClippingだけではテクスチャの歪みが解消されていないようです。
(ライブラリ内部の処理順序で結果が変わってきてしまう気もしますが。)
もし実装してみて歪みが出ないのだったら
PV3Dのクリッピングはまだ即席レベルのものなのかもしれませんね。
数日で出来ると思うので結果が分かったら改めてコメントしますね。
(コメントなのにかなり長文になってしまって申し訳ないです・・・(;´Д`)
なるほどー
PV3Dのプロパティ名だけで判断しちゃってたけど
実際は色々違うんですね。
ウォークスルーでは足元の地面がカリングされるのは致命的なので
FrustumClipping無しは考えられないんですが
どうにも上手く使えなくて困ってます。。
それにしても3Dのデモ完璧ですね!
クリッピングできたらもう3Dコンテンツ作り放題じゃないですか。