Add convert-mesh tool to convert blender files to binary resources
This commit is contained in:
parent
3e4cea25e7
commit
4fa64be5b0
2 changed files with 184 additions and 0 deletions
33
tools/convert-mesh/CMakeLists.txt
Normal file
33
tools/convert-mesh/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
set(PSEMEK_CONVERT_MESH_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE PATH "Path to convert-mesh tool")
|
||||||
|
|
||||||
|
function(psemek_add_model TARGET)
|
||||||
|
if(PSEMEK_PACKAGE_MODE)
|
||||||
|
if(NOT (TARGET ${TARGET}))
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_target_property(_OUT_DIR ${TARGET} BINARY_DIR)
|
||||||
|
|
||||||
|
while(ARGN)
|
||||||
|
list(GET ARGN 0 _FILE)
|
||||||
|
list(GET ARGN 1 _NAME)
|
||||||
|
list(REMOVE_AT ARGN 0 1)
|
||||||
|
|
||||||
|
get_filename_component(_NAME_PREFIX ${_NAME} DIRECTORY)
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY "${_OUT_DIR}/meshes/${_NAME_PREFIX}")
|
||||||
|
|
||||||
|
set(_OUT_FILE "${_OUT_DIR}/meshes/${_NAME}")
|
||||||
|
|
||||||
|
set(_SCRIPT "${PSEMEK_CONVERT_MESH_DIR}/bin/convert-mesh.py")
|
||||||
|
|
||||||
|
add_custom_command(OUTPUT "${_OUT_FILE}"
|
||||||
|
COMMAND blender --background "${_FILE}" --python "${_SCRIPT}" --python-exit-code 1 -- "${_OUT_FILE}"
|
||||||
|
DEPENDS "${_FILE}" "${_SCRIPT}"
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
psemek_add_resources(${TARGET} "${_OUT_FILE}" ${_NAME})
|
||||||
|
endwhile()
|
||||||
|
endfunction()
|
||||||
151
tools/convert-mesh/bin/convert-mesh.py
Normal file
151
tools/convert-mesh/bin/convert-mesh.py
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
import bpy
|
||||||
|
import math
|
||||||
|
import sys
|
||||||
|
import struct
|
||||||
|
|
||||||
|
bpy.ops.object.mode_set(mode = 'OBJECT')
|
||||||
|
|
||||||
|
mesh = None
|
||||||
|
flat = False
|
||||||
|
if 'mesh' in bpy.data.objects:
|
||||||
|
mesh = bpy.data.objects['mesh'].data
|
||||||
|
print('Using smooth normals')
|
||||||
|
if 'mesh_flat' in bpy.data.objects:
|
||||||
|
mesh = bpy.data.objects['mesh_flat'].data
|
||||||
|
print('Using flat normals')
|
||||||
|
flat = True
|
||||||
|
assert mesh
|
||||||
|
|
||||||
|
colors = None
|
||||||
|
if len(mesh.vertex_colors) > 0:
|
||||||
|
colors = mesh.vertex_colors.active.data
|
||||||
|
print('Found vertex colors')
|
||||||
|
|
||||||
|
texcoords = None
|
||||||
|
if len(mesh.uv_layers) > 0:
|
||||||
|
texcoords = mesh.uv_layers.active.data
|
||||||
|
print('Found texture coordinates')
|
||||||
|
|
||||||
|
skeleton = None
|
||||||
|
if 'skeleton' in bpy.data.objects:
|
||||||
|
skeleton = bpy.data.objects['skeleton'].data
|
||||||
|
print('Found skeleton')
|
||||||
|
|
||||||
|
POSITION_MASK = 1
|
||||||
|
NORMAL_MASK = 2
|
||||||
|
COLOR_MASK = 4
|
||||||
|
TEXCOORD_MASK = 8
|
||||||
|
|
||||||
|
vertex_format = POSITION_MASK | NORMAL_MASK
|
||||||
|
if colors:
|
||||||
|
vertex_format |= COLOR_MASK
|
||||||
|
if texcoords:
|
||||||
|
vertex_format |= TEXCOORD_MASK
|
||||||
|
print("Using vertex format", format(vertex_format, '04b'))
|
||||||
|
|
||||||
|
vertex_coords = []
|
||||||
|
vertex_normals = []
|
||||||
|
vertex_colors = []
|
||||||
|
vertex_texcoords = []
|
||||||
|
|
||||||
|
indices = []
|
||||||
|
|
||||||
|
mesh.calc_loop_triangles()
|
||||||
|
|
||||||
|
if flat:
|
||||||
|
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))
|
||||||
|
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))
|
||||||
|
|
||||||
|
if colors:
|
||||||
|
vertex_colors = [None] * len(vertex_coords)
|
||||||
|
if texcoords:
|
||||||
|
vertex_texcoords = [None] * len(vertex_coords)
|
||||||
|
|
||||||
|
for p in mesh.loop_triangles:
|
||||||
|
for li in p.loops:
|
||||||
|
vi = mesh.loops[li].vertex_index
|
||||||
|
indices.append(vi)
|
||||||
|
v = mesh.vertices[vi]
|
||||||
|
if colors:
|
||||||
|
vertex_colors[vi] = tuple(colors[li].color)
|
||||||
|
if texcoords:
|
||||||
|
vertex_texcoords[vi] = tuple(texcoords[li].uv)
|
||||||
|
|
||||||
|
assert (len(indices) % 3) == 0
|
||||||
|
assert len(vertex_coords) == len(vertex_normals)
|
||||||
|
if colors:
|
||||||
|
assert len(vertex_coords) == len(vertex_colors)
|
||||||
|
if texcoords:
|
||||||
|
assert len(vertex_coords) == len(vertex_texcoords)
|
||||||
|
|
||||||
|
if colors:
|
||||||
|
for i in range(len(vertex_colors)):
|
||||||
|
c = 0
|
||||||
|
for k in (3, 2, 1, 0):
|
||||||
|
c = (c << 8) | int(max(0, min(255, vertex_colors[i][k] * 255)))
|
||||||
|
vertex_colors[i] = c
|
||||||
|
|
||||||
|
vertices = []
|
||||||
|
for i in range(len(vertex_coords)):
|
||||||
|
attribs = [vertex_coords[i], vertex_normals[i]]
|
||||||
|
if colors:
|
||||||
|
attribs.append(vertex_colors[i])
|
||||||
|
if texcoords:
|
||||||
|
attribs.append(vertex_texcoords[i])
|
||||||
|
vertices.append(tuple(attribs))
|
||||||
|
|
||||||
|
print(len(vertices), 'vertices')
|
||||||
|
print(len(indices), 'indices')
|
||||||
|
|
||||||
|
if skeleton is not None:
|
||||||
|
bones = []
|
||||||
|
for b in skeleton.data.bones:
|
||||||
|
if b.parent is None:
|
||||||
|
bones.append(-1)
|
||||||
|
else:
|
||||||
|
pi = list(skeleton.data.bones).index(b.parent)
|
||||||
|
bones.append(pi)
|
||||||
|
|
||||||
|
def to_bytes(obj):
|
||||||
|
if type(obj) == int:
|
||||||
|
if obj < 0:
|
||||||
|
return struct.pack('<i', obj)
|
||||||
|
else:
|
||||||
|
return struct.pack('<I', obj)
|
||||||
|
if type(obj) == float:
|
||||||
|
return struct.pack('<f', obj)
|
||||||
|
if type(obj) == tuple:
|
||||||
|
res = bytes()
|
||||||
|
for x in obj:
|
||||||
|
res += to_bytes(x)
|
||||||
|
return res
|
||||||
|
if type(obj) == list:
|
||||||
|
res = to_bytes(len(obj))
|
||||||
|
for x in obj:
|
||||||
|
res += to_bytes(x)
|
||||||
|
return res
|
||||||
|
|
||||||
|
if skeleton is not None:
|
||||||
|
# TODO: support skeletons
|
||||||
|
assert False
|
||||||
|
else:
|
||||||
|
data = to_bytes((vertex_format, vertices, indices))
|
||||||
|
|
||||||
|
filename = sys.argv[sys.argv.index('--') + 1]
|
||||||
|
|
||||||
|
with open(filename, 'wb') as f:
|
||||||
|
f.write(data)
|
||||||
Loading…
Add table
Reference in a new issue