Rewrite convert-mesh: support both flat & non-flat shading in one model, support specifying model name

This commit is contained in:
Nikita Lisitsa 2022-02-22 22:17:58 +03:00
parent 3485e9ff21
commit e557fd4eaf
2 changed files with 56 additions and 78 deletions

View file

@ -11,23 +11,24 @@ function(psemek_add_model TARGET)
while(ARGN) while(ARGN)
list(GET ARGN 0 _FILE) list(GET ARGN 0 _FILE)
list(GET ARGN 1 _NAME) list(GET ARGN 1 _MODEL_NAME)
list(REMOVE_AT ARGN 0 1) list(GET ARGN 2 _RESOURCE_NAME)
list(REMOVE_AT ARGN 0 1 2)
get_filename_component(_NAME_PREFIX ${_NAME} DIRECTORY) get_filename_component(_NAME_PREFIX ${_RESOURCE_NAME} DIRECTORY)
file(MAKE_DIRECTORY "${_OUT_DIR}/meshes/${_NAME_PREFIX}") file(MAKE_DIRECTORY "${_OUT_DIR}/meshes/${_NAME_PREFIX}")
set(_OUT_FILE "${_OUT_DIR}/meshes/${_NAME}") set(_OUT_FILE "${_OUT_DIR}/meshes/${_RESOURCE_NAME}")
set(_SCRIPT "${PSEMEK_CONVERT_MESH_DIR}/bin/convert-mesh.py") set(_SCRIPT "${PSEMEK_CONVERT_MESH_DIR}/bin/convert-mesh.py")
add_custom_command(OUTPUT "${_OUT_FILE}" add_custom_command(OUTPUT "${_OUT_FILE}"
COMMAND blender --background "${_FILE}" --python "${_SCRIPT}" --python-exit-code 1 -- "${_OUT_FILE}" COMMAND blender --background "${_FILE}" --python "${_SCRIPT}" --python-exit-code 1 -- "${_MODEL_NAME}" "${_OUT_FILE}"
DEPENDS "${_FILE}" "${_SCRIPT}" DEPENDS "${_FILE}" "${_SCRIPT}"
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
) )
psemek_add_resources(${TARGET} "${_OUT_FILE}" ${_NAME}) psemek_add_resources(${TARGET} "${_OUT_FILE}" ${_RESOURCE_NAME})
endwhile() endwhile()
endfunction() endfunction()

View file

