Skip to content

Instantly share code, notes, and snippets.

@VirtuosoChris
Created April 23, 2019 20:31
Show Gist options
  • Save VirtuosoChris/1e77c283946b153c73716c5eb094b655 to your computer and use it in GitHub Desktop.
Save VirtuosoChris/1e77c283946b153c73716c5eb094b655 to your computer and use it in GitHub Desktop.
convert 3d model to header using assimp
#####
##### By Christopher Pugh
##### Copyright 2015 Virtuoso Engine, LLC
##### Public domain or equivalent license
#####
##### Basic asset to header script
##### Pulls vertices, normals, single texture coord channel
##### Triangulates meshes, pulls multiple meshes, puts everything in arrays in a namespace
##### first argument is input mesh file
##### Second optional argument is namespace name
##### Powered by Assimp Python API
##### Uses {NAMESPACE}_DEFINITIONS guard like an STB library to switch the header between declarations and definitions only
#todo variable naming breaks if there's more than one mesh
#todo use argparse like env tool to add flags like capping bone counts, etc
from pyassimp import *
import sys
def processNodes(node, nodes):
print (node.name)
nodes[node.name] = [node, False]
for n in node.children:
processNodes(n, nodes)
aiPrimitiveType_POINT = 1
aiPrimitiveType_LINE = 2
aiPrimitiveType_TRIANGLE = 4
aiPrimitiveType_POLYGON = 8
primNames = {}
primNames[aiPrimitiveType_POLYGON] = "polygon"
primNames[aiPrimitiveType_LINE] = "line"
primNames[aiPrimitiveType_TRIANGLE] = "triangle"
primNames[aiPrimitiveType_POINT] = "point"
print ('Number of arguments:', len(sys.argv), 'arguments.')
print ('Argument List:', str(sys.argv), "\n")
if len(sys.argv) < 2:
print ("Improper usage : Too few arguments")
exit()
print ("Loading asset " + sys.argv[1])
if len(sys.argv) >= 3 :
namespace = sys.argv[2]
else:
print "Using default file name and namespace \'mesh\'"
namespace = "mesh"
flags = postprocess.aiProcess_ImproveCacheLocality
flags |= postprocess.aiProcess_JoinIdenticalVertices
flags |= postprocess.aiProcess_Triangulate
flags |= postprocess.aiProcess_RemoveRedundantMaterials
flags |= postprocess.aiProcess_SortByPType
flags |= postprocess.aiProcess_OptimizeMeshes
flags |= postprocess.aiProcess_OptimizeGraph
#flags = postprocess.aiProcess_PreTransformVertices
flags |= postprocess.aiProcess_LimitBoneWeights
scene = load(sys.argv[1], processing=flags)
print ("Number of meshes " + str(len(scene.meshes)))
print ("Number of animations " + str(len(scene.animations)))
print ("Number of lights " + str(len(scene.lights)))
print ("Number of textures " + str(len(scene.textures)))
print ("Number of materials " + str(len(scene.materials)))
print ("Number of cameras " + str(len(scene.cameras)))
print ("\nEnumerating Meshes")
mergeIndices = True
#print animations
nodes = {}
processNodes(scene.rootnode, nodes)
namespaceMod = namespace.upper()
namespaceMod.replace(" ", "_")
headerGuardDefine = namespaceMod + "_H_INCLUDED"
f = open(namespace + '.h', 'w')
f.write ("\nnamespace " + namespace + "\n{\n")
namespaceDefinitions = namespaceMod + '_DEFINITIONS'
f.write ('\n#ifndef ' + namespaceDefinitions + '\n\n')
f.write ("\n\nextern const unsigned int " + namespaceMod + "_NUM_MESHES;\n\n")
f.write("#ifndef _" + headerGuardDefine + "\n#define _" + headerGuardDefine + "\n")
for i,m in enumerate(scene.meshes) :
f.write('extern int indices' + str(i) + '[];\n')
f.write('extern float vertices' + str(i) + '[];\n')
f.write('extern float normals' + str(i) + '[];\n')
f.write('extern float texcoords' + str(i) + '[];\n\n')
arrtype = ["int", "float", "float", "float"];
arrvar = ["indices", "vertices", "texcoords", "normals"];
namespacevar = namespace.replace(" ", "_")
for x in range(0, len(arrtype)) :
f.write ('extern ' + arrtype[x] + "* " + namespacevar + "_" + arrvar[x] + "[" + str(len(scene.meshes)) + '];\n')
f.write("\n#endif // " + headerGuardDefine)
f.write('\n\n#else\n\n')
f.write ("\n\nconst unsigned int " + namespaceMod + "_NUM_MESHES = " + str(len(scene.meshes)) + ';\n\n')
idxOffset = 0
for i,m in enumerate(scene.meshes) :
print ("\nmesh %d" % (i))
print ("\tfaces %d " % len(m.faces))
print ("\tvertices %d "%len(m.vertices))
print ("\ttexcoord channels %d "%len(m.texturecoords))
print ("Primitive type : " + primNames[m.primitivetypes])
if m.primitivetypes != aiPrimitiveType_TRIANGLE:
print ("Error: Non-triangle meshes not supported")
exit()
#write indices
f.write('int indices' + str(i) + '[] = {')
for fac in m.faces:
for fc in fac:
fc2 = fc
if mergeIndices:
fc2 = fc + idxOffset
f.write("%d, "%fc2)
#f.write(%d)
f.write('};')
#write vertices
f.write("\n\nfloat vertices" + str(i) + "[] = {")
for vert in m.vertices:
for c in vert:
f.write("%f, "%c )
f.write("};")
#write tex coords
f.write("\n\nfloat texcoords" + str(i) + "[] ={")
for uv in m.texturecoords[0]:
f.write(str(uv[0]) + ", " + str(uv[1]) + ", ")
f.write("};")
#write normals
f.write("\n\nfloat normals" + str(i) + "[] ={")
for n in m.normals:
for z in n :
f.write(str(z) + ", ")
f.write("};\n\n\n")
idxOffset += len(m.vertices)
#arrtype = ["int", "float", "float", "float"];
#arrvar = ["indices", "vertices", "texcoords", "normals"];
#namespacevar = namespace.replace(" ", "_")
for x in range(0, len(arrtype)) :
f.write (arrtype[x] + "* " + namespacevar + "_" + arrvar[x] + "[" + str(len(scene.meshes)) + '] = {')
for i,m in enumerate(scene.meshes) :
f.write(arrvar[x] + str(i) + ',')
f.write ('};\n\n')
f.write("\n\n#endif //" + namespaceDefinitions)
f.write ("\n} // namespace " + namespace)
release (scene)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment