8
$\begingroup$

I'm writing a python script to export triangulated meshes from Blender to an openGL application I am working on. I'm using text files, and I want to export my geometry data in the form of vertices, vertices attributes (normals, uv) and indices as in any openGL application. For the vertices and normals, I am using this code:

myFloat = lambda x: '''{0: 0.4f}'''.format( x )
mesh_file = open(target_path+".map", "w")
    mesh_file.write("\n")
    for vert in mesh.data.vertices:
        mesh_file.write('*VERTEX ')
        for i in (0,1,2):
            mesh_file.write(myFloat(vert.co[i])+' ')
        mesh_file.write("\n")
    for vert in mesh.data.vertices:
        mesh_file.write('*NORMAL ')
        for i in (0,1,2):
            mesh_file.write(myFloat(vert.normal.co[i])+' ')
        mesh_file.write("\n")  

How do I get the indices?

$\endgroup$
  • 1
    $\begingroup$ also read through blender.stackexchange.com/questions/2776/… , will work for your purpose if all faces are tris, else you can think of a way to place a check on the vertex count per face. $\endgroup$ – zeffii Nov 3 '13 at 12:16
3
$\begingroup$

I waited before posting this in case a better answer came up. Since no one posted anything, here is something.

I found the following code on http://davidejones.com. It is definitely not 100% alright so far as OpenGL goes, but it does run so far as Blender is concerned. It may help you get started until someone who knows what they are doing shows up.

The problem I see right away, when I look at the output, is that this code is printing out all of the redundant normals and UV coords but not those of the vertices. Since the stride of the different attributes does not match, you can't make a VBO from this code.

import bpy

obj = bpy.data.objects['Cube']
mesh = obj.data

normals = []
indices = []
for face in mesh.polygons:
    indices.append(face.vertices[0])
    indices.append(face.vertices[1])
    indices.append(face.vertices[2])
    for i in range(len(face.vertices)):
        v = mesh.vertices[face.vertices[i]]
        normals.append([v.normal[0],v.normal[1],v.normal[2]])

verts = []
for vert in mesh.vertices:
    verts.append(vert.co.xyz)

uvs = []
for uv_layer in mesh.uv_layers:
    for x in range(len(uv_layer.data)):
        uvs.append(uv_layer.data[x].uv)

print(indices)
print(verts)
print(uvs)
print(normals)
| improve this answer | |
$\endgroup$
2
$\begingroup$

There is also the following code which I found at a Blender scripting website. http://blenderscripting.blogspot.ca/2011/05/blender-25-python-printing-vertex.html

I ran this script through Blender and the console output looks sensible. The indices match the previous code example.

import bpy  

current_obj = bpy.context.active_object  

print("="*40) # printing marker  
for face in current_obj.data.polygons:  
    verts_in_face = face.vertices[:]  
    print("face index", face.index)  
    print("normal", face.normal)  
    for vert in verts_in_face:  
        print("vert", vert, " vert co", current_obj.data.vertices[vert].co)  
| improve this answer | |
$\endgroup$
1
$\begingroup$

Here is some code that is based on an OpenGL/C object exporter.

