Fixed skin export.
This commit is contained in:
parent
1f3684f9b0
commit
f34760589f
|
@ -32,7 +32,7 @@ class Animation extends Trait {
|
|||
}
|
||||
|
||||
function update() {
|
||||
Eg.setAnimationParams(model, iron.sys.Time.delta / 10);
|
||||
Eg.setAnimationParams(model, iron.sys.Time.delta);
|
||||
}
|
||||
|
||||
public function play(trackName:String, loop = true, speed = 1.0, onTrackComplete:Void->Void = null) {
|
||||
|
|
|
@ -54,11 +54,11 @@ deltaSubscaleName = ["dxscl", "dyscl", "dzscl"]
|
|||
axisName = ["x", "y", "z"]
|
||||
|
||||
class Vertex:
|
||||
__slots__ = ("co", "normal", "uvs", "col", "loop_indices", "index", "weights", "joint_indexes")
|
||||
__slots__ = ("co", "normal", "uvs", "col", "loop_indices", "index", "bone_weights", "bone_indices", "bone_count", "vertexIndex")
|
||||
def __init__(self, mesh, loop):
|
||||
vi = loop.vertex_index
|
||||
self.vertexIndex = loop.vertex_index
|
||||
i = loop.index
|
||||
self.co = mesh.vertices[vi].co.freeze()
|
||||
self.co = mesh.vertices[self.vertexIndex].co.freeze()
|
||||
self.normal = loop.normal.freeze()
|
||||
self.uvs = tuple(layer.data[i].uv.freeze() for layer in mesh.uv_layers)
|
||||
self.col = [0, 0, 0]
|
||||
|
@ -67,17 +67,13 @@ class Vertex:
|
|||
self.loop_indices = [i]
|
||||
|
||||
# Take the four most influential groups
|
||||
groups = sorted(mesh.vertices[vi].groups, key=lambda group: group.weight, reverse=True)
|
||||
if len(groups) > 4:
|
||||
groups = groups[:4]
|
||||
# groups = sorted(mesh.vertices[self.vertexIndex].groups, key=lambda group: group.weight, reverse=True)
|
||||
# if len(groups) > 4:
|
||||
# groups = groups[:4]
|
||||
|
||||
self.weights = [group.weight for group in groups]
|
||||
self.joint_indexes = [group.group for group in groups]
|
||||
|
||||
if len(self.weights) < 4:
|
||||
for i in range(len(self.weights), 4):
|
||||
self.weights.append(0.0)
|
||||
self.joint_indexes.append(0)
|
||||
# self.bone_weights = [group.weight for group in groups]
|
||||
# self.bone_indices = [group.group for group in groups]
|
||||
# self.bone_count = len(self.bone_weights)
|
||||
|
||||
self.index = 0
|
||||
|
||||
|
@ -1482,13 +1478,13 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
|
|||
skeleton = node.data
|
||||
if (skeleton):
|
||||
o['nodes'] = []
|
||||
o['bones_ref'] = 'bones_' + o.id
|
||||
o['bones_ref'] = 'bones_' + o['id']
|
||||
|
||||
# TODO: use option_geometry_per_file
|
||||
fp = self.get_geoms_file_path(o.bones_ref)
|
||||
fp = self.get_geoms_file_path(o['bones_ref'])
|
||||
assets.add(fp)
|
||||
|
||||
if self.node_is_geometry_cached(node) == False or not os.path.exists(fp):
|
||||
if node.data.armature_cached == False or not os.path.exists(fp):
|
||||
bones = []
|
||||
for bone in skeleton.bones:
|
||||
if (not bone.parent):
|
||||
|
@ -1501,7 +1497,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
|
|||
bones_obj = {}
|
||||
bones_obj['nodes'] = bones
|
||||
utils.write_arm(fp, bones_obj)
|
||||
node.data.geometry_cached = True
|
||||
node.data.armature_cached = True
|
||||
|
||||
if (parento == None):
|
||||
self.output['nodes'].append(o)
|
||||
|
@ -1518,7 +1514,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
|
|||
if (subnode.parent_type != "BONE"):
|
||||
self.ExportNode(subnode, scene, None, o)
|
||||
|
||||
def ExportSkin(self, node, armature, exportVertexArray, om):
|
||||
def ExportSkinQuality(self, node, armature, exportVertexArray, om):
|
||||
# This function exports all skinning data, which includes the skeleton
|
||||
# and per-vertex bone influence data.
|
||||
oskin = {}
|
||||
|
@ -1597,16 +1593,48 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
|
|||
# Write the bone count array. There is one entry per vertex.
|
||||
oskin['bone_count_array'] = boneCountArray
|
||||
|
||||
#self.IndentWrite(B"unsigned_int16\t\t// ")
|
||||
#self.WriteInt(len(boneCountArray))
|
||||
#self.WriteIntArray(boneCountArray)
|
||||
|
||||
# Write the bone index array. The number of entries is the sum of the bone counts for all vertices.
|
||||
oskin['bone_index_array'] = boneIndexArray
|
||||
|
||||
# Write the bone weight array. The number of entries is the sum of the bone counts for all vertices.
|
||||
oskin['bone_weight_array'] = boneWeightArray
|
||||
|
||||
def ExportSkinFast(self, node, armature, vert_list, om):
|
||||
oskin = {}
|
||||
om['skin'] = oskin
|
||||
|
||||
otrans = {}
|
||||
oskin['transform'] = otrans
|
||||
otrans['values'] = self.WriteMatrix(node.matrix_world)
|
||||
|
||||
oskel = {}
|
||||
oskin['skeleton'] = oskel
|
||||
oskel['bone_ref_array'] = []
|
||||
|
||||
boneArray = armature.data.bones
|
||||
boneCount = len(boneArray)
|
||||
for i in range(boneCount):
|
||||
boneRef = self.FindNode(boneArray[i].name)
|
||||
if (boneRef):
|
||||
oskel['bone_ref_array'].append(boneRef[1]["structName"])
|
||||
else:
|
||||
oskel['bone_ref_array'].append("null")
|
||||
|
||||
oskel['transforms'] = []
|
||||
for i in range(boneCount):
|
||||
oskel['transforms'].append(self.WriteMatrix(armature.matrix_world * boneArray[i].matrix_local))
|
||||
|
||||
boneCountArray = []
|
||||
boneIndexArray = []
|
||||
boneWeightArray = []
|
||||
for vtx in vert_list:
|
||||
boneCountArray.append(vtx.bone_count)
|
||||
boneIndexArray += vtx.bone_indices
|
||||
boneWeightArray += vtx.bone_weights
|
||||
oskin['bone_count_array'] = boneCountArray
|
||||
oskin['bone_index_array'] = boneIndexArray
|
||||
oskin['bone_weight_array'] = boneWeightArray
|
||||
|
||||
def calc_tangents(self, posa, nora, uva, ia):
|
||||
triangle_count = int(len(ia) / 3)
|
||||
vertex_count = int(len(posa) / 3)
|
||||
|
@ -1691,6 +1719,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
|
|||
# Make arrays
|
||||
for i, vtx in enumerate(vert_list):
|
||||
vtx.index = i
|
||||
|
||||
co = vtx.co
|
||||
normal = vtx.normal
|
||||
for j in range(3):
|
||||
|
@ -1755,7 +1784,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
|
|||
if poly.loop_total == 3:
|
||||
prim += indices
|
||||
elif poly.loop_total > 3:
|
||||
for i in range(poly.loop_total-1):
|
||||
for i in range(poly.loop_total-2):
|
||||
prim += (indices[-1], indices[i], indices[i + 1])
|
||||
|
||||
# Write indices
|
||||
|
@ -1784,6 +1813,8 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
|
|||
tana['values'] = self.calc_tangents(pa['values'], na['values'], ta['values'], om['index_arrays'][0]['values'])
|
||||
om['vertex_arrays'].append(tana)
|
||||
|
||||
return vert_list
|
||||
|
||||
def ExportGeometry(self, objectRef, scene):
|
||||
# This function exports a single geometry object.
|
||||
node = objectRef[1]["nodeTable"][0]
|
||||
|
@ -1867,14 +1898,16 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
|
|||
exportMesh = node.to_mesh(scene, applyModifiers, "RENDER", True, False)
|
||||
|
||||
# Process geometry
|
||||
if ArmoryExporter.option_optimize_geometry:
|
||||
self.export_geometry_quality(exportMesh, node, fp, o, om)
|
||||
geom_opt = ArmoryExporter.option_optimize_geometry
|
||||
if geom_opt:
|
||||
unifiedVertexArray = self.export_geometry_quality(exportMesh, node, fp, o, om)
|
||||
if (armature):
|
||||
self.ExportSkinQuality(node, armature, unifiedVertexArray, om)
|
||||
else:
|
||||
self.export_geometry_fast(exportMesh, node, fp, o, om)
|
||||
|
||||
# If the mesh is skinned, export the skinning data here.
|
||||
if (armature):
|
||||
self.ExportSkin(node, armature, unifiedVertexArray, om)
|
||||
vert_list = self.export_geometry_fast(exportMesh, node, fp, o, om)
|
||||
if (armature):
|
||||
self.ExportSkinQuality(node, armature, vert_list, om)
|
||||
# self.ExportSkinFast(node, armature, vert_list, om)
|
||||
|
||||
# Restore the morph state.
|
||||
if (shapeKeys):
|
||||
|
@ -2042,6 +2075,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
|
|||
|
||||
# Delete the new mesh that we made earlier.
|
||||
bpy.data.meshes.remove(exportMesh)
|
||||
return unifiedVertexArray
|
||||
|
||||
def ExportLight(self, objectRef):
|
||||
# This function exports a single light object.
|
||||
|
@ -2282,19 +2316,18 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
|
|||
for n in refs:
|
||||
if n.instanced_children == True:
|
||||
is_instanced = True
|
||||
# TODO: cache instanced geometry
|
||||
node.data.geometry_cached = False
|
||||
# Save offset data
|
||||
instance_offsets = [0, 0, 0] # Include parent
|
||||
for sn in n.children:
|
||||
# instance_offsets.append(sn.location.x)
|
||||
# instance_offsets.append(sn.location.y)
|
||||
# instance_offsets.append(sn.location.z)
|
||||
# Do not take parent matrix into account
|
||||
loc = sn.matrix_local.to_translation()
|
||||
instance_offsets.append(loc.x)
|
||||
instance_offsets.append(loc.y)
|
||||
instance_offsets.append(loc.z)
|
||||
# m = sn.matrix_local
|
||||
# instance_offsets.append(m[0][3]) #* m[0][0]) # Scale
|
||||
# instance_offsets.append(m[1][3]) #* m[1][1])
|
||||
# instance_offsets.append(m[2][3]) #* m[2][2])
|
||||
break
|
||||
return is_instanced, instance_offsets
|
||||
|
||||
|
|
|
@ -1423,7 +1423,7 @@ def findNodeByLinkFrom(node_group, from_node, outp):
|
|||
return link.to_node
|
||||
|
||||
def getRootNode(node_group):
|
||||
# Find first node linked to begin node and gather defs
|
||||
# Find first node linked to begin node
|
||||
rn = None
|
||||
for n in node_group.nodes:
|
||||
if n.bl_idname == 'BeginNodeType':
|
||||
|
@ -1436,9 +1436,7 @@ def getRootNode(node_group):
|
|||
if n.inputs[5].default_value == False: # No HDR space lighting, append def
|
||||
bpy.data.worlds[0].world_defs += '_LDR'
|
||||
rn = findNodeByLinkFrom(node_group, n, n.outputs[0])
|
||||
elif n.bl_idname == 'TAAPassNodeType':
|
||||
# bpy.data.worlds[0].world_defs += '_TAA'
|
||||
assets.add_khafile_def('WITH_TAA')
|
||||
break
|
||||
return rn
|
||||
|
||||
def get_render_targets(root_node, node_group):
|
||||
|
@ -1448,6 +1446,11 @@ def get_render_targets(root_node, node_group):
|
|||
return render_targets, depth_buffers
|
||||
|
||||
def traverse_for_rt(node, node_group, render_targets, depth_buffers):
|
||||
# Gather defs from linked nodes
|
||||
# if node.bl_idname == 'TAAPassNodeType':
|
||||
# bpy.data.worlds[0].world_defs += '_TAA'
|
||||
# assets.add_khafile_def('WITH_TAA')
|
||||
|
||||
# Collect render targets
|
||||
if node.bl_idname == 'SetTargetNodeType' or node.bl_idname == 'QuadPassNodeType' or node.bl_idname == 'DrawCompositorNodeType' or node.bl_idname == 'DrawCompositorWithFXAANodeType':
|
||||
if node.inputs[1].is_linked:
|
||||
|
|
|
@ -175,11 +175,11 @@ def export_game_data(fp, sdk_path):
|
|||
armatures = []
|
||||
for o in bpy.data.objects:
|
||||
if o.type == 'ARMATURE':
|
||||
a = Object()
|
||||
a.armature = o
|
||||
a.x = o.location.x
|
||||
a.y = o.location.y
|
||||
a.z = o.location.z
|
||||
a = {}
|
||||
a['armature'] = o
|
||||
a['x'] = o.location.x
|
||||
a['y'] = o.location.y
|
||||
a['z'] = o.location.z
|
||||
armatures.append(a)
|
||||
o.location.x = 0
|
||||
o.location.y = 0
|
||||
|
@ -198,9 +198,9 @@ def export_game_data(fp, sdk_path):
|
|||
|
||||
# Move armatures back
|
||||
for a in armatures:
|
||||
a.armature.location.x = a.x
|
||||
a.armature.location.y = a.y
|
||||
a.armature.location.z = a.z
|
||||
a['armature'].location.x = a['x']
|
||||
a['armature'].location.y = a['y']
|
||||
a['armature'].location.z = a['z']
|
||||
|
||||
# Clean compiled variants if cache is disabled
|
||||
if bpy.data.worlds[0].CGCacheShaders == False:
|
||||
|
|
|
@ -9,7 +9,10 @@ from bpy.props import *
|
|||
def cb_scene_update(context):
|
||||
edit_obj = bpy.context.edit_object
|
||||
if edit_obj is not None and edit_obj.is_updated_data is True:
|
||||
edit_obj.data.geometry_cached = False
|
||||
if edit_obj.type == 'MESH':
|
||||
edit_obj.data.geometry_cached = False
|
||||
elif edit_obj.type == 'ARMATURE':
|
||||
edit_obj.data.armature_cached = False
|
||||
|
||||
def initProperties():
|
||||
# For project
|
||||
|
@ -51,6 +54,15 @@ def initProperties():
|
|||
|
||||
# For object
|
||||
bpy.types.Object.instanced_children = bpy.props.BoolProperty(name="Instanced Children", default=False)
|
||||
bpy.types.Object.instanced_children_loc_x = bpy.props.BoolProperty(name="X", default=True)
|
||||
bpy.types.Object.instanced_children_loc_y = bpy.props.BoolProperty(name="Y", default=True)
|
||||
bpy.types.Object.instanced_children_loc_z = bpy.props.BoolProperty(name="Z", default=True)
|
||||
bpy.types.Object.instanced_children_rot_x = bpy.props.BoolProperty(name="X", default=False)
|
||||
bpy.types.Object.instanced_children_rot_y = bpy.props.BoolProperty(name="Y", default=False)
|
||||
bpy.types.Object.instanced_children_rot_z = bpy.props.BoolProperty(name="Z", default=False)
|
||||
bpy.types.Object.instanced_children_scale_x = bpy.props.BoolProperty(name="X", default=False)
|
||||
bpy.types.Object.instanced_children_scale_y = bpy.props.BoolProperty(name="Y", default=False)
|
||||
bpy.types.Object.instanced_children_scale_z = bpy.props.BoolProperty(name="Z", default=False)
|
||||
bpy.types.Object.override_material = bpy.props.BoolProperty(name="Override Material", default=False)
|
||||
bpy.types.Object.override_material_name = bpy.props.StringProperty(name="Name", default="")
|
||||
bpy.types.Object.game_export = bpy.props.BoolProperty(name="Game Export", default=True)
|
||||
|
@ -60,6 +72,8 @@ def initProperties():
|
|||
bpy.types.Mesh.geometry_cached_edges = bpy.props.IntProperty(name="Last Edges", default=0)
|
||||
bpy.types.Mesh.static_usage = bpy.props.BoolProperty(name="Static Usage", default=True)
|
||||
bpy.types.Curve.static_usage = bpy.props.BoolProperty(name="Static Usage", default=True)
|
||||
# For armature
|
||||
bpy.types.Armature.armature_cached = bpy.props.BoolProperty(name="Armature Cached", default=False)
|
||||
# For camera
|
||||
bpy.types.Camera.frustum_culling = bpy.props.BoolProperty(name="Frustum Culling", default=True)
|
||||
bpy.types.Camera.pipeline_path = bpy.props.StringProperty(name="Pipeline Path", default="deferred_pipeline")
|
||||
|
@ -153,6 +167,22 @@ class ObjectPropsPanel(bpy.types.Panel):
|
|||
layout.prop(obj, 'game_export')
|
||||
if obj.type == 'MESH':
|
||||
layout.prop(obj, 'instanced_children')
|
||||
if obj.instanced_children:
|
||||
layout.label('Location')
|
||||
row = layout.row()
|
||||
row.prop(obj, 'instanced_children_loc_x')
|
||||
row.prop(obj, 'instanced_children_loc_y')
|
||||
row.prop(obj, 'instanced_children_loc_z')
|
||||
layout.label('Rotation')
|
||||
row = layout.row()
|
||||
row.prop(obj, 'instanced_children_rot_x')
|
||||
row.prop(obj, 'instanced_children_rot_y')
|
||||
row.prop(obj, 'instanced_children_rot_z')
|
||||
layout.label('Scale')
|
||||
row = layout.row()
|
||||
row.prop(obj, 'instanced_children_scale_x')
|
||||
row.prop(obj, 'instanced_children_scale_y')
|
||||
row.prop(obj, 'instanced_children_scale_z')
|
||||
layout.prop(obj, 'override_material')
|
||||
if obj.override_material:
|
||||
layout.prop(obj, 'override_material_name')
|
||||
|
|
|
@ -55,7 +55,7 @@ project.addAssets('Assets/**');
|
|||
for d in assets.khafile_defs:
|
||||
f.write("project.addDefine('" + d + "');\n")
|
||||
|
||||
config_text = bpy.data.worlds[0]['CGKhafileConfig']
|
||||
config_text = bpy.data.worlds[0]['CGKhafile']
|
||||
if config_text != '':
|
||||
f.write(bpy.data.texts[config_text].as_string())
|
||||
|
||||
|
|
Loading…
Reference in a new issue