Defcronyke
Defcronyke

Reputation: 621

Blender 2.6 JSON exporter, texture coordinates trouble

I'm trying to write a simple JSON exporter for Blender 2.6x because the only one I could find ( http://code.google.com/p/blender-machete/ ) doesn't work with 2.6. I didn't have any trouble getting the vertices, normals, and indices from blender, but try as I might, I just can't seem to figure out why the texture coordinates are coming out wrong. The textures seem tilted diagonally across the face of a simple cube, and stretched... really ugly and wrong. I've been looking online and through the source for some of the official exporters, but I still can't figure it out, so I was hoping someone could give me some hints or solutions.

The piece of code I'm using to access the texture coordinates is this:

    # add texture coordinates to scene_data structure
    m = bpy.context.active_object.to_mesh(bpy.context.scene, True, 'PREVIEW')
    for j in range(len(m.tessfaces)):
        if len(m.tessface_uv_textures) > 0:
            scene_data[mesh_number]["tex_coords"].append( m.tessface_uv_textures.active.data[j].uv1.x )
            scene_data[mesh_number]["tex_coords"].append( m.tessface_uv_textures.active.data[j].uv1.y )
            scene_data[mesh_number]["tex_coords"].append( m.tessface_uv_textures.active.data[j].uv2.x )
            scene_data[mesh_number]["tex_coords"].append( m.tessface_uv_textures.active.data[j].uv2.y )
            scene_data[mesh_number]["tex_coords"].append( m.tessface_uv_textures.active.data[j].uv3.x )
            scene_data[mesh_number]["tex_coords"].append( m.tessface_uv_textures.active.data[j].uv3.y )

This is giving me a list of texture coordinates, but somehow I'm doing it wrong, because of the incorrect appearance of the texture as I explained above.

I don't know what else to do but show the code, since I've tried changing it around in every way I can think of, so here's the function where the above snippet of code is:

def get_json(objects, scene):
    """ Currently only supports one scene. 
        Exports with -Z forward, Y up. """

    scene_data = []
    mesh_number = -1

    # iterate over each mesh
    for i in range(len(bpy.data.objects)):
        if bpy.data.objects[i].type == 'MESH':

            mesh_number += 1

            bpy.ops.object.mode_set(mode='OBJECT')

            # convert all the mesh's faces to triangles
            bpy.data.objects[i].select = True
            bpy.context.scene.objects.active = bpy.data.objects[i]

            bpy.ops.object.mode_set(mode='EDIT')

            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.mesh.quads_convert_to_tris()
            bpy.context.scene.update()

            bpy.ops.object.mode_set(mode='OBJECT')

            bpy.data.objects[i].select = False

            # add data to scene_data structure
            scene_data.append({
                "name"          : bpy.data.objects[i].name,
                "vertices"      : [],
                "indices"       : [],
                "normals"       : [],
                "tex_coords"    : []
            })

            # iterate over all the vertices in the mesh
            for j in range(len(bpy.data.objects[i].data.vertices)):
                # add vertex to scene_data structure
                scene_data[mesh_number]["vertices"].append( bpy.data.objects[i].data.vertices[j].co.x + bpy.data.objects[i].location.x )
                scene_data[mesh_number]["vertices"].append( bpy.data.objects[i].data.vertices[j].co.z + bpy.data.objects[i].location.z )
                scene_data[mesh_number]["vertices"].append( -(bpy.data.objects[i].data.vertices[j].co.y + bpy.data.objects[i].location.y) )

                # add vertex normal to scene_data structure
                scene_data[mesh_number]["normals"].append( bpy.data.objects[i].data.vertices[j].normal.x )
                scene_data[mesh_number]["normals"].append( bpy.data.objects[i].data.vertices[j].normal.z )
                scene_data[mesh_number]["normals"].append( -(bpy.data.objects[i].data.vertices[j].normal.y) )

            # iterate over each face in the mesh
            for j in range(len(bpy.data.objects[i].data.polygons)):
                verts_in_face = bpy.data.objects[i].data.polygons[j].vertices[:]

                # iterate over each vertex in the face
                for k in range(len(verts_in_face)):

                    # twiddle index for -Z forward, Y up
                    index = k
                    if index == 1: index = 2
                    elif index == 2: index = 1

                    # twiddle index so we draw triangles counter-clockwise
                    if index == 0:  index = 2
                    elif index == 2: index = 0

                    # add index to scene_data structure
                    scene_data[mesh_number]["indices"].append( verts_in_face[index] )

            # add texture coordinates to scene_data structure
            m = bpy.context.active_object.to_mesh(bpy.context.scene, True, 'PREVIEW')
            for j in range(len(m.tessfaces)):
                if len(m.tessface_uv_textures) > 0:
                    scene_data[mesh_number]["tex_coords"].append( m.tessface_uv_textures.active.data[j].uv1.x )
                    scene_data[mesh_number]["tex_coords"].append( m.tessface_uv_textures.active.data[j].uv1.y )
                    scene_data[mesh_number]["tex_coords"].append( m.tessface_uv_textures.active.data[j].uv2.x )
                    scene_data[mesh_number]["tex_coords"].append( m.tessface_uv_textures.active.data[j].uv2.y )
                    scene_data[mesh_number]["tex_coords"].append( m.tessface_uv_textures.active.data[j].uv3.x )
                    scene_data[mesh_number]["tex_coords"].append( m.tessface_uv_textures.active.data[j].uv3.y )

    return json.dumps(scene_data, indent=4)

