|
@@ -4,8 +4,11 @@ import bmesh
|
|
import mathutils
|
|
import mathutils
|
|
|
|
|
|
from .material import export_material
|
|
from .material import export_material
|
|
-from ..structures import Array, NodeTemplate, InternalResource
|
|
|
|
|
|
+from ..structures import Array, NodeTemplate, InternalResource, NodePath
|
|
from . import physics
|
|
from . import physics
|
|
|
|
+from . import armature
|
|
|
|
+
|
|
|
|
+MAX_BONE_PER_VERTEX = 4
|
|
|
|
|
|
|
|
|
|
# ------------------------------- The Mesh -----------------------------------
|
|
# ------------------------------- The Mesh -----------------------------------
|
|
@@ -28,15 +31,31 @@ def export_mesh_node(escn_file, export_settings, node, parent_gd_node):
|
|
return parent_gd_node
|
|
return parent_gd_node
|
|
|
|
|
|
else:
|
|
else:
|
|
- armature = None
|
|
|
|
- if node.parent is not None and node.parent.type == "ARMATURE":
|
|
|
|
- armature = node.parent
|
|
|
|
-
|
|
|
|
- mesh_id = export_mesh(escn_file, export_settings, node, armature)
|
|
|
|
|
|
+ armature_data = armature.get_armature_data(node)
|
|
|
|
+
|
|
|
|
+ skeleton_node = None
|
|
|
|
+ if ("ARMATURE" in export_settings['object_types'] and
|
|
|
|
+ armature_data is not None):
|
|
|
|
+ # trace up the godot scene tree to find the binded skeleton node
|
|
|
|
+ gd_node_ptr = parent_gd_node
|
|
|
|
+ while (gd_node_ptr is not None and
|
|
|
|
+ gd_node_ptr.get_type() != "Skeleton"):
|
|
|
|
+ gd_node_ptr = gd_node_ptr.get_parent()
|
|
|
|
+ skeleton_node = gd_node_ptr
|
|
|
|
+
|
|
|
|
+ mesh_id = export_mesh(
|
|
|
|
+ escn_file,
|
|
|
|
+ export_settings,
|
|
|
|
+ node,
|
|
|
|
+ armature_data
|
|
|
|
+ )
|
|
|
|
|
|
mesh_node = NodeTemplate(node.name, "MeshInstance", parent_gd_node)
|
|
mesh_node = NodeTemplate(node.name, "MeshInstance", parent_gd_node)
|
|
mesh_node['mesh'] = "SubResource({})".format(mesh_id)
|
|
mesh_node['mesh'] = "SubResource({})".format(mesh_id)
|
|
mesh_node['visible'] = not node.hide
|
|
mesh_node['visible'] = not node.hide
|
|
|
|
+ if skeleton_node is not None:
|
|
|
|
+ mesh_node['skeleton'] = NodePath(
|
|
|
|
+ skeleton_node.get_path(), mesh_node.get_path())
|
|
if not physics.has_physics(node) or not physics.is_physics_root(node):
|
|
if not physics.has_physics(node) or not physics.is_physics_root(node):
|
|
mesh_node['transform'] = node.matrix_local
|
|
mesh_node['transform'] = node.matrix_local
|
|
else:
|
|
else:
|
|
@@ -46,7 +65,7 @@ def export_mesh_node(escn_file, export_settings, node, parent_gd_node):
|
|
return mesh_node
|
|
return mesh_node
|
|
|
|
|
|
|
|
|
|
-def export_mesh(escn_file, export_settings, node, armature):
|
|
|
|
|
|
+def export_mesh(escn_file, export_settings, node, armature_data):
|
|
"""Saves a mesh into the escn file """
|
|
"""Saves a mesh into the escn file """
|
|
# Check if it exists so we don't bother to export it twice
|
|
# Check if it exists so we don't bother to export it twice
|
|
mesh = node.data
|
|
mesh = node.data
|
|
@@ -61,7 +80,7 @@ def export_mesh(escn_file, export_settings, node, armature):
|
|
escn_file,
|
|
escn_file,
|
|
export_settings,
|
|
export_settings,
|
|
node,
|
|
node,
|
|
- armature)
|
|
|
|
|
|
+ armature_data)
|
|
|
|
|
|
for surface in surfaces:
|
|
for surface in surfaces:
|
|
mesh_resource[surface.name_str] = surface
|
|
mesh_resource[surface.name_str] = surface
|
|
@@ -72,12 +91,21 @@ def export_mesh(escn_file, export_settings, node, armature):
|
|
return mesh_id
|
|
return mesh_id
|
|
|
|
|
|
|
|
|
|
-def make_arrays(escn_file, export_settings, node, armature):
|
|
|
|
|
|
+def make_arrays(escn_file, export_settings, node, armature_data):
|
|
"""Generates arrays of positions, normals etc"""
|
|
"""Generates arrays of positions, normals etc"""
|
|
|
|
+ if armature_data is not None:
|
|
|
|
+ original_pose_position = armature_data.pose_position
|
|
|
|
+ armature_data.pose_position = 'REST'
|
|
|
|
+ bpy.context.scene.update()
|
|
|
|
+
|
|
mesh = node.to_mesh(bpy.context.scene,
|
|
mesh = node.to_mesh(bpy.context.scene,
|
|
export_settings['use_mesh_modifiers'],
|
|
export_settings['use_mesh_modifiers'],
|
|
"RENDER")
|
|
"RENDER")
|
|
|
|
|
|
|
|
+ if armature_data is not None:
|
|
|
|
+ armature_data.pose_position = original_pose_position
|
|
|
|
+ bpy.context.scene.update()
|
|
|
|
+
|
|
# Prepare the mesh for export
|
|
# Prepare the mesh for export
|
|
tri_mesh = bmesh.new()
|
|
tri_mesh = bmesh.new()
|
|
tri_mesh.from_mesh(mesh)
|
|
tri_mesh.from_mesh(mesh)
|
|
@@ -106,9 +134,11 @@ def make_arrays(escn_file, export_settings, node, armature):
|
|
has_tangents
|
|
has_tangents
|
|
)
|
|
)
|
|
|
|
|
|
|
|
+ has_bone = True if armature_data is not None else False
|
|
|
|
+
|
|
for surface_id, surface in enumerate(surfaces):
|
|
for surface_id, surface in enumerate(surfaces):
|
|
surface.id = surface_id
|
|
surface.id = surface_id
|
|
- surface.armature = armature
|
|
|
|
|
|
+ surface.has_bone = has_bone
|
|
|
|
|
|
bpy.data.meshes.remove(mesh)
|
|
bpy.data.meshes.remove(mesh)
|
|
|
|
|
|
@@ -166,6 +196,10 @@ def generate_surfaces(escn_file, export_settings, mesh, has_tangents):
|
|
new_vert.tangent = fix_vertex(loop.tangent)
|
|
new_vert.tangent = fix_vertex(loop.tangent)
|
|
new_vert.bitangent = fix_vertex(loop.bitangent)
|
|
new_vert.bitangent = fix_vertex(loop.bitangent)
|
|
|
|
|
|
|
|
+ for vertex_group in mesh.vertices[loop.vertex_index].groups:
|
|
|
|
+ new_vert.bones.append(vertex_group.group)
|
|
|
|
+ new_vert.weights.append(vertex_group.weight)
|
|
|
|
+
|
|
# Merge similar vertices
|
|
# Merge similar vertices
|
|
tup = new_vert.get_tup()
|
|
tup = new_vert.get_tup()
|
|
if tup not in surface.vertex_map:
|
|
if tup not in surface.vertex_map:
|
|
@@ -189,7 +223,7 @@ class Surface:
|
|
self.indices = []
|
|
self.indices = []
|
|
self.id = None
|
|
self.id = None
|
|
self.material = None
|
|
self.material = None
|
|
- self.armature = None
|
|
|
|
|
|
+ self.has_bone = False
|
|
|
|
|
|
def calc_tangent_dp(self, vert):
|
|
def calc_tangent_dp(self, vert):
|
|
"""Calculates the dot product of the tangent. I think this has
|
|
"""Calculates the dot product of the tangent. I think this has
|
|
@@ -279,37 +313,36 @@ class Surface:
|
|
|
|
|
|
def _get_bone_arrays(self):
|
|
def _get_bone_arrays(self):
|
|
"""Returns the most influential bones and their weights"""
|
|
"""Returns the most influential bones and their weights"""
|
|
- if self.armature is None:
|
|
|
|
|
|
+ if not self.has_bone:
|
|
return [
|
|
return [
|
|
Array("null, ; No Bones", "", ""),
|
|
Array("null, ; No Bones", "", ""),
|
|
Array("null, ; No Weights", "", "")
|
|
Array("null, ; No Weights", "", "")
|
|
]
|
|
]
|
|
|
|
|
|
- # Skin Weights!
|
|
|
|
- float_values = Array("FloatArray(")
|
|
|
|
- float_valuesw = Array("FloatArray(")
|
|
|
|
|
|
+ # Skin Weights
|
|
|
|
+ bone_idx_array = Array("IntArray(")
|
|
|
|
+ bone_ws_array = Array("FloatArray(")
|
|
for vert in self.vertices:
|
|
for vert in self.vertices:
|
|
- # skin_weights_total += len(v.weights)
|
|
|
|
weights = []
|
|
weights = []
|
|
- for i in len(vert.bones):
|
|
|
|
- weights += (vert.bones[i], vert.weights[i])
|
|
|
|
|
|
+ for i in range(len(vert.bones)):
|
|
|
|
+ weights.append((vert.bones[i], vert.weights[i]))
|
|
|
|
|
|
- weights = sorted(weights, key=lambda x: -x[1])
|
|
|
|
|
|
+ weights = sorted(weights, key=lambda x: x[1], reverse=True)
|
|
totalw = 0.0
|
|
totalw = 0.0
|
|
for weight in weights:
|
|
for weight in weights:
|
|
totalw += weight[1]
|
|
totalw += weight[1]
|
|
if totalw == 0.0:
|
|
if totalw == 0.0:
|
|
totalw = 0.000000001
|
|
totalw = 0.000000001
|
|
|
|
|
|
- for i in range(4):
|
|
|
|
|
|
+ for i in range(MAX_BONE_PER_VERTEX):
|
|
if i < len(weights):
|
|
if i < len(weights):
|
|
- float_values.append(weights[i][0])
|
|
|
|
- float_valuesw.append(weights[i][1]/totalw)
|
|
|
|
|
|
+ bone_idx_array.append(weights[i][0])
|
|
|
|
+ bone_ws_array.append(weights[i][1]/totalw)
|
|
else:
|
|
else:
|
|
- float_values.append(0)
|
|
|
|
- float_valuesw.append(0.0)
|
|
|
|
|
|
+ bone_idx_array.append(0)
|
|
|
|
+ bone_ws_array.append(0.0)
|
|
|
|
|
|
- return float_values, float_valuesw
|
|
|
|
|
|
+ return bone_idx_array, bone_ws_array
|
|
|
|
|
|
@property
|
|
@property
|
|
def name_str(self):
|
|
def name_str(self):
|