# PathRibbonMesh2D の概要（触手テクスチャを含む）

**URL:** https://guild.rpgmakerofficial.com/t/topic/1098
**Category:** 一般
**Created:** [2026 年 1 月 13 日午前 7:40 UTC](https://guild.rpgmakerofficial.com/t/topic/1098 "2026-01-13T07:40:55Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![Shirokishi](https://avatars.discourse-cdn.com/v4/letter/s/df788c/32.png) [@Shirokishi](https://guild.rpgmakerofficial.com/u/Shirokishi)
#### Post date: [2026 年 1 月 13 日午前 7:40 UTC](https://guild.rpgmakerofficial.com/t/topic/1098/1 "2026-01-13T07:40:55Z")

</div>

## 概要

`PathRibbonMesh2D` は、指定された `Path2D.curve` をベイクして取得した一連の点に沿って、リボン形状の2Dメッシュを生成します。  
このスクリプトを使用すると、パスに沿って伸びる蔓や触手などのエフェクト、攻撃の軌跡エフェクトなどを作成できます。  
エフェクト中にZ順序を変更して描画順序を調整することで、オブジェクトに貫通したり、巻き付いたりする表現が可能です。  
 ![Videotogif (1)](https://us1.discourse-cdn.com/flex002/uploads/rpgmaker_community/original/2X/d/dffea3455b02954f691d733b5ff1a5a00cd3d1c4.gif)  
 ![Videotogif](https://us1.discourse-cdn.com/flex002/uploads/rpgmaker_community/original/2X/8/8fb3f8a0fa2d6cf0f57081e1f0f9606c05c7eee4.gif)  
 ![tentacle_thighten](https://us1.discourse-cdn.com/flex002/uploads/rpgmaker_community/original/2X/a/a348c40ca67cce3414d1c81845079dc64abc09d4.gif)

[path\_ribbon\_mesh\_2d.gd](https://guild.rpgmakerofficial.com/uploads/short-url/7asY4WXuCs3eJBLERqDV754R60d.gd) (54.9 KB)

[tentacle\_texture.zip](https://guild.rpgmakerofficial.com/uploads/short-url/mPfKwMhwdLuZas6TGWYZzjEVzMq.zip) (570.3 KB)

[tentacle\_project.zip](https://guild.rpgmakerofficial.com/uploads/short-url/3w52cyqV5Dd36LhdhL0HIgSvqed.zip) (2.2 MB)

* * *

## 機能

レンダリングは、このノードの子として作成される自動生成された `MeshInstance2D` によって行われます。このスクリプトは、表示範囲の指定、幅変化カーブ、UVスケーリングと回転、鋭角でのミター処理、位置に基づく `z_index` の段階的な切り替えをサポートしています。

このスクリプトは、生成された `MeshInstance2D` ノードをスクリプト管理オブジェクトとして扱い、設定の変更や分割条件の変更時に再生成または破棄を行います。

## 前提条件と要件

これは Godot 4.x の2Dノード構成を対象に設計されています。

必要な条件は以下の通りです。

- `path_node` に `Path2D` が割り当てられている必要があります。
- `path_node.curve` は `Curve2D` として設定されている必要があります。
- ベイクされた点リストには、少なくとも2つの点が含まれている必要があります。

視覚的な外観は `ribbon_texture` と `blend_material` に依存します。テクスチャが割り当てられていなくてもメッシュ自体は生成されますが、最終的な外観はマテリアルの実装に依存します。

## セットアップ

1. `Path2D` を配置し、その `Curve2D` を編集して形状を作成します。
2. このスクリプトを `Node2D` にアタッチします。
3. ステップ1の `Path2D` を `path_node` に割り当てます。
4. `width` を設定します。
5. 視覚的な外観が必要な場合は、`ribbon_texture` と `blend_material` を設定します。
6. 必要に応じて、表示範囲、太さカーブ、UV設定、鋭角処理、Zキーフレームを設定します。

## 生成ノード仕様

`MeshInstance2D` がこのノードの子として自動的に生成されます。生成されたノードには `_path_ribbon_mesh2d_generated` というメタデータがあり、スクリプトによって管理されます。

- `use_center_split = true` の場合、2つのメッシュ（上側と下側）が生成されます。ノード名は `RibbonUpper_###` と `RibbonLower_###` です。中心線を共有し、上側は中心から上方へ、下側は中心から下方へ展開し、三角形を構築します。
- `use_center_split = false` の場合、1つのメッシュが生成されます。ノード名は `RibbonSingle_###` です。リボンの表面は、上辺と下辺を接続して構築されます。

`z_keyframes_percent_and_z` により `z_index` が変更される位置では、セグメントが分割され、複数の `MeshInstance2D` ノードが生成される場合があります。境界点は共有され、目立つ継ぎ目を減らします。

## 使用例

| 目標（ユースケース） | 設定 | 結果 | 備考 |
| --- | --- | --- | --- |
| パス全体を表示 | `start_percent=0`, `progress_percent=100`, `slide_offset_percent=0` | パス全体にリボンが表示される | `width_curve` が一定の1.0の場合、幅は一定になる |
| 先端を延ばす | `start_percent` を固定し、`progress_percent` を0→100でアニメーション | セクションの端が伸びる | `progress_percent < start_percent` の場合、`start_percent` にクランプされ、逆方向のセクションは作成されない |
| 長さを固定して位置のみを移動 | 表示長さを `progress_percent-start_percent` で設定し、`slide_offset_percent` を変更 | セクションがスライドしながら表示長さを維持 | 開始位置は `0..(100-VisibleLength)` に制限される |
| 太さの変化をパス上の絶対位置に固定 | `thickness_domain_mode=FullPathAbsolute`、`width_curve` を設定 | 表示範囲が変わっても、同じ距離位置の太さは同じまま | 部分表示やスライド中も、太さの位相は固定されたままになる |
| 太さの変化を表示範囲に追従させる | `thickness_domain_mode=VisibleRangeNormalized`、`width_curve` を設定 | 表示範囲を0..1に正規化して太さが決定される | 表示範囲を変更すると、太さの位相も移動する |
| 上側と下側で異なる太さ比を使用 | `use_center_split=true`、`upper_width_curve` / `lower_width_curve` に異なる形状を設定 | 中心線に対して上下で展開が異なる | 上側のみ細く、または下側のみ太くすることも可能 |
| 進行方向に沿ってテクスチャを繰り返す | `ribbon_texture` を設定し、`uv_scale.x` を増加 | U方向のタイル数が増加 | マテリアルとテクスチャ設定に依存する |
| テクスチャの角度を変更 | `texture_rotation_degrees` を設定し、必要に応じて `uv_rotation_mode=TileLocalWrapRotation` を設定 | UVが回転し、パターンの角度が変更される | タイル化に使用する場合、タイルローカルの回転が有利な場合がある |
| 位置によって描画順序を切り替え | `z_keyframes_percent_and_z` に複数の `Vector2(percent,z)` エントリを設定 | パスに沿って `z_index` が段階的に切り替わる | Zが変更される箇所でセグメントが分割され、描画順序が安定化する |
| 滑らかさとコストのバランス | 滑らかさのために `bake_interval` を小さく、コスト低減のために大きく設定 | カーブの忠実度と更新コストのトレードオフ | 重複する点が多い場合、重複排除により頂点生成コストを削減できる |

* * *

## プロパティ一覧

| プロパティ | 型 / デフォルト | 説明（動作 / 計算 / 備考） |
| --- | --- | --- |
| `path_node` | `Path2D` / (未設定) | リボン生成のソース `Path2D`。`path_node == null` の場合、生成されたすべてのメッシュが非表示になる。`path_node.curve == null` の場合、エラー（`push_error`）を報告し、同様に非表示になる。スクリプトはカーブ参照の置換（例：`Curve2D` インスタンスの置換）を監視し、置換を検出するとベイクキャッシュを破棄してメッシュ更新をスケジュールする。 |
| `width` | `float` / `40.0` | 基本幅（ピクセル）。各点の「幅係数」（`width_curve` など）で乗算し、その後2で割って法線方向に頂点をオフセットする。センター分割の場合、「中心→上側」と「中心→下側」のオフセットが個別に計算される。負の値はクランプされないため、実用上は `>= 0` として扱うべきである。 |
| `uv_scale` | `Vector2` / `(1,1)` | UV（テクスチャ座標）に適用されるスケール。適用方法は `uv_scale_apply_mode` に依存する。Uは線上の進行方向（表示範囲内での0..1）、Vはリボン全体（0..1）である。センター分割の場合、中心線はV=0.5を「中心線」として使用する。 |
| `bake_interval` | `float` / `1.0` | `curve.get_baked_points()` を取得する前に `Curve2D.bake_interval` を設定する。値が変更された場合やカーブが置換された場合、ベイクキャッシュ（点と累積距離）が再生成される。値が小さいほど点の数と滑らかさが増すが、更新コスト（点処理＋メッシュ生成）が高くなる。 |
| `start_percent` | `int` / `0` | 表示範囲の開始位置（0〜100）。`_process` で0..100にクランプされる。実際の表示計算時には、`progress_percent` に対して「開始 \> 終了」にならないように調整される（以下参照）。 |
| `progress_percent` | `int` / `100` | 表示範囲の終了位置（0〜100）。0..100にクランプされ、`progress_percent < start_percent` の場合は `start_percent` に強制的に一致させられる。つまり、逆方向のセクションは作成されず、少なくとも「長さ0」のセクションになる。 |
| `slide_offset_percent` | `int` / `0` | 表示長さを保ったまま開始位置のみを移動する。内部処理：`span_p = progress-start`（0..100）を計算し、`s_p = start + slide_offset` を `0..(100-span_p)` に制限する。終了位置は `e_p = s_p + span_p` となる。これにより「固定長、移動位置」が保証される。 |
| `sharp_bend_mode` | `bool` / `false` | コーナー処理を切り替える。`false` の場合、前後の方向ベクトルをブレンドして中心方向を構築し、その法線を使用してリボンを展開する（より穏やかなコーナー成長）。`true` の場合、前後の法線をブレンドしてミター方向を構築し、`join_scale`（ストレッチ係数）を計算する。鋭い角度では大きくストレッチされるため、`miter_limit` が実質的な安全上限として機能する。 |
| `ribbon_texture` | `Texture2D` / (未設定) | 生成された各 `MeshInstance2D.texture` に割り当てられる。さらに、`shader_texture_param_name` が空ではなく、マテリアルが `ShaderMaterial` の場合、同じテクスチャがシェーダーパラメータとして設定される（以下参照）。テクスチャがなくてもメッシュは生成されるが、外観はマテリアル設定に依存する。 |
| `blend_material` | `Material` / `null` | 生成された各 `MeshInstance2D.material` に適用されるソースマテリアル。`null` の場合、マテリアルは割り当てられない。エディタでは、`changed` シグナル（参照されるマテリアルが編集されたとき）を監視し、変更時に再適用をスケジュールする。 |
| `material_unique_per_instance` | `bool` / `true` | `true` の場合、`blend_material.duplicate(false)` によりローカルマテリアルを作成し、インスタンスごとに割り当てる。`false` の場合、`blend_material` の参照をそのまま共有する。共有すると編集が他のオブジェクトに影響するが、複製すると効果が隔離される代わりにマテリアル数が増加する。 |
| `shader_texture_param_name` | `StringName` / `""` | ローカルに適用されるマテリアルが `ShaderMaterial` の場合にのみ使用される。空でない場合、`set_shader_parameter(shader_texture_param_name, ribbon_texture)` を呼び出す。シェーダーがそのuniformを定義していない場合、設定しても効果がない（または警告が出る）ため、名前はシェーダーの実装と一致させる必要がある。 |
| `texture_rotation_degrees` | `float` / `0.0` | UVを回転させる。0の場合、回転はスキップされる。回転中心は `(0.5, 0.5)` であり、方法は `uv_rotation_mode` に依存する。タイル化されたUV（U \> 1 など）を使用する場合、外観が異なる可能性があるため、適切な `uv_rotation_mode` を選択すること。 |
| `uv_rotation_mode` | `enum` / `LegacyWholeUVRotation` | UV回転モード。`LegacyWholeUVRotation` は、タイルの境界でアーティファクトが発生する可能性があるが、UV空間全体をそのまま回転させる。`TileLocalWrapRotation` は `fposmod` を使用して小数部（0..1）を抽出し、タイル内で回転してから整数タイルインデックスを復元する。これは「各タイル内で回転」になり、繰り返しテクスチャとよく機能する。 |
| `uv_scale_apply_mode` | `enum` / `LegacyMultiplyVectorByUVScale` | UVスケールモード。`LegacyMultiplyVectorByUVScale` は `Vector2(u, v) * uv_scale` を単一の乗算として適用する。`SeparateXYScale` は `uv_scale.x` / `uv_scale.y` でUとVを個別にスケールする。センター分割における中心線（V=0.5）も同様にスケールされる。 |
| `miter_limit` | `float` / `2.5` | `sharp_bend_mode = true` の場合、これはコーナーにおける `join_scale`（オフセット乗数）の上限値である。係数は前方法線とのドット積から導出されるが、非常に鋭い角度では無限大に近づくため、この上限は極端なストレッチを防ぐ。値が高いほどコーナーは鋭く/長くなり、値が低いほどコーナーの成長が抑制される。 |
| `width_curve` | `Curve` / `Curve.new()` | 幅係数の基本カーブ。各点について `t_width` を計算し、`width_curve.sample(t_width)` を係数として `width` に乗算する。サンプリング値が負の場合、0にクランプされる。`_ready` でカーブに点がない場合、(0,1) と (1,1) が自動的に追加され、デフォルトで「一定の幅」になる。 |
| `upper_width_curve` | `Curve` / `Curve.new()` | センター分割（`use_center_split = true`）時の上側の幅係数カーブ。上側のオフセット距離は `base_half * upper_factor * join_scale` である。空の場合、`_ready` で一定の1.0に初期化される。 |
| `lower_width_curve` | `Curve` / `Curve.new()` | センター分割時の下側の幅係数カーブ。下側のオフセット距離は `base_half * lower_factor * join_scale` である。空の場合、`_ready` で一定の1.0に初期化される。 |
| `thickness_domain_mode` | `enum` / `VisibleRangeNormalized` | サンプリング位置 `t_width` の基準を切り替える。`VisibleRangeNormalized` の場合、現在表示されている距離範囲 `[start_len, end_len]` を0..1に正規化して `t_width` を計算する（表示範囲を変更すると、同じ絶対位置でも `t_width` が変化する）。`FullPathAbsolute` の場合、パス全体を0..1として扱い、`t_width = dist / total_len` を使用する（表示範囲を変更しても、同じ距離位置の `t_width` は変わらない）。 |
| `use_center_split` | `bool` / `true` | メッシュ生成モード。`true` の場合、中心線を共有する2つのメッシュ（Upper/Lower）を生成する。上側は「中心→上側」から三角形を構築し、下側は「中心→下側」から構築する。`false` の場合、「上側→下側」を接続してリボン表面を形成する単一メッシュ（Single）を生成する。切り替え時に、生成ノード配列を再構築し、ウォッチャー（カーブ変更監視）を再接続する。 |
| `bake_point_dedup_enabled` | `bool` / `true` | ベイクされた点の重複排除を有効にする。`Curve2D.get_baked_points()` の結果において、連続する点の距離が `<= bake_point_dedup_epsilon` の場合、重複が削除される。多くの小さな重複点を持つカーブにおける不要な作業（頂点生成／インデックス生成）を削減することを意図している。 |
| `bake_point_dedup_epsilon` | `float` / `0.0005` | 重複排除の距離閾値。実装は二乗距離を比較し、`(p - last).length_squared() > eps^2` の場合のみ点を保持する。`<= 0` の場合、実質的に無効になる。大きすぎるとカーブ形状が粗くなる。 |
| `profiling_enabled` | `bool` / `false` | プロファイリングを有効にする。内部で `Time.get_ticks_usec()` を使用し、ラベルごとに合計時間と回数を累積する。 |
| `profiling_print_each_event` | `bool` / `true` | `profiling_enabled = true` の場合、各イベントの測定結果を出力する。イベントごとの出力が不要な場合は `false` に設定する。 |
| `profiling_print_threshold_usec` | `int` / `0` | イベント出力の閾値（usec）。`<= 0` ですべて出力、`>= 1` で閾値以上のイベントのみ出力する。重い部分のみ抽出する場合に有用。 |
| `profiling_dump_after_first_flush` | `bool` / `true` | 最初の `_flush_updates` 完了後にサマリー（合計／カウント／平均）を出力する。初期実行のみが必要な場合に有用。 |
| `debug_print_range_stats` | `bool` / `true` | 各メッシュ更新時、表示範囲（%）、距離範囲（開始/終了/合計）、U範囲、`t_width` 範囲、`thickness_domain_mode` を出力する。動作確認を目的としている。 |
| `z_keyframes_percent_and_z` | `Array[Vector2]` / `[(0,0),(100,0)]` | Zキーフレーム。各要素は `Vector2(percent, z)` として扱われる。処理：(1) 作業用配列を作成するために percent を0..100にクランプ (2) percent 昇順でソート（同値の場合、z 昇順） (3) 任意の percent に対して、percent が `<=` その値である最後のキーを採用（ステップ） (4) `z` を丸めて int に変換し、`MeshInstance2D.z_index` に割り当てる。Zが変更される箇所でセグメントが分割され、継ぎ目を減らすために境界点が共有される。 |

## 典型的な運用パターン

- **パス全体を表示する固定リボン**  
`start_percent = 0`、`progress_percent = 100`、`slide_offset_percent = 0` を設定し、`width_curve` を一定の1.0にすることで、一定幅のリボンを作成する。
- **セクションを時間とともに延ばす**  
`start_percent` を固定し、`progress_percent` を0→100でアニメーションさせて表示範囲を延ばす。`progress_percent < start_percent` は許可されず、`start_percent` にクランプされる。
- **表示長さを固定して位置のみを移動**  
`start_percent` と `progress_percent` の差が表示長さになる。`slide_offset_percent` を使用することで、その差を保ったまま開始位置のみを移動できる。移動可能な範囲は `0..(100 - visible_length)` に制限される。
- **太さの変化が表示範囲に追従するか、固定されるかを選択**  
`thickness_domain_mode = VisibleRangeNormalized` の場合、サンプリングは0..1に正規化された表示範囲に基づいているため、表示範囲を変更すると太さの位相もシフトする。`FullPathAbsolute` の場合、サンプリングはパス全体を0..1として使用するため、表示範囲が変わっても同じ距離位置の太さは同じままになる。

---

<div class="post-metadata">

### Author: ![Justus](https://sea2.discourse-cdn.com/flex002/user_avatar/guild.rpgmakerofficial.com/justus/32/55_2.png) [@Justus](https://guild.rpgmakerofficial.com/u/Justus)
#### Post date: [2026 年 1 月 13 日午前 8:56 UTC](https://guild.rpgmakerofficial.com/t/topic/1098/2 "2026-01-13T08:56:08Z")

</div>

とてもクールな効果ですね！
