clean up path straightening + navmesh dev example improvement

This commit is contained in:
Dmitry Stepanov
2023-11-08 00:49:51 +03:00
parent 223004f5e5
commit 771d9c5229
3 changed files with 45 additions and 93 deletions
Binary file not shown.
+5 -41
View File
@@ -1,12 +1,3 @@
//! Example 01. Simple scene.
//!
//! Difficulty: Easy.
//!
//! This example shows how to create simple scene with animated model.
use fyrox::event_loop::EventLoop;
use fyrox::scene::camera::CameraBuilder;
use fyrox::scene::node::NodeTrait;
use fyrox::{ use fyrox::{
asset::manager::ResourceManager, asset::manager::ResourceManager,
core::{ core::{
@@ -19,25 +10,21 @@ use fyrox::{
dpi::LogicalPosition, dpi::LogicalPosition,
engine::{executor::Executor, GraphicsContext, GraphicsContextParams}, engine::{executor::Executor, GraphicsContext, GraphicsContextParams},
event::{ElementState, Event, WindowEvent}, event::{ElementState, Event, WindowEvent},
gui::{ event_loop::EventLoop,
message::MessageDirection,
text::{TextBuilder, TextMessage},
widget::WidgetBuilder,
BuildContext, UiNode,
},
keyboard::KeyCode, keyboard::KeyCode,
material::{Material, PropertyValue, SharedMaterial}, material::{Material, PropertyValue, SharedMaterial},
plugin::{Plugin, PluginConstructor, PluginContext}, plugin::{Plugin, PluginConstructor, PluginContext},
resource::model::{Model, ModelResourceExtension}, resource::model::{Model, ModelResourceExtension},
scene::{ scene::{
base::BaseBuilder, base::BaseBuilder,
camera::CameraBuilder,
debug::Line, debug::Line,
graph::physics::{Intersection, RayCastOptions}, graph::physics::{Intersection, RayCastOptions},
mesh::{ mesh::{
surface::{SurfaceBuilder, SurfaceData, SurfaceSharedData}, surface::{SurfaceBuilder, SurfaceData, SurfaceSharedData},
MeshBuilder, MeshBuilder,
}, },
node::Node, node::{Node, NodeTrait},
transform::TransformBuilder, transform::TransformBuilder,
Scene, Scene,
}, },
@@ -45,10 +32,6 @@ use fyrox::{
}; };
use winit::keyboard::PhysicalKey; use winit::keyboard::PhysicalKey;
fn create_ui(ctx: &mut BuildContext) -> Handle<UiNode> {
TextBuilder::new(WidgetBuilder::new()).build(ctx)
}
struct GameScene { struct GameScene {
scene: Scene, scene: Scene,
agent: Handle<Node>, agent: Handle<Node>,
@@ -77,7 +60,7 @@ async fn create_scene(resource_manager: ResourceManager) -> GameScene {
)); ));
resource_manager resource_manager
.request::<Model, _>("examples/data/navmesh_scene2.rgs") .request::<Model, _>("examples/data/navmesh_scene.rgs")
.await .await
.unwrap() .unwrap()
.instantiate(&mut scene); .instantiate(&mut scene);
@@ -143,7 +126,6 @@ struct Game {
target_position: Vector3<f32>, target_position: Vector3<f32>,
mouse_position: Vector2<f32>, mouse_position: Vector2<f32>,
navmesh_agent: NavmeshAgent, navmesh_agent: NavmeshAgent,
debug_text: Handle<UiNode>,
} }
impl Plugin for Game { impl Plugin for Game {
@@ -180,15 +162,13 @@ impl Plugin for Game {
} }
} }
let navmesh_handle = scene.graph.find_by_name_from_root("Navmesh0").unwrap().0; let navmesh_handle = scene.graph.find_by_name_from_root("Navmesh").unwrap().0;
let navmesh_node = scene.graph[navmesh_handle].as_navigational_mesh_mut(); let navmesh_node = scene.graph[navmesh_handle].as_navigational_mesh_mut();
navmesh_node.debug_draw(&mut scene.drawing_context); navmesh_node.debug_draw(&mut scene.drawing_context);
let navmesh = navmesh_node.navmesh_mut(); let navmesh = navmesh_node.navmesh_mut();
let last = std::time::Instant::now();
self.navmesh_agent.set_target(self.target_position); self.navmesh_agent.set_target(self.target_position);
let _ = self.navmesh_agent.update(context.dt, navmesh); let _ = self.navmesh_agent.update(context.dt, navmesh);
let agent_time = std::time::Instant::now() - last;
scene.graph[self.agent] scene.graph[self.agent]
.local_transform_mut() .local_transform_mut()
@@ -201,19 +181,6 @@ impl Plugin for Game {
color: Color::opaque(255, 0, 0), color: Color::opaque(255, 0, 0),
}); });
} }
if let GraphicsContext::Initialized(ref graphics_context) = context.graphics_context {
let fps = graphics_context.renderer.get_statistics().frames_per_second;
let text = format!(
"Example 12 - Navigation Mesh\nFPS: {}\nAgent time: {:?}",
fps, agent_time
);
context.user_interface.send_message(TextMessage::text(
self.debug_text,
MessageDirection::ToWidget,
text,
));
}
} }
fn on_os_event(&mut self, event: &Event<()>, context: PluginContext) { fn on_os_event(&mut self, event: &Event<()>, context: PluginContext) {
@@ -251,8 +218,6 @@ impl PluginConstructor for GameConstructor {
_override_scene: Option<&str>, _override_scene: Option<&str>,
context: PluginContext, context: PluginContext,
) -> Box<dyn Plugin> { ) -> Box<dyn Plugin> {
let debug_text = create_ui(&mut context.user_interface.build_ctx());
// Create test scene. // Create test scene.
let GameScene { let GameScene {
scene, scene,
@@ -280,7 +245,6 @@ impl PluginConstructor for GameConstructor {
target_position: Default::default(), target_position: Default::default(),
mouse_position: Default::default(), mouse_position: Default::default(),
navmesh_agent, navmesh_agent,
debug_text,
}) })
} }
} }
+40 -52
View File
@@ -121,7 +121,7 @@ struct Portal {
left: usize, left: usize,
right: usize, right: usize,
} }
fn signed_triangle_area_2d(a: Vector3<f32>, b: Vector3<f32>, c: Vector3<f32>) -> f32 { fn triangle_area_2d(a: Vector3<f32>, b: Vector3<f32>, c: Vector3<f32>) -> f32 {
let abx = b[0] - a[0]; let abx = b[0] - a[0];
let abz = b[2] - a[2]; let abz = b[2] - a[2];
let acx = c[0] - a[0]; let acx = c[0] - a[0];
@@ -136,7 +136,7 @@ enum Winding {
} }
fn winding(a: Vector3<f32>, b: Vector3<f32>, c: Vector3<f32>) -> Winding { fn winding(a: Vector3<f32>, b: Vector3<f32>, c: Vector3<f32>) -> Winding {
if signed_triangle_area_2d(a, b, c) > 0.0 { if triangle_area_2d(a, b, c) > 0.0 {
Winding::Clockwise Winding::Clockwise
} else { } else {
Winding::CounterClockwise Winding::CounterClockwise
@@ -669,16 +669,14 @@ impl NavmeshAgent {
self.path.push(src_position); self.path.push(src_position);
if path_triangles.len() > 1 { if path_triangles.len() > 1 {
let mut portal_apex = src_position; let mut funnel_apex = src_position;
let mut portal_left = src_position; let mut funnel_vertices = [funnel_apex; 2];
let mut portal_right = src_position; let mut side_indices = [0; 2];
let side_signs = [1.0, -1.0];
let mut left_index = 0;
let mut right_index = 0;
let mut i = 0; let mut i = 0;
while i < path_triangles.len() { while i < path_triangles.len() {
let (left, right) = if i + 1 < path_triangles.len() { let portal_vertices = if i + 1 < path_triangles.len() {
let portal = navmesh let portal = navmesh
.portal_between(path_triangles[i], path_triangles[i + 1]) .portal_between(path_triangles[i], path_triangles[i + 1])
.unwrap(); .unwrap();
@@ -695,54 +693,44 @@ impl NavmeshAgent {
right -= offset; right -= offset;
} }
(left, right) [left, right]
} else { } else {
(dest_position, dest_position) [dest_position, dest_position]
}; };
// Update right vertex. for current in 0..2 {
if signed_triangle_area_2d(portal_apex, portal_right, right) <= 0.0 { let opposite = 1 - current;
if portal_apex == portal_right let side_sign = side_signs[current];
|| signed_triangle_area_2d(portal_apex, portal_left, right) > 0.0 if side_sign
* triangle_area_2d(
funnel_apex,
funnel_vertices[current],
portal_vertices[current],
)
>= 0.0
{ {
// Tighten the funnel. if funnel_apex == funnel_vertices[current]
portal_right = right; || side_sign
right_index = i; * triangle_area_2d(
} else { funnel_apex,
// Right over left, insert left to path and restart scan from portal left point. funnel_vertices[opposite],
self.path.push(portal_left); portal_vertices[current],
// Make current left the new apex. )
portal_apex = portal_left; < 0.0
// Reset portal {
portal_left = portal_apex; funnel_vertices[current] = portal_vertices[current];
portal_right = portal_apex; side_indices[current] = i;
right_index = left_index; } else {
// Restart scan funnel_apex = funnel_vertices[opposite];
i = left_index + 1; funnel_vertices = [funnel_apex; 2];
continue;
}
}
// Update left vertex. self.path.push(funnel_apex);
if signed_triangle_area_2d(portal_apex, portal_left, left) >= 0.0 {
if portal_apex == portal_left i = side_indices[opposite];
|| signed_triangle_area_2d(portal_apex, portal_right, left) < 0.0 side_indices[current] = i;
{
// Tighten the funnel. break;
portal_left = left; }
left_index = i;
} else {
// Left over right, insert right to path and restart scan from portal right point.
self.path.push(portal_right);
// Make current right the new apex.
portal_apex = portal_right;
// Reset portal
portal_left = portal_apex;
portal_right = portal_apex;
left_index = right_index;
// Restart scan
i = right_index + 1;
continue;
} }
} }