Skip to content

Commit

Permalink
Merge branch 'to_as_0_21_4' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Tugcga committed Oct 1, 2022
2 parents aad8e7b + c0c3c46 commit cb35519
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 20 deletions.
60 changes: 55 additions & 5 deletions assemblyscript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ const navmesh_ptr = navmesh_exports.navmesh_from_bytes(nm_bytes);

For benchmarks we use the following map:

<img src="../images/map_00.png" width="400" />
<img src="../images/map_00.png" width="750" />

This navigation mesh contains 2 294 polygons. We compare our WASM implementation and Recast Navigation library (which is c++, but we will use Python bindings [PyRecastDetour](https://github.com/Tugcga/PyRecastDetour)). For benchmark we generate some random pair of points and calculate the path between these points. The results in the table:

Expand All @@ -520,7 +520,9 @@ Initialization time | 0.05 sec | 0.02 sec
65 536 pairs | 5.82 sec | 4.59 sec
147 456 pairs | 13.21 sec | 10.20 sec

So, our WASM version is nearly x1.3 times slowly with respect to c++ solution.
So, our WASM version is nearly x1.3 times slowly with respect to c++ solution. There are several reasons, why our solution is close to the native speed:
* Our algorithm is different from the Recast Navigation algorithm
* There are many interactions between environment and the module. May be the overhead for calling WASM function is smaller that overhead for calling c++ function from Python. This interaction can spend the most time with respect to actual path finding time.


### Collision avoidance algorithm
Expand All @@ -535,6 +537,39 @@ Task | as-RVO | em-RVO | c-RVO
So, Emscripten version is x1.5 times faster, c++ version is x5 times faster.


### Navmesh baking

For baking benchmark we use two methods. The first method is called ```plane```. We generate a large plane with the center at the origin and bake the navmesh for it. The complexity defined by the plane size. The second method is called ```cubes```. We generate random cubes in the space and bake navmesh for these cubes. The complexity defined by the number of cubes. Also we compare the performance with [PyRecastDetour](https://github.com/Tugcga/PyRecastDetour)), which implements the same baking algorithm.

```plane``` benchmark:

Size | WASM | PyRecastDetour
--- | --- | ---
4.0 | 0.0018 sec | 0.0 sec
16.0 | 0.033 sec | 0.004 sec
32.0 | 0.15 sec | 0.016 sec
64.0 | 0.74 sec | 0.069 sec
96.0 | 1.88 sec | 0.14 sec
128.0 | 4.39 sec | 0.31 sec
192.0 | 10.04 sec | 0.78 sec

So, c++ solution x10-x12 times faster.

```cubes``` benchmark:

Count | WASM | PyRecastDetour
--- | --- | ---
16 | 0.11 sec | 0.001 sec
32 | 0.19 sec | 0.013 sec
64 | 0.35 sec | 0.019 sec
128 | 0.58 sec | 0.032 sec
256 | 1.14 sec | 0.047 sec
512 | 2.18 sec | 0.086 sec
1024 | 4.39 sec | 0.16 sec

So, c++ solution near x20 times faster.


### Deserialization navmesh

We make the following experiment. Generate random navigation mesh polygonal data, and then:
Expand All @@ -560,20 +595,35 @@ Conclusions:
* Decompression and deserialization is slowly then direct initialization from polygonal data


## Navmesh Baker web application

[Here](https://tugcga.github.io/web_apps/navmesh_baker/index.html) is a small application, which use ```baker.wasm``` module for building navigation mesh for the input geometry.

<img src="../images/baker_app_01.png" width="750" />

You can use this application in the following way:
* Click ```Load OBJ``` button and select ```*.obj``` file with level gemoetry
* Setup bake settings and press ```Bake navmesh``` button
* Rotate and move the camera by using mouse: LMB - rotate, MMB and Wheel - zoom, RMB - pan
* When navmesh is generated, click ```Export navmesh``` button to save the polygon description of the mesh into ```*.txt``` file and save it into the local drive

The application use [OGL](https://github.com/oframe/ogl) for 3d-rendering, [obj-file-parser](https://github.com/Deckeraga/obj-file-parser-ts) for loading ```*.obj``` files and [FileSaver.js](https://github.com/eligrey/FileSaver.js/) for save output ```*.txt``` file.


## Example application

[Here](https://playcanv.as/p/MID4JNwZ/) is a simple Playcanvas application, which demonstrates the basic possibilities of the module. This application contains three different scenes.

The first scene demonstrate the path finding algorithm and snapping of the agent to the navigation mesh.

<img src="../images/pc_scene_01.png" width="400" />
<img src="../images/pc_scene_01.png" width="750" />

The second scene demonstrate the simple case of the using RVO2 algorithm. A number of agents move in the plane to the common destination point and avoid collisions.

<img src="../images/pc_scene_02.png" width="400" />
<img src="../images/pc_scene_02.png" width="750" />

The third scene demonstrate the complex usage of the path finding and collision avoidance. A number of agents moves on navigation mesh to random destination points.

<img src="../images/pc_scene_03.png" width="400" />
<img src="../images/pc_scene_03.png" width="750" />

This application use the old version of the module. The functionality is the same, but there are some difference with the module import process. The old version used the AssemblyScript loader, but current version use automatically generated bindings.
6 changes: 1 addition & 5 deletions assemblyscript/assembly/baker/rc_calcs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,7 @@ export function prev(i: int,

@inline
export function slice(array: StaticArray<float>, start: int, end: int): StaticArray<float>{
let to_return = new StaticArray<float>(end - start);
for(let i = 0; i < end - start; i++){
to_return[i] = array[start + i];
}
return to_return;
return array.slice<StaticArray<float>>(start, end);
}

@inline
Expand Down
4 changes: 2 additions & 2 deletions assemblyscript/assembly/baker/rc_contour.ts
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ function merge_region_holes(region: ContourRegion, holes: StaticArray<ContourHol
holes[region.holes_index + i].leftmost = find_result[2];
}
}
let sorted_holes: Array<ContourHole> = holes.slice(region.holes_index, region.holes_index+region.nholes);
let sorted_holes: StaticArray<ContourHole> = holes.slice<StaticArray<ContourHole>>(region.holes_index, region.holes_index + region.nholes);
sorted_holes.sort(compare_holes);

for(let i = 0; i < region.nholes; i++){
Expand Down Expand Up @@ -783,7 +783,7 @@ function merge_region_holes(region: ContourRegion, holes: StaticArray<ContourHol
ndiags += 1;
}
}
let sorted_diags: Array<PotentialDiagonal> = diags.slice(0, ndiags);
let sorted_diags: StaticArray<PotentialDiagonal> = diags.slice<StaticArray<PotentialDiagonal>>(0, ndiags);
sorted_diags.sort(compare_diag_dist);
for(let m = 0; m < ndiags; m++){
diags[m] = sorted_diags[m];
Expand Down
4 changes: 2 additions & 2 deletions assemblyscript/assembly/common/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class List<T> extends Serializable {

@inline
sort(): void{
this.m_array = StaticArray.slice<T>(this.m_array, 0, this.m_size).sort();
this.m_array = this.m_array.slice<StaticArray<T>>(0, this.m_size).sort();
this.m_size = this.m_array.length;
this.m_max_size = this.m_size;
}
Expand Down Expand Up @@ -176,7 +176,7 @@ export class List<T> extends Serializable {

@inline
to_static(): StaticArray<T>{
return StaticArray.slice<T>(this.m_array, 0, this.m_size);
return this.m_array.slice<StaticArray<T>>(0, this.m_size);
}

toString(): string{
Expand Down
6 changes: 0 additions & 6 deletions assemblyscript/assembly/navmesh/navmesh_graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,6 @@ export class Graph extends Serializable {
const pos_id = view.getInt32(shift);
if(pos_id == SD_TYPE.SD_TYPE_STATICARRAY_FLOAT32) {
const pos_bytes_length = view.getInt32(shift + 4);
//this.m_positions = staticarray_f32_from_bytes(bytes.slice(shift, shift + pos_bytes_length));
this.m_positions = staticarray_f32_from_bytes_expr(view, shift);
shift += pos_bytes_length;
} else { return; }
Expand All @@ -357,7 +356,6 @@ export class Graph extends Serializable {
const names_id = view.getInt32(shift);
const names_bytes_length = view.getInt32(shift + 4);
if(names_id == SD_TYPE.SD_TYPE_STATICARRAY_INT32) {
//this.m_vertex_names = staticarray_i32_from_bytes(bytes.slice(shift, shift + names_bytes_length));
this.m_vertex_names = staticarray_i32_from_bytes_expr(view, shift);
shift += names_bytes_length;
} else { return; }
Expand All @@ -366,7 +364,6 @@ export class Graph extends Serializable {
const count_id = view.getInt32(shift);
const count_bytes_length = view.getInt32(shift + 4);
if(count_id == SD_TYPE.SD_TYPE_INT32) {
//this.m_vertex_count = i32_from_bytes(bytes.slice(shift, shift + count_bytes_length));
this.m_vertex_count = view.getInt32(shift + 8);
shift += count_bytes_length;
} else { return; }
Expand All @@ -375,7 +372,6 @@ export class Graph extends Serializable {
const edges_id = view.getInt32(shift);
const edges_bytes_length = view.getInt32(shift + 4);
if(edges_id == SD_TYPE.SD_TYPE_STATICARRAY_INT32) {
//this.m_edges = staticarray_i32_from_bytes(bytes.slice(shift, shift + edges_bytes_length));
this.m_edges = staticarray_i32_from_bytes_expr(view, shift);
shift += edges_bytes_length;
} else { return; }
Expand All @@ -384,7 +380,6 @@ export class Graph extends Serializable {
const index_id = view.getInt32(shift);
const index_bytes_length = view.getInt32(shift + 4);
if(index_id == SD_TYPE.SD_TYPE_MAP_INT32_INT32) {
//this.m_index_map = map_i32_i32_from_bytes(bytes.slice(shift, shift + index_bytes_length));
this.m_index_map = map_i32_i32_from_bytes_expr(view, shift);
shift += index_bytes_length;
} else { return; }
Expand All @@ -393,7 +388,6 @@ export class Graph extends Serializable {
const incident_id = view.getInt32(shift);
const incident_bytes_length = view.getInt32(shift + 4);
if(incident_id == SD_TYPE.SD_TYPE_MAP_INT32_STATICARRAY_INT32) {
//this.m_incident_map = map_i32_staticarray_i32_from_bytes(bytes.slice(shift, shift + incident_bytes_length));
this.m_incident_map = map_i32_staticarray_i32_from_bytes_expr(view, shift);
shift += incident_bytes_length;
} else { return; }
Expand Down
Binary file added images/baker_app_01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit cb35519

Please sign in to comment.