質問するログイン新規登録

Q&A

0回答

483閲覧

[Godot] C++(GDExtension)でのChunk処理(パース/配置/Collision/メッシュ作成)時に20FPS以下まで落ちるため最適化したい

sknewroles

総合スコア0

CMake

CMakeはクロスプラットフォームで作動するオープンソースのビルドシステムです。コマンドライン又は組み込まれた開発環境で使うことができる元のmakefileとプロジェクトファイルを生成します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1グッド

0クリップ

投稿2026/10/05 13:20

編集2026/10/08 13:38

1

0

実現したいこと

Godotにて、C++(GDExtension)を用いてChunk(チャンク)のロード処理(ファイルパース、座標配置、Collision作成、メッシュ作成)を実装しています。
プレイヤーの移動に伴うChunkロード時のフレームレート低下を抑え、快適に動作させたいです。

発生している問題・分からないこと

新規Chunkのロード処理(ファイルパース〜メッシュ・Collision作成)が走る際、フレームレートが一時的に 約15 FPS まで大幅に落ち込んでしまいます。

  1. 下記の処理フロー(ファイルパース → 座標配置 → Collision作成 → メッシュ作成)において、Godot + C++(GDExtension)の構成で特にボトルネックになりやすいポイント(Collision生成、メッシュ構築、Godot API呼出し等)はどこでしょうか?
  2. メインスレッドを止めずに WorkerThreadPool 等を使って非同期(バックグラウンド)でロード・生成処理を行うための推奨設計・アプローチがあればアドバイスをいただきたいです。
  1. ファイルパース: Chunkデータの読み込み・解析
  2. チャンク配置・座標配置: ワールド内での位置確定とブロックデータの配置
  3. あたり判定(Collision)作成: 物理判定(CollisionShape3D等)の生成
  4. メッシュ作成: SurfaceTool や ArrayMesh 等を用いた描画用メッシュの構築・SceneTree追加

該当のソースコード

PlainText

1範囲が大きい為、GitHubにコードをまとめて公開しています。

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果
  • 処理時間の簡易計測:
    Chunkの読み込み時のパフォーマンス低下を確認するためFPSの計測を行ったところ、一時的に約15 FPSまで低下していることが分かりました。

  • Godotでの非同期処理の調査:
    Godot mono 4.7の WorkerThreadPool やC++標準のマルチスレッドを利用し、パースやデータ計算、メッシュ/Collision構築をバックグラウンドスレッドで行う手法についてドキュメントや事例を調べました。

補足

動作環境

  • Godot Engine: Godot mono 4.7 (GDExtension)
  • OS: macOS Golden Gate
  • 言語: C++ (C++17)
katsukoが👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailerrrr

2026/10/20 08:13

ご質問ありがとうございます。コードは拝見できていないため、一般的な傾向として回答します。 1. ボトルネックになりやすい箇所 まず、計測が先です。各工程を `std::chrono` で測り、「パース / 配置 / Collision / メッシュ / add_child」のどこが長いかを出してください。macOSならInstrumentsも使えます。あわせて、GDExtensionをrelease(`target=template_release`)または最適化付きでビルドしているか確認してください。debugビルドのままだと、それだけで数倍遅くなります。 そのうえで、特に重くなりやすいのは次の4点です。 - Collision生成: ブロックごとに `CollisionShape3D` や `BoxShape3D` を作る方式は非常に重いです。`ConcavePolygonShape3D::set_faces()` はBVH構築を伴うので、これも重い処理です。可能なら、Chunk単位で1つのShapeにまとめてください。 - メッシュ構築: `SurfaceTool` で頂点ごとにAPIを呼ぶと、呼び出しとVariant変換のコストが大きくなります。C++側のバッファに頂点を溜め、`PackedVector3Array` などに一括で詰めて `add_surface_from_arrays()` を1回呼ぶ方式が定石です。 - 描画されない面の生成: 隣接ブロックで隠れる面を除外(face culling)していないと、頂点数が数倍に膨れます。余裕があれば、greedy meshingも有効です。 - SceneTreeへの追加: `add_child` の際に、ノードのready処理、Transformの伝播、物理サーバーへの登録がまとめて走ります。これを1フレームに何Chunkも行うとスパイクになります。 2. 非同期化の推奨設計 大きな方針は、「重い計算はワーカー、Godotオブジェクトの接続はメインスレッド」に分けることです。 1. ワーカー側(`WorkerThreadPool::add_task`) - ファイルパース、座標配置、face culling、頂点/インデックスの生成を行います。 - 結果は、Godot APIに依存しない純粋なC++構造体(`std::vector` など)に入れます。 - Collision用のShape(`ConcavePolygonShape3D`)の構築も、Resourceなのでワーカー側で可能です。 2. メインスレッド側 - 完成したChunkを完了キューに積みます。 - `_process` で1フレームあたりの予算(例: 1 Chunk、または2ms以内)だけ取り出し、ノード追加とメッシュ登録を行います。 - ここでスパイクを均すのが、体感に一番効きます。 3. 補足 - SceneTreeの操作(`add_child` 等)をワーカーから直接行わないでください。`call_deferred` か、上記の完了キュー経由にします。 - プレイヤーが移動して不要になったChunkのタスクは、世代番号などでキャンセルするか、結果を捨てられるようにします。 - 距離順に優先度をつけ、近いChunkから生成します。 - 破棄したChunkのノードやメッシュは、プールして再利用できます。 - さらに踏み込むなら、`RenderingServer` と `PhysicsServer3D` を直接使う方法があります。ノードを介さないぶん軽くなります。スレッド安全性はプロジェクト設定(スレッドモデル)に依存するので、ドキュメントで確認してください。 次のステップ 各工程の所要時間(ms)を教えていただければ、どこを優先して直すべきか、より具体的にお答えできます。
sknewroles

2026/10/22 13:53

コメントありがとうございます。言われた通りにコードを修正したら動作が軽くなりました! ベストアンサーに選びたいので同じ内容を回答欄に投稿いただけますでしょうか?
teratailerrrr

2026/10/23 01:08

ご報告ありがとうございます。改善につながったようで何よりです。 それでは、回答欄にも同じ内容を投稿いたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.25%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問