Использование навигационных сеток
2D- и 3D-версии навигационной сетки доступны как NavigationPolygon и NavigationMesh соответственно.
Примечание
Навигационная сетка описывает только проходимую область относительно центрального положения агента. Любые значения радиуса, которые может иметь агент, игнорируются. Чтобы поиск пути учитывал размер агента (коллизию), необходимо соответствующим образом сжать навигационную сетку.
Навигация работает независимо от других компонентов движка, таких как рендеринг и физика. Навигационные сетки — единственное, что учитывается при поиске пути, например, визуальные данные и формы столкновений, полностью игнорируются навигационной системой. Если при поиске пути необходимо учитывать другие данные (например, визуальные данные), необходимо соответствующим образом адаптировать навигационные сетки. Процесс учёта ограничений навигации в навигационных сетках обычно называется запеканием навигационных сеток.
Навигационная сетка описывает поверхность, на которой агент может безопасно стоять своим центром, в отличие от физических фигур, которые описывают внешние границы столкновений.
Если при следовании по навигационным маршрутам у вас возникли проблемы с застреванием или столкновением, всегда помните, что вам необходимо сообщить навигационной системе о своих намерениях с помощью соответствующей навигационной сетки. Сама по себе навигационная система никогда не определит, что это форма столкновения дерева/камня/стены или визуальная сетка, поскольку она знает только: "Здесь мне сказали, что я могу безопасно пройти по этому маршруту, потому что он находится на навигационной сетке".
Запекание навигационной сетки можно выполнить либо с помощью NavigationRegion2D или NavigationRegion3D, либо напрямую с помощью API NavigationServer2D и NavigationServer3D.
Создание навигационной сетки с помощью NavigationRegion
Запекание навигационной сетки со смещением радиуса агента относительно геометрии.
Запекание навигационной сетки стало более доступным благодаря узлу NavigationRegion. При запекании с использованием узла NavigationRegion отдельные этапы анализа, запекания и обновления региона объединяются в одну функцию.
Узлы доступны в 2D и 3D как NavigationRegion2D и NavigationRegion3D соответственно.
Совет
Навигационную сетку source_geometry_mode можно переключить на анализ определенных имен групп узлов, чтобы узлы, которые необходимо запечь, можно было разместить в любом месте сцены.
При выборе узла NavigationRegion2D в редакторе на верхней панели Редактора появляются параметры запекания, а также инструменты рисования многоугольников.
Для работы региона необходимо добавить ресурс NavigationPolygon.
Свойства для анализа и создания навигационной сетки затем становятся частью используемого ресурса и могут быть найдены в инспекторе ресурсов.
На результат анализа исходной геометрии можно повлиять с помощью следующих свойств.
Параметр
parsed_geometry_typeопределяет, следует ли анализировать визуальные объекты, физические объекты или и те, и другие из SceneTree. Подробнее о том, какие объекты анализируются и как, см. в разделе об анализе исходной геометрии ниже.collision_maskфильтрует, какие физические объекты столкновений включаются, когдаparsed_geometry_typeвключает статические коллайдеры.source_geometry_mode, который определяет, с какого узла (узлов) начинать анализ и как обходить SceneTree.source_geometry_group_nameиспользуется, когда требуется проанализировать только определённую группу узлов. Зависит от выбранногоsource_geometry_mode.
После добавления исходной геометрии результат запекания можно контролировать с помощью следующих свойств.
cell_sizeзадает размер сетки растеризации и должен соответствовать размеру навигационной карты.agent_radiusсжимает запеченную навигационную сетку, чтобы иметь достаточный запас для размера агента (столкновения).
Запекание NavigationRegion2D также можно использовать во время выполнения скриптов.
var on_thread: bool = true
bake_navigation_polygon(on_thread)
bool onThread = true;
BakeNavigationPolygon(onThread);
Чтобы быстро протестировать 2D-выпечку с настройками по умолчанию:
Добавьте NavigationRegion2D.
Добавьте ресурс NavigationPolygon к NavigationRegion2D.
Добавьте Polygon2D под NavigationRegion2D.
Нарисуйте 1 контур NavigationPolygon с помощью выбранного инструмента рисования NavigationRegion2D.
Нарисуйте 1 контур Polygon2D внутри контура NavigationPolygon с помощью выбранного инструмента рисования Polygon2D.
Нажмите кнопку «bake (запекать)» в редакторе, и должна появиться навигационная сетка.
Если в редакторе выбран узел NavigationRegion3D, в верхней панели редактора появляются параметры запекания.
Для работы региона необходимо добавить ресурс NavigationMesh.
Свойства для анализа и создания навигационной сетки затем становятся частью используемого ресурса и могут быть найдены в инспекторе ресурсов.
На результат анализа исходной геометрии можно повлиять с помощью следующих свойств.
Параметр
parsed_geometry_typeопределяет, следует ли анализировать визуальные объекты, физические объекты или и те, и другие из SceneTree. Подробнее о том, какие объекты анализируются и как, см. в разделе об анализе исходной геометрии ниже.collision_maskфильтрует, какие физические объекты столкновений включаются, когдаparsed_geometry_typeвключает статические коллайдеры.source_geometry_mode, который определяет, с какого узла (узлов) начинать анализ и как обходить SceneTree.source_geometry_group_nameиспользуется, когда требуется проанализировать только определённую группу узлов. Зависит от выбранногоsource_geometry_mode.
После добавления исходной геометрии результат запекания можно контролировать с помощью следующих свойств.
cell_sizeиcell_heightзадают размер сетки вокселей растеризации и должны соответствовать размеру навигационной карты.agent_radiusсжимает запеченную навигационную сетку, чтобы иметь достаточный запас для размера агента (столкновения).agent_heightисключает области из навигационной сетки, где агент слишком высокий, чтобы вписаться.agent_max_climbиagent_max_slopeудаляют области, где разница высот между соседними вокселями слишком велика или где их поверхность слишком крутая.
Предупреждение
Слишком маленькое значение cell_size или cell_height может привести к созданию такого количества вокселей, что игра может зависнуть или даже вылететь.
Запекание NavigationRegion3D также можно использовать во время выполнения скриптов.
var on_thread: bool = true
bake_navigation_mesh(on_thread)
bool onThread = true;
BakeNavigationMesh(onThread);
Чтобы быстро протестировать 3D-выпечку с настройками по умолчанию:
Добавьте NavigationRegion3D.
Добавьте ресурс NavigationMesh в NavigationRegion3D.
Добавьте MeshInstance3D под NavigationRegion3D.
Добавьте PlaneMesh к MeshInstance3D.
Нажмите кнопку «bake (запекать)» в редакторе, и должна появиться навигационная сетка.
Создание навигационной сетки с помощью NavigationServer
NavigationServer2D и NavigationServer3D имеют функции API для индивидуального вызова каждого этапа процесса запекания навигационной сетки.
parse_source_geometry_data()можно использовать для разбора исходной геометрии в повторно используемый и сериализуемый ресурс.bake_from_source_geometry_data()можно использовать для создания навигационной сетки из уже проанализированных данных, например, чтобы избежать проблем с производительностью во время выполнения при (избыточном) анализе.bake_from_source_geometry_data_async()— то же самое, но запекает навигационную сетку, отложенную с потоками, не блокируя основной поток.
По сравнению с NavigationRegion, NavigationServer обеспечивает более точный контроль над процессом запекания навигационной сетки. Он, в свою очередь, сложнее в использовании, но и предоставляет более расширенные возможности.
Вот некоторые другие преимущества NavigationServer по сравнению с NavigationRegion:
Сервер может анализировать исходную геометрию без запекания, например, чтобы кэшировать ее для последующего использования.
Сервер позволяет вручную выбрать корневой узел, с которого следует начать разбор исходной геометрии.
Сервер может принимать и выпекать данные из процедурно сгенерированных исходных геометрических данных.
Сервер может запекать несколько навигационных сеток последовательно, используя (повторно) одни и те же исходные геометрические данные.
Для запекания навигационных сеток с помощью NavigationServer требуется исходная геометрия. Исходная геометрия — это геометрические данные, которые следует учитывать при запекании навигационной сетки. Навигационные сетки для 2D и 3D создаются путём запекания исходной геометрии.
2D- и 3D-версии ресурсов исходной геометрии доступны как NavigationMeshSourceGeometryData2D и NavigationMeshSourceGeometryData3D соответственно.
Исходная геометрия может быть получена из визуальных сеток, из физических столкновений или из процедурно созданных массивов данных, таких как контуры (2D) и треугольные грани (3D). Для удобства исходная геометрия обычно анализируется непосредственно из настроек узлов в SceneTree. При повторном запекании навигационных сеток во время выполнения имейте в виду, что анализ геометрии всегда происходит в основном потоке.
Примечание
SceneTree не является потокобезопасным. Анализ исходной геометрии из SceneTree может выполняться только в основном потоке.
Предупреждение
Данные визуальных сеток и полигонов необходимо получать от графического процессора, что приводит к остановке сервера рендеринга. Для запекания (ре)запекания в реальном времени предпочтительно использовать физические фигуры в качестве проанализированной исходной геометрии.
Исходная геометрия хранится внутри ресурсов, поэтому созданную геометрию можно использовать повторно для нескольких запеканий. Например, для запекания нескольких навигационных сеток для агентов разных размеров из одной исходной геометрии. Это также позволяет сохранять исходную геометрию на диск для последующей загрузки, например, чтобы избежать накладных расходов на её повторный анализ во время выполнения.
Геометрические данные, как правило, должны быть максимально простыми. Необходимо максимальное количество рёбер, но как можно меньше. Особенно в двумерных моделях следует избегать дублирования и вложенности геометрии, поскольку это приводит к необходимости вычисления отверстий полигонов, что может привести к перевёртыванию полигонов. Примером вложенной геометрии может служить небольшая фигура StaticBody2D, полностью помещённая внутрь другой фигуры StaticBody2D.
Выпекание фрагментов navigation mesh (навигационной сетки) для больших миров
Создание и обновление отдельных фрагментов навигационной сетки во время выполнения.
См. также
Запекание фрагментов навигационной сетки можно увидеть в действии в демонстрационных проектах Navigation Mesh Chunks 2D и Navigation Mesh Chunks 3D.
Чтобы избежать несоответствия краёв между различными фрагментами региона, навигационные сетки обладают двумя важными свойствами для процесса запекания навигационной сетки: границей запекания и размером границы. Вместе они могут использоваться для обеспечения идеального выравнивания краёв между фрагментами региона.
Кусок навигационной сетки, запеченный с запеченным краем или запеченный с дополнительным размером рамки.
Граница запекания, которая представляет собой выровненный по осям Rect2 для 2D и AABB для 3D, ограничивает используемую исходную геометрию, отбрасывая всю геометрию, которая находится за пределами границ.
Свойства baking_rect и baking_rect_offset класса NavigationPolygon можно использовать для создания и размещения 2D-границы запекания.
Свойства filter_baking_aabb и filter_baking_aabb_offset класса NavigationMesh можно использовать для создания и размещения границы 3D-запекания.
При задании только границы запекания остаётся ещё одна проблема. На результирующую навигационную сетку неизбежно повлияют необходимые смещения, такие как agent_radius, из-за чего края не будут выравниваться должным образом.
Фрагменты навигационной сетки с заметными зазорами из-за смещения радиуса запеченного агента.
Именно здесь пригодится свойство border_size для навигационной сетки. Размер границы — это внутренний отступ от границы запекания. Важной характеристикой размера границы является то, что на него не влияют большинство смещений и постобработки, например, agent_radius.
Вместо того, чтобы отбрасывать исходную геометрию, размер границы отбрасывает части конечной поверхности запечённой навигационной сетки. Если граница запекания достаточно велика, размер границы может удалить проблемные части поверхности, оставив только фрагмент нужного размера.
Фрагменты навигационной сетки с выровненными краями и без зазоров.
Примечание
Границы запекания должны быть достаточно большими, чтобы включать в себя разумное количество исходной геометрии из всех соседних фрагментов.
Предупреждение
В 3D функциональность размера границы ограничена осью xz.
Распространенные проблемы с запеканием навигационной сетки
При создании или запекании навигационных сеток следует учитывать некоторые распространенные проблемы пользователей и важные предостережения.
- Запекание навигационной сетки создает проблемы с частотой кадров во время выполнения
Запекание навигационной сетки по умолчанию выполняется в фоновом потоке, поэтому, пока платформа поддерживает потоки, фактическое запекание редко является источником каких-либо проблем с производительностью (при условии разумного размера и сложной геометрии для повторного запекания во время выполнения).
Распространенным источником проблем с производительностью во время выполнения является этап анализа исходной геометрии, включающий узлы и SceneTree. SceneTree не является потокобезопасным, поэтому все узлы необходимо анализировать в основном потоке. Некоторые узлы с большим объёмом данных могут быть очень тяжёлыми и медленными для анализа во время выполнения, например, TileMap содержит один или несколько полигонов для каждой используемой ячейки и TileMapLayer для анализа. Узлы, содержащие сетки, вынуждены запрашивать данные у RenderingServer, что замедляет процесс рендеринга.
Для повышения производительности используйте более оптимизированные формы, например, формы столкновений вместо подробных визуальных сеток, а также объединяйте и упрощайте как можно больше геометрии заранее. Если ничего не помогает, не анализируйте SceneTree и не добавляйте исходную геометрию процедурно с помощью скриптов. Если в качестве исходной геометрии используются только чистые массивы данных, весь процесс запекания можно выполнить в фоновом потоке.
- Навигационная сетка создает непреднамеренные дыры в 2D.
Запекание навигационной сетки в 2D осуществляется путём обрезки полигонов по контурам. Полигоны с "дырками" — необходимое зло для создания более сложных 2D-полигонов, но могут стать непредсказуемыми для пользователей, использующих множество сложных фигур.
Чтобы избежать непредвиденных проблем с расчётом отверстий полигонов, избегайте вложения контуров в другие контуры того же типа (проходимые/препятствующие). Это касается и проанализированных фигур из узлов. Например, размещение меньшей фигуры StaticBody2D внутри большей может привести к перевёртыванию результирующего полигона.
- Навигационная сетка отображается внутри геометрии в 3D.
При запекании навигационной сетки в 3D нет понятия "внутри". Воксельные ячейки, используемые для растеризации геометрии, либо заняты, либо нет. Удалите геометрию, находящуюся на земле внутри другой геометрии. Если это невозможно, добавьте внутрь меньшую «фиктивную» геометрию с минимальным количеством треугольников, чтобы ячейки были чем-то заняты.
Форма NavigationObstacle3D, заданная для запекания с навигационной сеткой, также может использоваться для отбрасывания геометрии.
Фигуру NavigationObstacle3D можно использовать для удаления нежелательных частей навигационной сетки.
Шаблоны сценариев навигационной сетки
Следующий скрипт использует NavigationServer для анализа исходной геометрии из дерева сцены, создает навигационную сетку и обновляет навигационную область с помощью обновленной навигационной сетки.
extends Node2D
var navigation_mesh: NavigationPolygon
var source_geometry : NavigationMeshSourceGeometryData2D
var callback_parsing : Callable
var callback_baking : Callable
var region_rid: RID
func _ready() -> void:
navigation_mesh = NavigationPolygon.new()
navigation_mesh.agent_radius = 10.0
source_geometry = NavigationMeshSourceGeometryData2D.new()
callback_parsing = on_parsing_done
callback_baking = on_baking_done
region_rid = NavigationServer2D.region_create()
# Enable the region and set it to the default navigation map.
NavigationServer2D.region_set_enabled(region_rid, true)
NavigationServer2D.region_set_map(region_rid, get_world_2d().get_navigation_map())
# Some mega-nodes like TileMap are often not ready on the first frame.
# Also the parsing needs to happen on the main-thread.
# So do a deferred call to avoid common parsing issues.
parse_source_geometry.call_deferred()
func parse_source_geometry() -> void:
source_geometry.clear()
var root_node: Node2D = self
# Parse the obstruction outlines from all child nodes of the root node by default.
NavigationServer2D.parse_source_geometry_data(
navigation_mesh,
source_geometry,
root_node,
callback_parsing
)
func on_parsing_done() -> void:
# If we did not parse a TileMap with navigation mesh cells we may now only
# have obstruction outlines so add at least one traversable outline
# so the obstructions outlines have something to "cut" into.
source_geometry.add_traversable_outline(PackedVector2Array([
Vector2(0.0, 0.0),
Vector2(500.0, 0.0),
Vector2(500.0, 500.0),
Vector2(0.0, 500.0)
]))
# Bake the navigation mesh on a thread with the source geometry data.
NavigationServer2D.bake_from_source_geometry_data_async(
navigation_mesh,
source_geometry,
callback_baking
)
func on_baking_done() -> void:
# Update the region with the updated navigation mesh.
NavigationServer2D.region_set_navigation_polygon(region_rid, navigation_mesh)
using Godot;
public partial class MyNode2D : Node2D
{
private NavigationPolygon _navigationMesh;
private NavigationMeshSourceGeometryData2D _sourceGeometry;
private Callable _callbackParsing;
private Callable _callbackBaking;
private Rid _regionRid;
public override void _Ready()
{
_navigationMesh = new NavigationPolygon();
_navigationMesh.AgentRadius = 10.0f;
_sourceGeometry = new NavigationMeshSourceGeometryData2D();
_callbackParsing = Callable.From(OnParsingDone);
_callbackBaking = Callable.From(OnBakingDone);
_regionRid = NavigationServer2D.RegionCreate();
// Enable the region and set it to the default navigation map.
NavigationServer2D.RegionSetEnabled(_regionRid, true);
NavigationServer2D.RegionSetMap(_regionRid, GetWorld2D().NavigationMap);
// Some mega-nodes like TileMap are often not ready on the first frame.
// Also the parsing needs to happen on the main-thread.
// So do a deferred call to avoid common parsing issues.
CallDeferred(MethodName.ParseSourceGeometry);
}
private void ParseSourceGeometry()
{
_sourceGeometry.Clear();
Node2D rootNode = this;
// Parse the obstruction outlines from all child nodes of the root node by default.
NavigationServer2D.ParseSourceGeometryData(
_navigationMesh,
_sourceGeometry,
rootNode,
_callbackParsing
);
}
private void OnParsingDone()
{
// If we did not parse a TileMap with navigation mesh cells we may now only
// have obstruction outlines so add at least one traversable outline
// so the obstructions outlines have something to "cut" into.
_sourceGeometry.AddTraversableOutline(
[
new Vector2(0.0f, 0.0f),
new Vector2(500.0f, 0.0f),
new Vector2(500.0f, 500.0f),
new Vector2(0.0f, 500.0f),
]);
// Bake the navigation mesh on a thread with the source geometry data.
NavigationServer2D.BakeFromSourceGeometryDataAsync(_navigationMesh, _sourceGeometry, _callbackBaking);
}
private void OnBakingDone()
{
// Update the region with the updated navigation mesh.
NavigationServer2D.RegionSetNavigationPolygon(_regionRid, _navigationMesh);
}
}
extends Node3D
var navigation_mesh: NavigationMesh
var source_geometry : NavigationMeshSourceGeometryData3D
var callback_parsing : Callable
var callback_baking : Callable
var region_rid: RID
func _ready() -> void:
navigation_mesh = NavigationMesh.new()
navigation_mesh.agent_radius = 0.5
source_geometry = NavigationMeshSourceGeometryData3D.new()
callback_parsing = on_parsing_done
callback_baking = on_baking_done
region_rid = NavigationServer3D.region_create()
# Enable the region and set it to the default navigation map.
NavigationServer3D.region_set_enabled(region_rid, true)
NavigationServer3D.region_set_map(region_rid, get_world_3d().get_navigation_map())
# Some mega-nodes like GridMap are often not ready on the first frame.
# Also the parsing needs to happen on the main-thread.
# So do a deferred call to avoid common parsing issues.
parse_source_geometry.call_deferred()
func parse_source_geometry() -> void:
source_geometry.clear()
var root_node: Node3D = self
# Parse the geometry from all mesh child nodes of the root node by default.
NavigationServer3D.parse_source_geometry_data(
navigation_mesh,
source_geometry,
root_node,
callback_parsing
)
func on_parsing_done() -> void:
# Bake the navigation mesh on a thread with the source geometry data.
NavigationServer3D.bake_from_source_geometry_data_async(
navigation_mesh,
source_geometry,
callback_baking
)
func on_baking_done() -> void:
# Update the region with the updated navigation mesh.
NavigationServer3D.region_set_navigation_mesh(region_rid, navigation_mesh)
using Godot;
public partial class MyNode3D : Node3D
{
private NavigationMesh _navigationMesh;
private NavigationMeshSourceGeometryData3D _sourceGeometry;
private Callable _callbackParsing;
private Callable _callbackBaking;
private Rid _regionRid;
public override void _Ready()
{
_navigationMesh = new NavigationMesh();
_navigationMesh.AgentRadius = 0.5f;
_sourceGeometry = new NavigationMeshSourceGeometryData3D();
_callbackParsing = Callable.From(OnParsingDone);
_callbackBaking = Callable.From(OnBakingDone);
_regionRid = NavigationServer3D.RegionCreate();
// Enable the region and set it to the default navigation map.
NavigationServer3D.RegionSetEnabled(_regionRid, true);
NavigationServer3D.RegionSetMap(_regionRid, GetWorld3D().NavigationMap);
// Some mega-nodes like GridMap are often not ready on the first frame.
// Also the parsing needs to happen on the main-thread.
// So do a deferred call to avoid common parsing issues.
CallDeferred(MethodName.ParseSourceGeometry);
}
private void ParseSourceGeometry ()
{
_sourceGeometry.Clear();
Node3D rootNode = this;
// Parse the geometry from all mesh child nodes of the root node by default.
NavigationServer3D.ParseSourceGeometryData(
_navigationMesh,
_sourceGeometry,
rootNode,
_callbackParsing
);
}
private void OnParsingDone()
{
// Bake the navigation mesh on a thread with the source geometry data.
NavigationServer3D.BakeFromSourceGeometryDataAsync(_navigationMesh, _sourceGeometry, _callbackBaking);
}
private void OnBakingDone()
{
// Update the region with the updated navigation mesh.
NavigationServer3D.RegionSetNavigationMesh(_regionRid, _navigationMesh);
}
}
Следующий скрипт использует NavigationServer для обновления навигационной области с помощью процедурно сгенерированных данных навигационной сетки.
extends Node2D
var navigation_mesh: NavigationPolygon
var region_rid: RID
func _ready() -> void:
navigation_mesh = NavigationPolygon.new()
region_rid = NavigationServer2D.region_create()
# Enable the region and set it to the default navigation map.
NavigationServer2D.region_set_enabled(region_rid, true)
NavigationServer2D.region_set_map(region_rid, get_world_2d().get_navigation_map())
# Add vertices for a convex polygon.
navigation_mesh.vertices = PackedVector2Array([
Vector2(0.0, 0.0),
Vector2(100.0, 0.0),
Vector2(100.0, 100.0),
Vector2(0.0, 100.0),
])
# Add indices for the polygon.
navigation_mesh.add_polygon(
PackedInt32Array([0, 1, 2, 3])
)
NavigationServer2D.region_set_navigation_polygon(region_rid, navigation_mesh)
using Godot;
public partial class MyNode2D : Node2D
{
private NavigationPolygon _navigationMesh;
private Rid _regionRid;
public override void _Ready()
{
_navigationMesh = new NavigationPolygon();
_regionRid = NavigationServer2D.RegionCreate();
// Enable the region and set it to the default navigation map.
NavigationServer2D.RegionSetEnabled(_regionRid, true);
NavigationServer2D.RegionSetMap(_regionRid, GetWorld2D().NavigationMap);
// Add vertices for a convex polygon.
_navigationMesh.Vertices =
[
new Vector2(0, 0),
new Vector2(100.0f, 0),
new Vector2(100.0f, 100.0f),
new Vector2(0, 100.0f),
];
// Add indices for the polygon.
_navigationMesh.AddPolygon([0, 1, 2, 3]);
NavigationServer2D.RegionSetNavigationPolygon(_regionRid, _navigationMesh);
}
}
extends Node3D
var navigation_mesh: NavigationMesh
var region_rid: RID
func _ready() -> void:
navigation_mesh = NavigationMesh.new()
region_rid = NavigationServer3D.region_create()
# Enable the region and set it to the default navigation map.
NavigationServer3D.region_set_enabled(region_rid, true)
NavigationServer3D.region_set_map(region_rid, get_world_3d().get_navigation_map())
# Add vertices for a convex polygon.
navigation_mesh.vertices = PackedVector3Array([
Vector3(-1.0, 0.0, 1.0),
Vector3(1.0, 0.0, 1.0),
Vector3(1.0, 0.0, -1.0),
Vector3(-1.0, 0.0, -1.0),
])
# Add indices for the polygon.
navigation_mesh.add_polygon(
PackedInt32Array([0, 1, 2, 3])
)
NavigationServer3D.region_set_navigation_mesh(region_rid, navigation_mesh)
using Godot;
public partial class MyNode3D : Node3D
{
private NavigationMesh _navigationMesh;
private Rid _regionRid;
public override void _Ready()
{
_navigationMesh = new NavigationMesh();
_regionRid = NavigationServer3D.RegionCreate();
// Enable the region and set it to the default navigation map.
NavigationServer3D.RegionSetEnabled(_regionRid, true);
NavigationServer3D.RegionSetMap(_regionRid, GetWorld3D().NavigationMap);
// Add vertices for a convex polygon.
_navigationMesh.Vertices =
[
new Vector3(-1.0f, 0.0f, 1.0f),
new Vector3(1.0f, 0.0f, 1.0f),
new Vector3(1.0f, 0.0f, -1.0f),
new Vector3(-1.0f, 0.0f, -1.0f),
];
// Add indices for the polygon.
_navigationMesh.AddPolygon([0, 1, 2, 3]);
NavigationServer3D.RegionSetNavigationMesh(_regionRid, _navigationMesh);
}
}