Hello! I’m using Blender 2.7a and have been working on getting a custom exporter to work. Geometry and material information is exporting ok for me, but texture coordinates are coming out wrong despite me following the obj exporter pattern for the data access (as best as i can tell anyways). Script below… does anyone see what I’m doing wrong?
Thank you so much for any help you can give, I’ve been banging my head on this for several days now with no luck!
bl_info = {
"name": "ProjectX Exporters",
"author": "Alan Wolfe",
"blender": (2,7,0),
"version": (0,0,1),
"location": "File > Import-Export",
"description": "Export custom data formats for ProjectX",
"category": "Import-Export"
}
import bpy
from bpy_extras.io_utils import ExportHelper
import bpy_extras.io_utils
import os
from mathutils import Matrix, Vector
# flip Y and Z axis, since blender has +Z as up, and we have +Y as up
GLOBAL_EXPORT_MATRIX = Matrix([[1, 0, 0, 0],[0, 0, 1, 0],[0, 1, 0, 0],[0, 0, 0, 1]])
def mesh_triangulate(me):
import bmesh
bm = bmesh.new()
bm.from_mesh(me)
bmesh.ops.triangulate(bm, faces=bm.faces)
bm.to_mesh(me)
bm.free()
class ExportModel(bpy.types.Operator, ExportHelper):
bl_idname = "model.xmd";
bl_label = "Save";
bl_options = {'PRESET'};
filename_ext = ".xmd";
def execute(self, context):
out = open(self.filepath, "w");
out.write('<?xml version="1.0" encoding="utf-8"?>
<model>
')
for obj in bpy.data.objects:
try:
data = obj.to_mesh(bpy.context.scene, True, 'PREVIEW')
except RuntimeError:
data = None
if data is None:
continue
data.transform(obj.matrix_world * GLOBAL_EXPORT_MATRIX)
mesh_triangulate(data)
data.calc_tessface();
data.calc_tangents();
out.write(' <object>
')
source_dir = os.path.dirname(bpy.data.filepath)
dest_dir = os.path.dirname(bpy.data.filepath)
if len(data.materials) == 0:
out.write(' <material/>
')
# write materials for this object
for mat_num, mat in enumerate(data.materials):
out.write(' <material>
')
# todo: EmissiveColor
# todo: ReflectionAmount
# todo: Absorbance
out.write(' <DiffuseColor Value="%f,%f,%f"/>
' % (mat.diffuse_intensity * mat.diffuse_color)[:])
# write images
image_map = {}
# backwards so topmost are highest priority
for mtex in reversed(mat.texture_slots):
if mtex and mtex.texture and mtex.texture.type == 'IMAGE':
image = mtex.texture.image
if image:
# texface overrides others
if (mtex.use_map_color_diffuse and
(mtex.use_map_warp is False) and
(mtex.texture_coords != 'REFLECTION')):
image_map["DiffuseTexture"] = image
if mtex.use_map_ambient:
image_map["AmbientTexture_Unused"] = image
# this is the Spec intensity channel but Ks stands for specular Color
'''
if mtex.use_map_specular:
image_map["SpecularTexture_Unused"] = image
'''
if mtex.use_map_color_spec: # specular color
image_map["SpecularTexture_Unused"] = image
if mtex.use_map_hardness: # specular hardness/glossiness
image_map["HardnessTexture_Unused"] = image
if mtex.use_map_alpha:
image_map["AlphaTexture_Unused"] = image
if mtex.use_map_translucency:
image_map["TranslucencyTexture_Unused"] = image
if mtex.use_map_normal and (mtex.texture.use_normal_map is True):
image_map["BumpTexture_Unused"] = image
if mtex.use_map_normal and (mtex.texture.use_normal_map is False):
image_map["NormalTexture"] = image
if mtex.use_map_color_diffuse and (mtex.texture_coords == 'REFLECTION'):
image_map["ReflectionTexture_Unused"] = image
if mtex.use_map_emit:
image_map["EmissiveTexture"] = image
for key, image in image_map.items():
out.write(' <%s Value="%s"/>
' % (key, repr(image.filepath)[1:-1]))
out.write(' <SpecularColor Value="%f,%f,%f"/>
' % (mat.specular_intensity * mat.specular_color)[:])
# convert from blenders spec to 0 - 1000 range.
if mat.specular_shader == 'WARDISO':
tspec = (0.4 - mat.specular_slope) / 0.0004
else:
tspec = (mat.specular_hardness - 1) * 1.9607843137254901
out.write(' <SpecularPower Value="%f"/>
' % tspec)
if hasattr(mat, "ior"):
out.write(' <RefractionIndex Value="%f"/>
' % mat.ior)
out.write(' <RefractionAmount Value="%f"/>
' % (1.0 - mat.alpha))
out.write(' </material>
')
# write polygons
for face_num, face in enumerate(data.polygons):
out.write(' <face>
')
for loopIndex in (face.loop_indices):
vert = data.vertices[data.loops[loopIndex].vertex_index];
out.write(' <vert>
');
out.write(' <pos Value="%f,%f,%f"/>
' % (vert.co[:]));
out.write(' <normal Value="%f,%f,%f"/>
' % (data.loops[loopIndex].normal[:]));
out.write(' <tangent Value="%f,%f,%f"/>
' % (data.loops[loopIndex].tangent[:]));
out.write(' <bitangent Value="%f,%f,%f"/>
' % (data.loops[loopIndex].bitangent[:]));
if data.uv_layers.active != None:
out.write(' <uv Value="%f,%f"/>
' % (data.uv_layers.active.data[loopIndex].uv[:]));
out.write(' </vert>
');
out.write(' </face>
')
out.write(' </object>
')
bpy.data.meshes.remove(data)
out.write('</model>
')
out.close();
return {'FINISHED'};
def model_menu_func(self, context):
self.layout.operator(ExportModel.bl_idname, text="ProjectX Model(.xmd)");
def register():
bpy.utils.register_module(__name__);
bpy.types.INFO_MT_file_export.append(model_menu_func);
def unregister():
bpy.utils.unregister_module(__name__);
bpy.types.INFO_MT_file_export.remove(model_menu_func);
if __name__ == "__main__":
register()