if bpy.context.selected_objects: for obj in bpy.context.selected_objects: bpy.context.scene.objects.active = obj bpy.ops.object.mode_set(mode='OBJECT')

    #============================================================
    directoryPath    = "//" + ProjectName + "/_MODEL_FOLDERS_/"
    path = bpy.path.abspath(directoryPath)
    #------------------------------------
    if os.path.exists(path + obj.name) == False:
        os.mkdir(path + obj.name)  
    #============================================================
    #----THE_OPEN_GL_EXPORTER_DOES_IT'S_THING
    #============================================================
    msh = obj.to_mesh(bpy.context.scene,False,'PREVIEW') #-------THE_'False'_IS_THE_APPLY_MODIFIERS_FLAG

    print(obj)
    print(msh)
    print(obj.name)
    print('\n')
    #============================================================
    lvdic = {} # -------------local dictionary
    lfl = [] # ---------------local faces index list
    lvl = [] # ---------------local vertex list
    lnl = [] # ---------------local normal list
    luvl = [] # --------------local uv list
    lvcnt = 0 # --------------local vertices count
    isSmooth = False
    hasUV = True    # true by default, it will be verified below

    print("Building for: %s\n"%obj.name)
    #============================================================ 
    if (len(msh.tessface_uv_textures) > 0):
        if (msh.tessface_uv_textures.active is None):
            hasUV=False
    else:
        hasUV = False
    #-------------------
    if (hasUV):
        activeUV = msh.tessface_uv_textures.active.data
    #============================================================ 
    obj_names.append(clearName(obj.name))
    obj_cnt+=1 
    print('objectCount =', obj_cnt)
    print('\n')
    #============================================================ 
    for i,f in enumerate(msh.tessfaces):
        isSmooth = f.use_smooth
        tmpfaces = []
        for j,v in enumerate(f.vertices):  
            vec = msh.vertices[v].co
            vec = r3d(vec)

            if (isSmooth):  # use vertex normal
                nor = msh.vertices[v].normal
            else:           # use face normal
                nor = f.normal

            nor = r3d(nor)

            if (hasUV):
                co = activeUV[i].uv[j]
                co = r2d(co)
            else:
                co = (0.0, 0.0)

            key = vec, nor, co
            vinx = lvdic.get(key)

            if (vinx is None): # vertex not found
                lvdic[key] = lvcnt
                lvl.append(vec)
                lnl.append(nor)
                luvl.append(co)
                tmpfaces.append(lvcnt)
                lvcnt+=1
            else:
                inx = lvdic[key]
                tmpfaces.append(inx)

        if (len(tmpfaces)==3): 
            lfl.append(tmpfaces)
        else:
            lfl.append([tmpfaces[0], tmpfaces[1], tmpfaces[2]])
            lfl.append([tmpfaces[0], tmpfaces[2], tmpfaces[3]])


    bpy.data.meshes.remove(msh)
    #===============================================================    
    #update global lists and dictionaries
    vtx.append(lvdic)
    faces.append(lfl)
    vl.append(lvl)
    nl.append(lnl)
    uvl.append(luvl)
    obj_mtx.append(obj.matrix_local)

    #===============================================================
    #============---WRITE_INDICES========
    #===============================================================      
    numberOfFaces = len(lfl)
    numberOfIndices = numberOfFaces * 3
    #-----------------------------------
    filename = obj.name + '_INDICES' + '.cpp'
    file = open(path + obj.name + '/' + filename, "w", newline="\n")
    #--------------------
    file.write("GLuint ")
    file.write(obj.name)
    file.write("_INDICES[] = \n{\n")
    file.write("    //numberOfIndices = %d\n" %numberOfIndices)
    file.write("\n")
    #-------------------------------------------------------------------
    for faceCount in range(numberOfFaces):#---------print the index list
        file.write("%d" %lfl[faceCount][0])
        file.write(", ")
        file.write("%d" %lfl[faceCount][1])
        file.write(", ")
        file.write("%d" %lfl[faceCount][2])
        file.write(", ")
        file.write("\n")
    #---------------------------------------
    file.write("}; \n")
    file.close()
    #=========================================================================
    #============---WRITE_VERTICES========
    #=========================================================================
    numberOfVerts    = len(lvl)
    print(numberOfVerts)
    numberOfVertices = numberOfVerts
    #-----------------------------------
    filename = obj.name + '.cpp'
    file = open(path  + obj.name + '/' + filename, "w", newline="\n")
    #---------------------
    file.write("GLfloat ")
    file.write(obj.name)
    file.write("[] = \n{\n")
    file.write("    //numberOfVertices = %d\n" %numberOfVertices)
    file.write("\n")
    #-------------------------------------------------------------------
    for vertCount in range(numberOfVertices):#---------print the vertex list
        file.write("\t%f " %lvl[vertCount][0])
        file.write(", ")
        file.write("\t%f " %lvl[vertCount][1])
        file.write(", ")
        file.write("\t%f " %lvl[vertCount][2])
        file.write(", ")
        file.write("\t%f " %lnl[vertCount][0])
        file.write(", ")
        file.write("\t%f " %lnl[vertCount][1])
        file.write(", ")
        file.write("\t%f " %lnl[vertCount][2])
        file.write(", ")
        file.write("\t%f " %luvl[vertCount][0])
        file.write(", ")
        file.write("\t%f " %luvl[vertCount][1])
        file.write(", ")
        file.write("\n")

    #--------------------------------------
    file.write("}; \n")  
    file.close()

The functional component is exactly the same except that I've added a function call that deletes the created data after it's used so the mesh data blocks don't fill up with nuisance data... the output has been reformatted to suit my needs so you are likely going to want to do the same since this tends to be specific to the final OpenGL render code setup.

The original code can be found at the following site and may be located using the following keywords.

http://ksolek.fm.interia.pl/Blender/

Keywords: Blender OpenGL / C header exporter Krzysztof So�ek Bruce Merry Campbell Barton Stanford PLY

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.