documentation 1
This commit is contained in:
parent
8e69bea14e
commit
d4f9982768
|
@ -1127,21 +1127,25 @@ class ArmoryExporter:
|
||||||
|
|
||||||
def export_shape_keys(self, bobject: bpy.types.Object, export_mesh: bpy.types.Mesh, out_mesh):
|
def export_shape_keys(self, bobject: bpy.types.Object, export_mesh: bpy.types.Mesh, out_mesh):
|
||||||
|
|
||||||
|
# Max shape keys supported
|
||||||
max_shape_keys = 32
|
max_shape_keys = 32
|
||||||
|
# Path to store shape key textures
|
||||||
output_dir = bpy.path.abspath('//') + "Bundled\\"
|
output_dir = bpy.path.abspath('//') + "Bundled\\"
|
||||||
name = bobject.data.name
|
name = bobject.data.name
|
||||||
vert_pos = []
|
vert_pos = []
|
||||||
vert_nor = []
|
vert_nor = []
|
||||||
names = []
|
names = []
|
||||||
default_values = [0] * max_shape_keys
|
default_values = [0] * max_shape_keys
|
||||||
|
# Shape key base mesh
|
||||||
shape_key_base = bobject.data.shape_keys.key_blocks[0]
|
shape_key_base = bobject.data.shape_keys.key_blocks[0]
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
|
# Loop through all shape keys
|
||||||
for shape_key in bobject.data.shape_keys.key_blocks[1:]:
|
for shape_key in bobject.data.shape_keys.key_blocks[1:]:
|
||||||
|
|
||||||
if(count > max_shape_keys):
|
if(count > max_shape_keys):
|
||||||
break
|
break
|
||||||
|
# get vertex data from shape key
|
||||||
vert_data = self.get_vertex_data_from_shape_key(shape_key_base, shape_key)
|
vert_data = self.get_vertex_data_from_shape_key(shape_key_base, shape_key)
|
||||||
vert_pos.append(vert_data['pos'])
|
vert_pos.append(vert_data['pos'])
|
||||||
vert_nor.append(vert_data['nor'])
|
vert_nor.append(vert_data['nor'])
|
||||||
|
@ -1150,24 +1154,32 @@ class ArmoryExporter:
|
||||||
|
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
|
# Convert to array for easy manipulation
|
||||||
pos_array = np.array(vert_pos)
|
pos_array = np.array(vert_pos)
|
||||||
nor_array = np.array(vert_nor)
|
nor_array = np.array(vert_nor)
|
||||||
|
|
||||||
|
# Min and Max values of shape key displacements
|
||||||
max = np.amax(pos_array)
|
max = np.amax(pos_array)
|
||||||
min = np.amin(pos_array)
|
min = np.amin(pos_array)
|
||||||
|
|
||||||
array_size = len(pos_array[0]), len(pos_array)
|
array_size = len(pos_array[0]), len(pos_array)
|
||||||
|
|
||||||
|
# Get best 2^n image size to fit shape key data (min = 2 X 2, max = 4096 X 4096)
|
||||||
img_size, extra_zeros, block_size = self.get_best_image_size(array_size)
|
img_size, extra_zeros, block_size = self.get_best_image_size(array_size)
|
||||||
|
|
||||||
|
# Image size required is too large. Skip export
|
||||||
if(img_size < 1):
|
if(img_size < 1):
|
||||||
log.error(f"""object {bobject.name} contains too many vertices or shape keys to support shape keys export""")
|
log.error(f"""object {bobject.name} contains too many vertices or shape keys to support shape keys export""")
|
||||||
self.remove_morph_uv_set(bobject)
|
self.remove_morph_uv_set(bobject)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Write data to image
|
||||||
self.bake_to_image(pos_array, nor_array, max, min, extra_zeros, img_size, name, output_dir)
|
self.bake_to_image(pos_array, nor_array, max, min, extra_zeros, img_size, name, output_dir)
|
||||||
|
|
||||||
|
# Create a new UV set for shape keys
|
||||||
self.create_morph_uv_set(bobject, img_size)
|
self.create_morph_uv_set(bobject, img_size)
|
||||||
|
|
||||||
|
# Export Shape Key names, defaults, etc..
|
||||||
morph_target = {}
|
morph_target = {}
|
||||||
morph_target['morph_target_data_file'] = name
|
morph_target['morph_target_data_file'] = name
|
||||||
morph_target['morph_target_ref'] = names
|
morph_target['morph_target_ref'] = names
|
||||||
|
@ -1193,27 +1205,31 @@ class ArmoryExporter:
|
||||||
pos = []
|
pos = []
|
||||||
nor = []
|
nor = []
|
||||||
|
|
||||||
|
# Loop through all vertices
|
||||||
for i in range(num_verts):
|
for i in range(num_verts):
|
||||||
|
# Vertex position relative to base vertex
|
||||||
pos.append(list(vert_pos[i].co - base_vert_pos[i].co))
|
pos.append(list(vert_pos[i].co - base_vert_pos[i].co))
|
||||||
temp = []
|
temp = []
|
||||||
for j in range(3):
|
for j in range(3):
|
||||||
|
# Vertex normal relative to base vertex
|
||||||
temp.append(vert_nor[j + i * 3] - base_vert_nor[j + i * 3])
|
temp.append(vert_nor[j + i * 3] - base_vert_nor[j + i * 3])
|
||||||
nor.append(temp)
|
nor.append(temp)
|
||||||
|
|
||||||
return {'pos': pos, 'nor': nor}
|
return {'pos': pos, 'nor': nor}
|
||||||
|
|
||||||
def bake_to_image(self, pos_array, nor_array, pos_max, pos_min, extra_x, img_size, name, output_dir):
|
def bake_to_image(self, pos_array, nor_array, pos_max, pos_min, extra_x, img_size, name, output_dir):
|
||||||
|
# Scale position data between [0, 1] to bake to image
|
||||||
pos_array_scaled = np.interp(pos_array, (pos_min, pos_max), (0, 1))
|
pos_array_scaled = np.interp(pos_array, (pos_min, pos_max), (0, 1))
|
||||||
|
# Write positions to image
|
||||||
self.write_output_image(pos_array_scaled, extra_x, img_size, name + '_morph_pos', output_dir)
|
self.write_output_image(pos_array_scaled, extra_x, img_size, name + '_morph_pos', output_dir)
|
||||||
|
# Scale normal data between [0, 1] to bake to image
|
||||||
nor_array_scaled = np.interp(nor_array, (-1, 1), (0, 1))
|
nor_array_scaled = np.interp(nor_array, (-1, 1), (0, 1))
|
||||||
|
# Write normals to image
|
||||||
self.write_output_image(nor_array_scaled, extra_x, img_size, name + '_morph_nor', output_dir)
|
self.write_output_image(nor_array_scaled, extra_x, img_size, name + '_morph_nor', output_dir)
|
||||||
|
|
||||||
def write_output_image(self, data, extra_x, img_size, name, output_dir):
|
def write_output_image(self, data, extra_x, img_size, name, output_dir):
|
||||||
|
|
||||||
|
# Pad data with zeros to make up for required number of pixels of 2^n format
|
||||||
data = np.pad(data, ((0, 0), (0, extra_x), (0, 0)), 'minimum')
|
data = np.pad(data, ((0, 0), (0, extra_x), (0, 0)), 'minimum')
|
||||||
pixel_list = []
|
pixel_list = []
|
||||||
|
|
||||||
|
@ -1247,7 +1263,7 @@ class ArmoryExporter:
|
||||||
obj.data.uv_layers.remove(layer)
|
obj.data.uv_layers.remove(layer)
|
||||||
|
|
||||||
def create_morph_uv_set(self, obj, img_size):
|
def create_morph_uv_set(self, obj, img_size):
|
||||||
|
# Get/ create morph UV set
|
||||||
if(obj.data.uv_layers.get('UVMap_shape_key') is None):
|
if(obj.data.uv_layers.get('UVMap_shape_key') is None):
|
||||||
obj.data.uv_layers.new(name = 'UVMap_shape_key')
|
obj.data.uv_layers.new(name = 'UVMap_shape_key')
|
||||||
|
|
||||||
|
@ -1259,6 +1275,7 @@ class ArmoryExporter:
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
j = 0
|
j = 0
|
||||||
|
# Arrange UVs to match exported image pixels
|
||||||
for v in bm.verts:
|
for v in bm.verts:
|
||||||
for l in v.link_loops:
|
for l in v.link_loops:
|
||||||
uv_data = l[uv_layer]
|
uv_data = l[uv_layer]
|
||||||
|
@ -1303,6 +1320,7 @@ class ArmoryExporter:
|
||||||
# Check if shape keys were exported
|
# Check if shape keys were exported
|
||||||
has_morph_target = self.get_shape_keys(bobject.data)
|
has_morph_target = self.get_shape_keys(bobject.data)
|
||||||
if(has_morph_target):
|
if(has_morph_target):
|
||||||
|
# Shape keys UV are exported separately, so reduce UV count by 1
|
||||||
num_uv_layers -= 1
|
num_uv_layers -= 1
|
||||||
morph_uv_index = self.get_morph_uv_index(bobject.data)
|
morph_uv_index = self.get_morph_uv_index(bobject.data)
|
||||||
has_tex = (self.get_export_uvs(bobject.data) and num_uv_layers > 0) or is_baked
|
has_tex = (self.get_export_uvs(bobject.data) and num_uv_layers > 0) or is_baked
|
||||||
|
@ -1614,8 +1632,10 @@ Make sure the mesh only has tris/quads.""")
|
||||||
bobject_eval = bobject.evaluated_get(self.depsgraph) if apply_modifiers else bobject
|
bobject_eval = bobject.evaluated_get(self.depsgraph) if apply_modifiers else bobject
|
||||||
export_mesh = bobject_eval.to_mesh()
|
export_mesh = bobject_eval.to_mesh()
|
||||||
|
|
||||||
|
# Export shape keys here
|
||||||
if shape_keys:
|
if shape_keys:
|
||||||
self.export_shape_keys(bobject, export_mesh, out_mesh)
|
self.export_shape_keys(bobject, export_mesh, out_mesh)
|
||||||
|
# Update dependancy after new UV layer was added
|
||||||
self.depsgraph.update()
|
self.depsgraph.update()
|
||||||
bobject_eval = bobject.evaluated_get(self.depsgraph) if apply_modifiers else bobject
|
bobject_eval = bobject.evaluated_get(self.depsgraph) if apply_modifiers else bobject
|
||||||
export_mesh = bobject_eval.to_mesh()
|
export_mesh = bobject_eval.to_mesh()
|
||||||
|
@ -1640,7 +1660,7 @@ Make sure the mesh only has tris/quads.""")
|
||||||
if armature:
|
if armature:
|
||||||
self.export_skin(bobject, armature, export_mesh, out_mesh)
|
self.export_skin(bobject, armature, export_mesh, out_mesh)
|
||||||
|
|
||||||
# Restore the morph state
|
# Restore the morph state after mesh export
|
||||||
if shape_keys:
|
if shape_keys:
|
||||||
bobject.active_shape_key_index = active_shape_key_index
|
bobject.active_shape_key_index = active_shape_key_index
|
||||||
bobject.show_only_shape_key = show_only_shape_key
|
bobject.show_only_shape_key = show_only_shape_key
|
||||||
|
|
Loading…
Reference in a new issue