@ -3,18 +3,18 @@ import math
import sys import sys
import struct import struct
model_name = sys.argv[sys.argv.index('--') + 1]
filename = sys.argv[sys.argv.index('--') + 2]
bpy.ops.object.mode_set(mode = 'OBJECT') bpy.ops.object.mode_set(mode = 'OBJECT')
obj = None obj = None
mesh = None mesh = None
flat = False if model_name in bpy.data.objects:
if 'mesh' in bpy.data.objects: obj = bpy.data.objects[model_name]
obj = bpy.data.objects['mesh'] else:
print('Using smooth normals') raise RuntimeError("Model " + model_name + " not found in file")
if 'mesh_flat' in bpy.data.objects:
obj = bpy.data.objects['mesh_flat']
print('Using flat normals')
flat = True
mesh = obj.data mesh = obj.data
colors = None colors = None
@ -27,6 +27,7 @@ if len(mesh.uv_layers) > 0:
texcoords = mesh.uv_layers.active.data texcoords = mesh.uv_layers.active.data
print('Found texture coordinates') print('Found texture coordinates')
# TODO: proper armature support
armature = None armature = None
bone_names = None bone_names = None
if 'armature' in bpy.data.objects: if 'armature' in bpy.data.objects:
@ -59,73 +60,51 @@ indices = []
mesh.calc_loop_triangles() mesh.calc_loop_triangles()
if flat: smooth_index = {}
for p in mesh.loop_triangles:
for li in p.loops:
i = len(vertex_coords)
v = mesh.vertices[mesh.loops[li].vertex_index]
vertex_coords.append((v.co.x, v.co.y, v.co.z))
vertex_normals.append((p.normal.x, p.normal.y, p.normal.z))
if colors:
vertex_colors.append(tuple(colors[li].color))
if texcoords:
vertex_texcoords.append(tuple(texcoords[li].uv))
if armature:
weights = []
for g in v.groups:
name = obj.vertex_groups[g.group].name
if name in bone_names:
weights.append((bone_names.index(name), g.weight))
for g, w in weights:
if g >= len(armature.data.bones):
print("Invalid vertex group index {} for armature weights".format(g), file=sys.stderr)
sys.exit(1)
weights = list(sorted(weights, key=lambda p: -p[1]))[:2]
while len(weights) < 2:
weights.append((0,0.0))
weights = list(sorted(weights, key=lambda p: -p[1]))[:2]
W = sum(p[1] for p in weights)
weights = [(i,w/W) for i,w in weights]
vertex_weights[vi] = weights
indices.append(i)
else:
for v in mesh.vertices:
vertex_coords.append((v.co.x, v.co.y, v.co.z))
vertex_normals.append((v.normal.x, v.normal.y, v.normal.z))
def append_vertex(v, n):
vertex_coords.append((v.co.x, v.co.y, v.co.z))
vertex_normals.append((n.x, n.y, n.z))
if colors: if colors:
vertex_colors = [None] * len(vertex_coords) vertex_colors.append(tuple(colors[li].color))
if texcoords: if texcoords:
vertex_texcoords = [None] * len(vertex_coords) vertex_texcoords.append(tuple(texcoords[li].uv))
if armature: if armature:
vertex_weights = [None] * len(vertex_coords) weights = []
for g in v.groups:
name = obj.vertex_groups[g.group].name
if name in bone_names:
weights.append((bone_names.index(name), g.weight))
for g, w in weights:
if g >= len(armature.data.bones):
print("Invalid vertex group index {} for armature weights".format(g), file=sys.stderr)
sys.exit(1)
while len(weights) < 2:
weights.append((0,0.0))
weights = list(sorted(weights, key=lambda p: -p[1]))[:2]
W = sum(p[1] for p in weights)
weights = [(i,w/W) for i,w in weights]
vertex_weights.append(weights)
for p in mesh.loop_triangles: for p in mesh.loop_triangles:
for li in p.loops: for li in p.loops:
vi = mesh.loops[li].vertex_index vi = mesh.loops[li].vertex_index
indices.append(vi) v = mesh.vertices[vi]
v = mesh.vertices[vi] n = p.normal
if colors: if p.use_smooth:
vertex_colors[vi] = tuple(colors[li].color) i = None
if texcoords: if vi not in smooth_index:
vertex_texcoords[vi] = tuple(texcoords[li].uv) i = len(vertex_coords)
if armature: smooth_index[vi] = i
weights = [] append_vertex(v, n)
for g in v.groups: else:
name = obj.vertex_groups[g.group].name i = smooth_index[vi]
if name in bone_names:
weights.append((bone_names.index(name), g.weight)) indices.append(i)
for g, w in weights: else:
if g >= len(armature.data.bones): i = len(vertex_coords)
print("Invalid vertex group index {} for armature weights".format(g), file=sys.stderr) append_vertex(v, n)
sys.exit(1) indices.append(i)
weights = list(sorted(weights, key=lambda p: -p[1]))[:2]
while len(weights) < 2:
weights.append((0,0.0))
W = sum(p[1] for p in weights)
weights = [(i,w/W) for i,w in weights]
vertex_weights[vi] = weights
assert (len(indices) % 3) == 0 assert (len(indices) % 3) == 0
@ -267,7 +246,5 @@ if armature:
for name, pdata in poses: for name, pdata in poses:
data += to_bytes((SECTION_POSE, name, pdata)) data += to_bytes((SECTION_POSE, name, pdata))
filename = sys.argv[sys.argv.index('--') + 1]
with open(filename, 'wb') as f: with open(filename, 'wb') as f:
f.write(data) f.write(data)