Merge pull request #1338 from N8n5h/nav-update

update for navmesh generation
master
Lubos Lenco 2019-08-10 12:57:22 +02:00 committed by GitHub
commit ad114a95f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 105 additions and 77 deletions

View File

@ -57,8 +57,7 @@ class NavAgent extends Trait {
orient.subvecs(p, object.transform.loc).normalize;
var targetAngle = Math.atan2(orient.y, orient.x) + Math.PI / 2;
locAnim = Tween.to({ target: object.transform.loc, props: { x: p.x, y: p.y /*, z: p.z*/ }, duration: dist / speed, done: function() {
locAnim = Tween.to({ target: object.transform.loc, props: { x: p.x, y: p.y , z: p.z }, duration: dist / speed, done: function() {
index++;
if (index < path.length) go();
else removeUpdate(update);

View File

@ -15,6 +15,20 @@ class NavMesh extends Trait {
public function new() { super(); }
#else
// recast config:
@prop
public var cellSize:Float = 0.3; // voxelization cell size
@prop
public var cellHeight:Float = 0.2; // voxelization cell height
@prop
public var agentHeight:Float = 2.0; // agent capsule height
@prop
public var agentRadius:Float = 0.4; // agent capsule radius
@prop
public var agentMaxClimb:Float = 0.9; // how high steps agents can climb, in voxels
@prop
public var agentMaxSlope:Float = 45.0; // maximum slope angle, in degrees
var recast:Recast = null;
var ready = false;
@ -33,6 +47,17 @@ class NavMesh extends Trait {
recast = Navigation.active.recast;
recast.OBJDataLoader(b.toString(), function() {
var settings = [
'cellSize' => cellSize,
'cellHeight' => cellHeight,
'agentHeight' => agentHeight,
'agentRadius' => agentRadius,
'agentMaxClimb' => agentMaxClimb,
'agentMaxSlope' => agentMaxSlope,
];
recast.settings(settings);
recast.buildSolo();
ready = true;
});
@ -43,7 +68,7 @@ class NavMesh extends Trait {
if (!ready) return;
recast.findPath(from.x, from.z, from.y, to.x, to.z, to.y, 200, function(path:Array<RecastWaypoint>) {
var ar:Array<Vec4> = [];
for (p in path) ar.push(new Vec4(p.x, p.z, -p.y));
for (p in path) ar.push(new Vec4(p.x, p.z, (p.y + 1.1)));
done(ar);
});
}

View File

@ -10,6 +10,7 @@ from arm.props_traits_props import *
import arm.utils
import arm.write_data as write_data
import arm.make as make
import json
def trigger_recompile(self, context):
wrd = bpy.data.worlds['Arm']
@ -306,6 +307,74 @@ class ArmEditBundledScriptButton(bpy.types.Operator):
return{'FINISHED'}
class ArmoryGenerateNavmeshButton(bpy.types.Operator):
'''Generate navmesh from selected meshes'''
bl_idname = 'arm.generate_navmesh'
bl_label = 'Generate Navmesh'
def execute(self, context):
obj = context.active_object
if obj.type != 'MESH':
return{'CANCELLED'}
# TODO: build tilecache here
# For visualization
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.data.name
mesh_path = nav_full_path + '/' + nav_mesh_name + '.obj'
with open(mesh_path, 'w') as f:
for v in obj.data.vertices:
f.write("v %.4f " % (v.co[0] * obj.scale.x))
f.write("%.4f " % (v.co[2] * obj.scale.z))
f.write("%.4f\n" % (v.co[1] * obj.scale.y)) # Flipped
for p in obj.data.polygons:
f.write("f")
for i in reversed(p.vertices): # Flipped normals
f.write(" %d" % (i + 1))
f.write("\n")
fp_build_name = arm.utils.get_fp_build().rsplit('/')[-1]
nav_mesh_path = '/' + fp_build_name + '/compiled/Assets/navigation/' + nav_mesh_name
buildnavjs_path = arm.utils.get_sdk_path() + '/lib/haxerecast/buildnavjs'
# append config values
nav_config = {}
for t in obj.arm_traitlist:
# check if trait is navmesh here
if len(t.arm_traitpropslist) > 0 and t.class_name_prop == 'NavMesh':
for pt in t.arm_traitpropslist: # Append props
prop = pt.name.replace(')', '').split('(')
name = prop[0]
value = float(pt.value)
nav_config[name] = value
nav_config_json = json.dumps(nav_config)
args = [arm.utils.get_node_path(), buildnavjs_path, nav_mesh_path, nav_config_json]
proc = subprocess.Popen(args)
proc.wait()
navmesh = bpy.ops.import_scene.obj(filepath=mesh_path)
navmesh = bpy.context.selected_objects[0]
navmesh.name = nav_mesh_name
navmesh.rotation_euler = (0,0,0)
navmesh.location = (obj.location.x,obj.location.y,obj.location.z)
navmesh.arm_export = False
bpy.context.view_layer.objects.active = navmesh
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.remove_doubles()
bpy.ops.object.editmode_toggle()
return{'FINISHED'}
class ArmEditCanvasButton(bpy.types.Operator):
'''Edit ui canvas'''
bl_idname = 'arm.edit_canvas'
@ -508,12 +577,17 @@ def draw_traits(layout, obj, is_object):
op.is_object = is_object
op = row.operator("arm.refresh_scripts")
else: # Bundled
if item.class_name_prop == 'NavMesh':
row = layout.row(align=True)
row.alignment = 'EXPAND'
op = layout.operator("arm.generate_navmesh")
row = layout.row(align=True)
row.alignment = 'EXPAND'
column = row.column(align=True)
column.alignment = 'EXPAND'
op = column.operator("arm.edit_bundled_script", icon="FILE_SCRIPT")
op.is_object = is_object
if not item.class_name_prop == 'NavMesh':
op = column.operator("arm.edit_bundled_script", icon="FILE_SCRIPT")
op.is_object = is_object
op = row.operator("arm.refresh_scripts")
elif item.type_prop == 'WebAssembly':
@ -563,6 +637,7 @@ def register():
bpy.utils.register_class(ArmTraitListMoveItem)
bpy.utils.register_class(ArmEditScriptButton)
bpy.utils.register_class(ArmEditBundledScriptButton)
bpy.utils.register_class(ArmoryGenerateNavmeshButton)
bpy.utils.register_class(ArmEditCanvasButton)
bpy.utils.register_class(ArmNewScriptDialog)
bpy.utils.register_class(ArmNewCanvasDialog)
@ -590,6 +665,7 @@ def unregister():
bpy.utils.unregister_class(ArmTraitListMoveItem)
bpy.utils.unregister_class(ArmEditScriptButton)
bpy.utils.unregister_class(ArmEditBundledScriptButton)
bpy.utils.unregister_class(ArmoryGenerateNavmeshButton)
bpy.utils.unregister_class(ArmEditCanvasButton)
bpy.utils.unregister_class(ArmNewScriptDialog)
bpy.utils.unregister_class(ArmNewCanvasDialog)

View File

@ -434,72 +434,6 @@ class ArmVirtualInputPanel(bpy.types.Panel):
layout.use_property_split = True
layout.use_property_decorate = False
class ARM_PT_NavigationPanel(bpy.types.Panel):
bl_label = "Armory Navigation"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scene = bpy.context.scene
if scene == None:
return
layout.operator("arm.generate_navmesh")
layout.operator("arm.remove_navmesh")
class ArmoryGenerateNavmeshButton(bpy.types.Operator):
'''Generate navmesh from selected meshes'''
bl_idname = 'arm.generate_navmesh'
bl_label = 'Generate Navmesh'
def execute(self, context):
obj = context.active_object
if obj == None or obj.type != 'MESH':
return{'CANCELLED'}
# Prevent duplicates
for t in obj.arm_traitlist:
if t.class_name_prop == 'NavMesh':
return{'FINISHED'}
# TODO: build tilecache here
# Navmesh trait
obj.arm_traitlist.add()
obj.arm_traitlist[-1].type_prop = 'Bundled Script'
obj.arm_traitlist[-1].class_name_prop = 'NavMesh'
# For visualization
# Removed in b28
# bpy.ops.mesh.navmesh_make('EXEC_DEFAULT')
# obj = context.active_object
# obj.hide_render = True
# obj.arm_export = False
return{'FINISHED'}
class ArmoryRemoveNavmeshButton(bpy.types.Operator):
'''Remove generated navmesh from selected mesh'''
bl_idname = 'arm.remove_navmesh'
bl_label = 'Remove Navmesh'
def execute(self, context):
obj = context.active_object
if obj == None or obj.type != 'MESH':
return{'CANCELLED'}
# Navmesh trait
for i in range(len(obj.arm_traitlist)):
if obj.arm_traitlist[i].class_name_prop == 'NavMesh':
obj.arm_traitlist.remove(i)
break
return{'FINISHED'}
class ArmoryPlayButton(bpy.types.Operator):
'''Launch player in new window'''
bl_idname = 'arm.play'
@ -1508,9 +1442,6 @@ def register():
bpy.utils.register_class(CleanButtonMenu)
bpy.utils.register_class(ArmoryCleanProjectButton)
bpy.utils.register_class(ArmoryPublishProjectButton)
bpy.utils.register_class(ArmoryGenerateNavmeshButton)
bpy.utils.register_class(ArmoryRemoveNavmeshButton)
bpy.utils.register_class(ARM_PT_NavigationPanel)
bpy.utils.register_class(ArmGenLodButton)
bpy.utils.register_class(ARM_PT_LodPanel)
bpy.utils.register_class(ArmGenTerrainButton)
@ -1561,9 +1492,6 @@ def unregister():
bpy.utils.unregister_class(CleanButtonMenu)
bpy.utils.unregister_class(ArmoryCleanProjectButton)
bpy.utils.unregister_class(ArmoryPublishProjectButton)
bpy.utils.unregister_class(ArmoryGenerateNavmeshButton)
bpy.utils.unregister_class(ArmoryRemoveNavmeshButton)
bpy.utils.unregister_class(ARM_PT_NavigationPanel)
bpy.utils.unregister_class(ArmGenLodButton)
bpy.utils.unregister_class(ARM_PT_LodPanel)
bpy.utils.unregister_class(ArmGenTerrainButton)