Skip to content

Commit

Permalink
Merge pull request #3003 from QuantumCoderQC/NavMesh-preview
Browse files Browse the repository at this point in the history
Implementing NavMesh preview
  • Loading branch information
luboslenco authored Mar 4, 2024
2 parents 3f54ff9 + 9d36417 commit f5646a5
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 25 deletions.
9 changes: 5 additions & 4 deletions Sources/armory/trait/NavMesh.hx
Original file line number Diff line number Diff line change
Expand Up @@ -429,21 +429,22 @@ class NavMesh extends Trait {
vertexIndexMap = generateVertexIndexMap(vecind, vertexMapArray);

// Parented object - clear parent location
/*
if (object.parent != null && object.parent.name != "") {
object.transform.loc.x += object.parent.transform.worldx();
object.transform.loc.y += object.parent.transform.worldy();
object.transform.loc.z += object.parent.transform.worldz();
object.transform.localOnly = true;
object.transform.buildMatrix();
}
}*/

var positions = fromI16(geom.positions.values, mo.data.scalePos);
for (i in 0...Std.int(positions.length / 3)) {
v.set(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]);
v.applyQuat(object.transform.rot);
v.x *= object.transform.scale.x;
v.y *= object.transform.scale.y;
v.z *= object.transform.scale.z;
v.x *= object.transform.scale.x * object.parent.transform.scale.x;
v.y *= object.transform.scale.y * object.parent.transform.scale.y;
v.z *= object.transform.scale.z * object.parent.transform.scale.z;
v.addf(object.transform.worldx(), object.transform.worldy(), object.transform.worldz());
positions[i * 3 ] = v.x;
positions[i * 3 + 1] = v.y;
Expand Down
104 changes: 83 additions & 21 deletions blender/arm/props_traits.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,33 +414,91 @@ def execute(self, context):
if not arm.utils.check_sdkpath(self):
return {"CANCELLED"}

print("Started visualization generation")

# Append objects to be included in NavMesh
export_objects = []
# Append Object with trait
export_objects.append(obj)
# Get NavMesh trait
for trait in obj.arm_traitlist:
if trait.arm_traitpropslist and trait.class_name_prop == 'NavMesh':
# Check if child objects should be included in NavMesh
prop = trait.arm_traitpropslist['combineImmidiateChildren']
if(prop.get_value()):
# If yes, check if child is a mesh
for child_obj in obj.children:
if obj.type == 'MESH':
# Append child
export_objects.append(child_obj)

# get dependency graph
depsgraph = bpy.context.evaluated_depsgraph_get()
armature = obj.find_armature()
apply_modifiers = not armature

obj_eval = obj.evaluated_get(depsgraph) if apply_modifiers else obj
export_mesh = obj_eval.to_mesh()
# TODO: build tilecache here
print("Started visualization generation")
# For visualization
# Get build directory
nav_full_path = arm.utils.get_fp_build() + '/compiled/Assets/navigation'
if not os.path.exists(nav_full_path):
os.makedirs(nav_full_path)

nav_mesh_name = 'nav_' + obj_eval.data.name
# Get export OBJ name and path
nav_mesh_name = 'nav_' + obj.data.name
mesh_path = nav_full_path + '/' + nav_mesh_name + '.obj'

# Max index of objects (vertices) traversed
max_overall_index = 0
# Open to OBJ file
with open(mesh_path, 'w') as f:
for v in export_mesh.vertices:
f.write("v %.4f " % (v.co[0] * obj_eval.scale.x))
f.write("%.4f " % (v.co[2] * obj_eval.scale.z))
f.write("%.4f\n" % (v.co[1] * obj_eval.scale.y)) # Flipped
for p in export_mesh.polygons:
f.write("f")
for i in reversed(p.vertices): # Flipped normals
f.write(" %d" % (i + 1))
f.write("\n")

for export_obj in export_objects:
# If armature, apply armature modifier
armature = export_obj.find_armature()
apply_modifiers = not armature
obj_eval = export_obj.evaluated_get(depsgraph) if apply_modifiers else export_obj

# Get mesh data
export_mesh = obj_eval.to_mesh()

# Get world transform
world_matrix = obj_eval.matrix_world

# Iterate over the triangles and get vertices and indices
triangles = export_mesh.loop_triangles
traversed_indices = []

# For each triangle in the object
for triangle in triangles:
# For each index in triangle
for loop_index in triangle.loops:
# Get vertex index
vertex_index = export_mesh.loops[loop_index].vertex_index
# Skip if vertex already appended
if (vertex_index not in traversed_indices):
# If not, append vertex
traversed_indices.append(vertex_index)
vertex = export_mesh.vertices[vertex_index].co
# Apply world transform
tv = world_matrix @ vertex
# Write to OBJ
f.write("v %.4f " % (tv[0]))
f.write("%.4f " % (tv[2]))
f.write("%.4f\n" % (tv[1])) # Flipped

# Max index of this object
max_index = 0
# For each triangle in the object
for triangle in triangles:
# Write index to OBJ
f.write("f")
for loop_index in triangle.loops:
# index of this object should be > index of previous objects
curr_index = max_overall_index + loop_index + 1
f.write(" %d" % (curr_index))
if(curr_index > max_overall_index):
max_index = curr_index
f.write("\n")
# Store max overall index
max_overall_index = max_index

# Get buildnavjs
buildnavjs_path = arm.utils.get_sdk_path() + '/lib/haxerecast/buildnavjs'

# append config values
Expand All @@ -461,9 +519,10 @@ def execute(self, context):
navmesh = bpy.ops.import_scene.obj(filepath=mesh_path)
navmesh = bpy.context.selected_objects[0]

# NavMesh preview settings, cleanup
navmesh.name = nav_mesh_name
navmesh.rotation_euler = (0, 0, 0)
navmesh.location = (obj.location.x, obj.location.y, obj.location.z)
navmesh.location = (0, 0, 0)
navmesh.arm_export = False

bpy.context.view_layer.objects.active = navmesh
Expand Down Expand Up @@ -886,8 +945,11 @@ def draw_traits_panel(layout: bpy.types.UILayout, obj: Union[bpy.types.Object, b

# Bundled scripts
else:
row.enabled = item.class_name_prop != ''
row.operator("arm.edit_bundled_script", icon_value=ICON_HAXE).is_object = is_object
if item.class_name_prop == 'NavMesh':
row.operator("arm.generate_navmesh", icon="UV_VERTEXSEL")
else:
row.enabled = item.class_name_prop != ''
row.operator("arm.edit_bundled_script", icon_value=ICON_HAXE).is_object = is_object

refresh_op = "arm.refresh_object_scripts" if is_object else "arm.refresh_scripts"
row.operator(refresh_op, text="Refresh", icon="FILE_REFRESH")
Expand Down

0 comments on commit f5646a5

Please sign in to comment.