Will someone please tell me what I'm doing wrong? I've been at this for a few days now with no progress.

Upvotes: 0

Views: 1393

Answers (1)

Defcronyke
Defcronyke

Reputation: 621

Upon further research, I think I might know the problem, but I'm not sure about this...

From here: http://www.gamedev.net/topic/602169-opengl-drawing-cube-using-gldrawelements-and-gltexcoordpointer/page_p_4811454#entry4811454

This is a classical example of when you cannot use shared vertices. As soon as you introduce a vertex attribute other than position, the cube is required to have 24 vertices, not 8. The corners of a cube are not shared vertices, because they don't have the same texture coordinates.

For example, the first two triangles are made up of the indices [0, 1, 2, 0, 2, 3], and if you reference the vertex and texture coordinate arrays, that face is fine. The second two triangles are made up of the indices [0, 4, 5, 0, 5, 1], and while the vertex array is referenced correct to make second face of the cube, the resulting texture coordinates are entirely broken.

Am I right about this being my problem, or am I way off?

Edit: Almost got textures working by using more vertex positions. Now the only problem is that one face of a simple cube will be warped and diagonal to its correct position. All other faces are looking good.

Here's the function that's almost working:

def get_json(objects, scene):
    """ Currently only supports one scene. 
        Exports with -Z forward, Y up. """

    object_number = -1
    scene_data = []

    # for every object in the scene
    for object in bpy.context.scene.objects:

        # if the object is a mesh       
        if object.type == 'MESH':

            object_number += 1

            # convert all the mesh's faces to triangles
            bpy.ops.object.mode_set(mode='OBJECT')
            object.select = True
            bpy.context.scene.objects.active = object

            # triangulate using new Blender 2.65 Triangulate modifier
            bpy.ops.object.modifier_add(type='TRIANGULATE')
            object.modifiers["Triangulate"].use_beauty = False
            bpy.ops.object.modifier_apply(apply_as="DATA", modifier="Triangulate")

            bpy.ops.object.mode_set(mode='OBJECT')

            object.select = False

            # add data to scene_data structure
            scene_data.append({
                "name"          : object.name,
                "vertices"      : [],
                "indices"       : [],
                "normals"       : [],
                "tex_coords"    : []
            })

            vertex_number = -1

            # for each face in the object
            for face in object.data.polygons:
                vertices_in_face = face.vertices[:]

                # for each vertex in the face
                for vertex in vertices_in_face:

                    vertex_number += 1

                    # store vertices in scene_data structure
                    scene_data[object_number]["vertices"].append( object.data.vertices[vertex].co.x + object.location.x )
                    scene_data[object_number]["vertices"].append( object.data.vertices[vertex].co.z + object.location.z )
                    scene_data[object_number]["vertices"].append( -(object.data.vertices[vertex].co.y + object.location.y) )

                    # store normals in scene_data structure
                    scene_data[object_number]["normals"].append( object.data.vertices[vertex].normal.x )
                    scene_data[object_number]["normals"].append( object.data.vertices[vertex].normal.z )
                    scene_data[object_number]["normals"].append( -(object.data.vertices[vertex].normal.y) )

                    # store indices in scene_data structure
                    scene_data[object_number]["indices"].append(vertex_number)

            # texture coordinates
            #   bug: for a simple cube, one face's texture is warped
            mesh = object.to_mesh(bpy.context.scene, True, 'PREVIEW')
            if len(mesh.tessface_uv_textures) > 0:
                for data in mesh.tessface_uv_textures.active.data:
                    scene_data[object_number]["tex_coords"].append( data.uv1.x )
                    scene_data[object_number]["tex_coords"].append( data.uv1.y )
                    scene_data[object_number]["tex_coords"].append( data.uv2.x )
                    scene_data[object_number]["tex_coords"].append( data.uv2.y )
                    scene_data[object_number]["tex_coords"].append( data.uv3.x )
                    scene_data[object_number]["tex_coords"].append( data.uv3.y )

    return json.dumps(scene_data, indent=4)

I'm wondering what could be the cause of only one face's texture being warped? I'm almost there, but can't seem to figure this one out.

Upvotes: 0

Related Questions