概要
私は現在、Three.jsで3Dタイル状の六角形ボードを作成しています。芸術的および機能的な理由から、タイルはそれぞれ独自のメッシュであり、基本的な(変更されていない)ジオメトリと、そのマテリアルに生成されたマップの配列(変位、拡散、法線)で構成されています。
テクスチャマップを追加すると、FPSの低下に気づき始め、ソースを調べるようになりました。私は15x15のゲームボードを持っています。つまり、フレームごとに225の個別のメッシュがレンダリングされています。当時、各メッシュはデザインが不十分なため215面で構成されていたため、シーンには48,375面が含まれていました。
パフォーマンスの問題を解決できると考えて、メッシュを再設計して、シーン全体で合計6,750面の30面のみを含むようにしました。驚異的な改善。顔を86%減らしても、パフォーマンスにほとんど影響がないことに失望しました。
そこで、パフォーマンスの低下の原因を正確に突き止めることにしました。抽象化されたテスト環境を設定し、3x10の平面のグリッドを使用しました(自分のモデルと同じように、30の面を与えるため)。さまざまなグリッドサイズ(メッシュ数)を試し、さまざまな複雑さのマテリアルを適用しました。これが私が見つけたものです:
材料試験
// /---------------------------------------------------\
// | Material | 15x15 | 20x20 | 25x25 |
// |---------------------|---------|---------|---------|------\
// | Flat Lambert Color | 60FPS | 48FPS | 30FPS | -00% |
// | Lambert Diffuse | 57FPS | 41FPS | 27FPS | -10% |
// | Blank Shader | 51FPS | 37FPS | 24FPS | -20% |
// | Full Shader (-H) | 49FPS | 32FPS | 21FPS | -30% |
// | Full Shader (+H) | 42FPS | 28FPS | 19FPS | -37% |
// \----------------------------------------------------------/
// | -00% | -33% | -55% |
// \-----------------------------/
行:
MeshLambertMaterial({color})
私のベースラインでしたMeshLambertMaterial({map})
パフォーマンスが約10%低下しましたShaderMaterial()
デフォルト設定を使用すると、パフォーマンスが約20%低下しましたShaderMaterial()
ディフューズマップを使用すると、パフォーマンスが約30%低下しました。ShaderMaterial()
Diffuse + Normal + Displacementマップを使用すると、37%のパフォーマンスヒットが発生しました
列:
- 15x15(225メッシュ)が私のベースラインでした
- 20x20(400メッシュ)は33%のパフォーマンスヒットを受けました
- 25x25(625メッシュ)は55%のパフォーマンスヒットを受けました
あらすじ
そのため、使用しているシェーダーと適用しているマップから大きなヒットがあったことを知りました。ただし、「モノ」の量からははるかに大きなヒットがあります。これが面なのかメッシュなのかわからなかったので、別のテストを実行しました。ベースラインマテリアル(MeshLambertMaterial({ color: red })
)を使用して、2つの変数をテストすることにしました。辺の数とメッシュの数です。これが私が見つけたものです:
顔/メッシュカウントテスト
// 15x15 (225) Meshes @ 30 Faces = 6,750 Faces = 60 FPS
// 20x20 (400) Meshes @ 30 Faces = 12,000 Faces = 48 FPS
// 25x25 (625) Meshes @ 30 Faces = 18,750 Faces = 30 FPS
// 30x30 (900) Meshes @ 30 Faces = 27,000 Faces = 25 FPS
// 40x40 (1600) Meshes @ 30 Faces = 48,000 Faces = 15 FPS
// 50x50 (2500) Meshes @ 30 Faces = 75,000 Faces = 10 FPS
// 15x15 (225) Meshes @ 100 Faces = 22,500 Faces = 60 FPS
// 15x15 (225) Meshes @ 400 Faces = 90,000 Faces = 60 FPS
// 15x15 (225) Meshes @ 900 Faces = 202,500 Faces = 60 FPS
シンポシス
これは、関係する面の数がフレームレートにほとんど影響しないことを非常に決定的に示しているようです。むしろ、シーンに描画される個々のメッシュの量によって、実質的にすべてのパフォーマンスドラッグが作成されます。何がそのような遅れを正確に引き起こしているのかわかりません。メッシュごとに大量のオーバーヘッドがあると思います。おそらく、このオーバーヘッドの一部を排除する方法はありますか?
考慮事項
私はすでに自分のジオメトリをマージすることを検討しました。これにより、フレームレートの低下がほぼ完全に解消されます。ただし、この記事の冒頭で述べたように、各タイルは個別に翻訳可能、回転可能、スケーラブル、その他の方法で変更可能である必要があります。私の知る限り、これはマージされたジオメトリでは不可能です。
また、デフォルトでマージされたジオメトリを使用し、タイルを変更する関数が呼び出されたときにジオメトリ/シーンを再作成することも検討しました。ただし、このアプローチには2つの問題があります。
- ボード上に200〜400の個別のメッシュがあり、マージされている場合、処理に1000ミリ秒以上かかる可能性があり、目立った視覚的なスタッターが発生する可能性があります。
- すべてのタイルを同時に「揺さぶる」または「ぐらつく」可能性があるような大きな効果は、現在のボードと同じように遅れ、それらを実装する理由はありません。
私は、このパフォーマンスへの影響を回避しようとするのではなく、それを排除する解決策を見つけたいと思っています。
質問
それは私の質問に私をもたらします:大量の個々のメッシュをレンダリングするためのより効率的な方法はありますか?