finished moving importers and exporters into python packages (as proposed on the mailing list).
- made operator dir's into python packages - lazy loading of module which do the actual import and export (faster blender load times) - general maintanance and small fixes. - bugfix for exporting x3d materials - leak fix for exporting 3ds
This commit is contained in:
@@ -19,9 +19,7 @@
|
||||
# This directory is a Python package.
|
||||
|
||||
# To support reload properly, try to access a package var, if it's there, reload everything
|
||||
try:
|
||||
init_data
|
||||
|
||||
if "bpy" in locals():
|
||||
reload(model)
|
||||
reload(operators)
|
||||
reload(client)
|
||||
@@ -32,7 +30,7 @@ try:
|
||||
reload(balancing)
|
||||
reload(ui)
|
||||
reload(repath)
|
||||
except:
|
||||
else:
|
||||
from netrender import model
|
||||
from netrender import operators
|
||||
from netrender import client
|
||||
@@ -49,7 +47,6 @@ slaves = []
|
||||
blacklist = []
|
||||
|
||||
init_file = ""
|
||||
init_data = True
|
||||
init_address = True
|
||||
|
||||
def register():
|
||||
|
||||
@@ -42,6 +42,23 @@ class ImportHelper:
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
|
||||
# limited replacement for BPyImage.comprehensiveImageLoad
|
||||
def load_image(imagepath, dirname):
|
||||
|
||||
if os.path.exists(imagepath):
|
||||
return bpy.data.images.load(imagepath)
|
||||
|
||||
variants = [imagepath, os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))]
|
||||
|
||||
for filepath in variants:
|
||||
for nfilepath in (filepath, bpy.path.resolve_ncase(filepath)):
|
||||
if os.path.exists(nfilepath):
|
||||
return bpy.data.images.load(nfilepath)
|
||||
|
||||
# TODO comprehensiveImageLoad also searched in bpy.config.textureDir
|
||||
return None
|
||||
|
||||
|
||||
# return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects()
|
||||
def create_derived_objects(scene, ob):
|
||||
if ob.parent and ob.parent.dupli_type != 'NONE':
|
||||
@@ -54,42 +71,16 @@ def create_derived_objects(scene, ob):
|
||||
return False, [(ob, ob.matrix_world)]
|
||||
|
||||
|
||||
|
||||
def free_derived_objects(ob):
|
||||
ob.free_dupli_list()
|
||||
|
||||
|
||||
# So 3ds max can open files, limit names to 12 in length
|
||||
# this is verry annoying for filenames!
|
||||
name_unique = []
|
||||
name_mapping = {}
|
||||
def sane_name(name):
|
||||
name_fixed = name_mapping.get(name)
|
||||
if name_fixed != None:
|
||||
return name_fixed
|
||||
|
||||
if len(name) > 12:
|
||||
new_name = name[:12]
|
||||
else:
|
||||
new_name = name
|
||||
|
||||
i = 0
|
||||
|
||||
while new_name in name_unique:
|
||||
new_name = new_name[:-4] + '.%.3d' % i
|
||||
i+=1
|
||||
|
||||
name_unique.append(new_name)
|
||||
name_mapping[name] = new_name
|
||||
return new_name
|
||||
|
||||
|
||||
def unpack_list(list_of_tuples):
|
||||
flat_list = []
|
||||
flat_list_extend = flat_list.extend # a tich faster
|
||||
for t in list_of_tuples:
|
||||
flat_list_extend(t)
|
||||
return l
|
||||
return flat_list
|
||||
|
||||
# same as above except that it adds 0 for triangle faces
|
||||
def unpack_face_list(list_of_tuples):
|
||||
|
||||
74
release/scripts/op/io_anim_bvh/__init__.py
Normal file
74
release/scripts/op/io_anim_bvh/__init__.py
Normal file
@@ -0,0 +1,74 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
# To support reload properly, try to access a package var, if it's there, reload everything
|
||||
if "bpy" in locals():
|
||||
# only reload if we alredy loaded, highly annoying
|
||||
import sys
|
||||
reload(sys.modules.get("io_mesh_ply.export_ply", sys))
|
||||
|
||||
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
from io_utils import ImportHelper
|
||||
|
||||
|
||||
class BvhImporter(bpy.types.Operator, ImportHelper):
|
||||
'''Load a OBJ Motion Capture File'''
|
||||
bl_idname = "import_anim.bvh"
|
||||
bl_label = "Import BVH"
|
||||
|
||||
filename_ext = ".bvh"
|
||||
|
||||
scale = FloatProperty(name="Scale", description="Scale the BVH by this value", min=0.0001, max=1000000.0, soft_min=0.001, soft_max=100.0, default=0.1)
|
||||
frame_start = IntProperty(name="Start Frame", description="Starting frame for the animation", default=1)
|
||||
loop = BoolProperty(name="Loop", description="Loop the animation playback", default=False)
|
||||
rotate_mode = EnumProperty(items=(
|
||||
('QUATERNION', "Quaternion", "Convert rotations to quaternions"),
|
||||
('NATIVE', "Euler (Native)", "Use the rotation order defined in the BVH file"),
|
||||
('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
|
||||
('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
|
||||
('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
|
||||
('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
|
||||
('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
|
||||
('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
|
||||
),
|
||||
name="Rotation",
|
||||
description="Rotation conversion.",
|
||||
default='NATIVE')
|
||||
|
||||
def execute(self, context):
|
||||
import io_anim_bvh.import_bvh
|
||||
return io_anim_bvh.import_bvh.load(self, context, **self.properties)
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(BvhImporter.bl_idname, text="Motion Capture (.bvh)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_import.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_import.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
@@ -555,67 +555,24 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
|
||||
return arm_ob
|
||||
|
||||
|
||||
from bpy.props import *
|
||||
from io_utils import ImportHelper
|
||||
def load(operator, context, filepath="", rotate_mode='NATIVE', scale=1.0, use_cyclic=False, frame_start=1):
|
||||
import time
|
||||
t1 = time.time()
|
||||
print('\tparsing bvh %r...' % filepath, end="")
|
||||
|
||||
bvh_nodes = read_bvh(context, filepath,
|
||||
ROT_MODE=rotate_mode,
|
||||
GLOBAL_SCALE=scale)
|
||||
|
||||
class BvhImporter(bpy.types.Operator, ImportHelper):
|
||||
'''Load a OBJ Motion Capture File'''
|
||||
bl_idname = "import_anim.bvh"
|
||||
bl_label = "Import BVH"
|
||||
print('%.4f' % (time.time() - t1))
|
||||
t1 = time.time()
|
||||
print('\timporting to blender...', end="")
|
||||
|
||||
bvh_node_dict2armature(context, bvh_nodes,
|
||||
ROT_MODE=rotate_mode,
|
||||
IMPORT_START_FRAME=frame_start,
|
||||
IMPORT_LOOP=use_cyclic)
|
||||
|
||||
print('Done in %.4f\n' % (time.time() - t1))
|
||||
|
||||
filename_ext = ".bvh"
|
||||
|
||||
scale = FloatProperty(name="Scale", description="Scale the BVH by this value", min=0.0001, max=1000000.0, soft_min=0.001, soft_max=100.0, default=0.1)
|
||||
frame_start = IntProperty(name="Start Frame", description="Starting frame for the animation", default=1)
|
||||
loop = BoolProperty(name="Loop", description="Loop the animation playback", default=False)
|
||||
rotate_mode = EnumProperty(items=(
|
||||
('QUATERNION', "Quaternion", "Convert rotations to quaternions"),
|
||||
('NATIVE', "Euler (Native)", "Use the rotation order defined in the BVH file"),
|
||||
('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
|
||||
('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
|
||||
('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
|
||||
('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
|
||||
('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
|
||||
('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
|
||||
),
|
||||
name="Rotation",
|
||||
description="Rotation conversion.",
|
||||
default='NATIVE')
|
||||
|
||||
def execute(self, context):
|
||||
# print("Selected: " + context.active_object.name)
|
||||
import time
|
||||
t1 = time.time()
|
||||
print('\tparsing bvh...', end="")
|
||||
|
||||
bvh_nodes = read_bvh(context, self.properties.filepath,
|
||||
ROT_MODE=self.properties.rotate_mode,
|
||||
GLOBAL_SCALE=self.properties.scale)
|
||||
|
||||
print('%.4f' % (time.time() - t1))
|
||||
t1 = time.time()
|
||||
print('\timporting to blender...', end="")
|
||||
|
||||
bvh_node_dict2armature(context, bvh_nodes,
|
||||
ROT_MODE=self.properties.rotate_mode,
|
||||
IMPORT_START_FRAME=self.properties.frame_start,
|
||||
IMPORT_LOOP=self.properties.loop)
|
||||
|
||||
print('Done in %.4f\n' % (time.time() - t1))
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(BvhImporter.bl_idname, text="Motion Capture (.bvh)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_import.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_import.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
return {'FINISHED'}
|
||||
|
||||
76
release/scripts/op/io_mesh_ply/__init__.py
Normal file
76
release/scripts/op/io_mesh_ply/__init__.py
Normal file
@@ -0,0 +1,76 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# To support reload properly, try to access a package var, if it's there, reload everything
|
||||
if "bpy" in locals():
|
||||
import sys
|
||||
reload(sys.modules.get("io_mesh_ply.export_ply", sys))
|
||||
|
||||
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
from io_utils import ExportHelper
|
||||
|
||||
|
||||
class ExportPLY(bpy.types.Operator, ExportHelper):
|
||||
'''Export a single object as a stanford PLY with normals, colours and texture coordinates.'''
|
||||
bl_idname = "export.ply"
|
||||
bl_label = "Export PLY"
|
||||
|
||||
filename_ext = ".ply"
|
||||
|
||||
use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default=True)
|
||||
use_normals = BoolProperty(name="Normals", description="Export Normals for smooth and hard shaded faces", default=True)
|
||||
use_uv_coords = BoolProperty(name="UVs", description="Exort the active UV layer", default=True)
|
||||
use_colors = BoolProperty(name="Vertex Colors", description="Exort the active vertex color layer", default=True)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.active_object != None
|
||||
|
||||
def execute(self, context):
|
||||
filepath = self.properties.filepath
|
||||
filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
|
||||
import io_mesh_ply.export_ply
|
||||
return io_mesh_ply.export_ply.save(self, context, **self.properties)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
props = self.properties
|
||||
|
||||
row = layout.row()
|
||||
row.prop(props, "use_modifiers")
|
||||
row.prop(props, "use_normals")
|
||||
row = layout.row()
|
||||
row.prop(props, "use_uv_coords")
|
||||
row.prop(props, "use_colors")
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_export.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_export.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
@@ -21,79 +21,64 @@
|
||||
# Copyright (C) 2004, 2005: Bruce Merry, bmerry@cs.uct.ac.za
|
||||
# Contributors: Bruce Merry, Campbell Barton
|
||||
|
||||
import bpy
|
||||
|
||||
"""
|
||||
This script exports Stanford PLY files from Blender. It supports normals,
|
||||
colours, and texture coordinates per face or per vertex.
|
||||
Only one mesh can be exported at a time.
|
||||
"""
|
||||
|
||||
def rvec3d(v):
|
||||
return round(v[0], 6), round(v[1], 6), round(v[2], 6)
|
||||
import bpy
|
||||
import os
|
||||
|
||||
|
||||
def rvec2d(v):
|
||||
return round(v[0], 6), round(v[1], 6)
|
||||
def save(operator, context, filepath="", use_modifiers=True, use_normals=True, use_uv_coords=True, use_colors=True):
|
||||
|
||||
def rvec3d(v):
|
||||
return round(v[0], 6), round(v[1], 6), round(v[2], 6)
|
||||
|
||||
|
||||
def write(filename, scene, ob, \
|
||||
EXPORT_APPLY_MODIFIERS=True,\
|
||||
EXPORT_NORMALS=True,\
|
||||
EXPORT_UV=True,\
|
||||
EXPORT_COLORS=True):
|
||||
def rvec2d(v):
|
||||
return round(v[0], 6), round(v[1], 6)
|
||||
|
||||
scene = context.scene
|
||||
obj = context.object
|
||||
|
||||
if not filename.lower().endswith('.ply'):
|
||||
filename += '.ply'
|
||||
|
||||
if not ob:
|
||||
if not obj:
|
||||
raise Exception("Error, Select 1 active object")
|
||||
return
|
||||
|
||||
file = open(filename, 'w')
|
||||
file = open(filepath, 'w')
|
||||
|
||||
|
||||
#EXPORT_EDGES = Draw.Create(0)
|
||||
"""
|
||||
is_editmode = Blender.Window.EditMode()
|
||||
if is_editmode:
|
||||
Blender.Window.EditMode(0, '', 0)
|
||||
|
||||
Window.WaitCursor(1)
|
||||
"""
|
||||
if scene.objects.active:
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
#mesh = BPyMesh.getMeshFromObject(ob, None, EXPORT_APPLY_MODIFIERS, False, scn) # XXX
|
||||
if EXPORT_APPLY_MODIFIERS:
|
||||
mesh = ob.create_mesh(scene, True, 'PREVIEW')
|
||||
if use_modifiers:
|
||||
mesh = obj.create_mesh(scene, True, 'PREVIEW')
|
||||
else:
|
||||
mesh = ob.data
|
||||
mesh = obj.data
|
||||
|
||||
if not mesh:
|
||||
raise ("Error, could not get mesh data from active object")
|
||||
return
|
||||
raise Exception("Error, could not get mesh data from active object")
|
||||
|
||||
# mesh.transform(ob.matrix_world) # XXX
|
||||
# mesh.transform(obj.matrix_world) # XXX
|
||||
|
||||
faceUV = (len(mesh.uv_textures) > 0)
|
||||
vertexUV = (len(mesh.sticky) > 0)
|
||||
vertexColors = len(mesh.vertex_colors) > 0
|
||||
|
||||
if (not faceUV) and (not vertexUV):
|
||||
EXPORT_UV = False
|
||||
use_uv_coords = False
|
||||
if not vertexColors:
|
||||
EXPORT_COLORS = False
|
||||
use_colors = False
|
||||
|
||||
if not EXPORT_UV:
|
||||
if not use_uv_coords:
|
||||
faceUV = vertexUV = False
|
||||
if not EXPORT_COLORS:
|
||||
if not use_colors:
|
||||
vertexColors = False
|
||||
|
||||
if faceUV:
|
||||
active_uv_layer = mesh.uv_textures.active
|
||||
if not active_uv_layer:
|
||||
EXPORT_UV = False
|
||||
use_uv_coords = False
|
||||
faceUV = None
|
||||
else:
|
||||
active_uv_layer = active_uv_layer.data
|
||||
@@ -101,7 +86,7 @@ def write(filename, scene, ob, \
|
||||
if vertexColors:
|
||||
active_col_layer = mesh.vertex_colors.active
|
||||
if not active_col_layer:
|
||||
EXPORT_COLORS = False
|
||||
use_colors = False
|
||||
vertexColors = None
|
||||
else:
|
||||
active_col_layer = active_col_layer.data
|
||||
@@ -166,7 +151,7 @@ def write(filename, scene, ob, \
|
||||
|
||||
file.write('ply\n')
|
||||
file.write('format ascii 1.0\n')
|
||||
file.write('comment Created by Blender %s - www.blender.org, source file: %s\n' % (bpy.app.version_string, bpy.data.filepath.split('/')[-1].split('\\')[-1]))
|
||||
file.write('comment Created by Blender %s - www.blender.org, source file: %r\n' % (bpy.app.version_string, os.path.basename(bpy.data.filepath)))
|
||||
|
||||
file.write('element vertex %d\n' % len(ply_verts))
|
||||
|
||||
@@ -174,14 +159,14 @@ def write(filename, scene, ob, \
|
||||
file.write('property float y\n')
|
||||
file.write('property float z\n')
|
||||
|
||||
if EXPORT_NORMALS:
|
||||
if use_normals:
|
||||
file.write('property float nx\n')
|
||||
file.write('property float ny\n')
|
||||
file.write('property float nz\n')
|
||||
if EXPORT_UV:
|
||||
if use_uv_coords:
|
||||
file.write('property float s\n')
|
||||
file.write('property float t\n')
|
||||
if EXPORT_COLORS:
|
||||
if use_colors:
|
||||
file.write('property uchar red\n')
|
||||
file.write('property uchar green\n')
|
||||
file.write('property uchar blue\n')
|
||||
@@ -192,11 +177,11 @@ def write(filename, scene, ob, \
|
||||
|
||||
for i, v in enumerate(ply_verts):
|
||||
file.write('%.6f %.6f %.6f ' % tuple(mesh_verts[v[0]].co)) # co
|
||||
if EXPORT_NORMALS:
|
||||
if use_normals:
|
||||
file.write('%.6f %.6f %.6f ' % v[1]) # no
|
||||
if EXPORT_UV:
|
||||
if use_uv_coords:
|
||||
file.write('%.6f %.6f ' % v[2]) # uv
|
||||
if EXPORT_COLORS:
|
||||
if use_colors:
|
||||
file.write('%u %u %u' % v[3]) # col
|
||||
file.write('\n')
|
||||
|
||||
@@ -207,9 +192,9 @@ def write(filename, scene, ob, \
|
||||
file.write('4 %d %d %d %d\n' % tuple(pf))
|
||||
|
||||
file.close()
|
||||
print("writing", filename, "done")
|
||||
print("writing %r done" % filepath)
|
||||
|
||||
if EXPORT_APPLY_MODIFIERS:
|
||||
if use_modifiers:
|
||||
bpy.data.meshes.remove(mesh)
|
||||
|
||||
# XXX
|
||||
@@ -217,65 +202,5 @@ def write(filename, scene, ob, \
|
||||
if is_editmode:
|
||||
Blender.Window.EditMode(1, '', 0)
|
||||
"""
|
||||
|
||||
from bpy.props import *
|
||||
from io_utils import ExportHelper
|
||||
|
||||
|
||||
class ExportPLY(bpy.types.Operator, ExportHelper):
|
||||
'''Export a single object as a stanford PLY with normals, colours and texture coordinates.'''
|
||||
bl_idname = "export.ply"
|
||||
bl_label = "Export PLY"
|
||||
|
||||
filename_ext = ".ply"
|
||||
|
||||
# List of operator properties, the attributes will be assigned
|
||||
# to the class instance from the operator settings before calling.
|
||||
|
||||
use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default=True)
|
||||
use_normals = BoolProperty(name="Normals", description="Export Normals for smooth and hard shaded faces", default=True)
|
||||
use_uvs = BoolProperty(name="UVs", description="Exort the active UV layer", default=True)
|
||||
use_colors = BoolProperty(name="Vertex Colors", description="Exort the active vertex color layer", default=True)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.active_object != None
|
||||
|
||||
def execute(self, context):
|
||||
filepath = self.properties.filepath
|
||||
filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
|
||||
|
||||
write(filepath, context.scene, context.active_object,\
|
||||
EXPORT_APPLY_MODIFIERS=self.properties.use_modifiers,
|
||||
EXPORT_NORMALS=self.properties.use_normals,
|
||||
EXPORT_UV=self.properties.use_uvs,
|
||||
EXPORT_COLORS=self.properties.use_colors,
|
||||
)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
props = self.properties
|
||||
|
||||
row = layout.row()
|
||||
row.prop(props, "use_modifiers")
|
||||
row.prop(props, "use_normals")
|
||||
row = layout.row()
|
||||
row.prop(props, "use_uvs")
|
||||
row.prop(props, "use_colors")
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_export.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_export.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
return {'FINISHED'}
|
||||
|
||||
86
release/scripts/op/io_scene_3ds/__init__.py
Normal file
86
release/scripts/op/io_scene_3ds/__init__.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
# To support reload properly, try to access a package var, if it's there, reload everything
|
||||
if "bpy" in locals():
|
||||
import sys
|
||||
reload(sys.modules.get("io_scene_3ds.import_3ds", sys))
|
||||
reload(sys.modules.get("io_scene_3ds.export_3ds", sys))
|
||||
|
||||
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
from io_utils import ImportHelper, ExportHelper
|
||||
|
||||
|
||||
class Import3DS(bpy.types.Operator, ImportHelper):
|
||||
'''Import from 3DS file format (.3ds)'''
|
||||
bl_idname = "import_scene.autodesk_3ds"
|
||||
bl_label = 'Import 3DS'
|
||||
|
||||
filename_ext = ".3ds"
|
||||
|
||||
constrain_size = FloatProperty(name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0)
|
||||
use_image_search = BoolProperty(name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True)
|
||||
use_apply_transform = BoolProperty(name="Apply Transform", description="Workaround for object transformations importing incorrectly", default=False)
|
||||
|
||||
def execute(self, context):
|
||||
import io_scene_3ds.import_3ds
|
||||
return io_scene_3ds.import_3ds.load(self, context, **self.properties)
|
||||
|
||||
|
||||
class Export3DS(bpy.types.Operator, ExportHelper):
|
||||
'''Export to 3DS file format (.3ds)'''
|
||||
bl_idname = "export_scene.autodesk_3ds"
|
||||
bl_label = 'Export 3DS'
|
||||
|
||||
filename_ext = ".3ds"
|
||||
|
||||
def execute(self, context):
|
||||
import io_scene_3ds.export_3ds
|
||||
return io_scene_3ds.export_3ds.save(self, context, **self.properties)
|
||||
|
||||
|
||||
# Add to a menu
|
||||
def menu_func_export(self, context):
|
||||
self.layout.operator(Export3DS.bl_idname, text="3D Studio (.3ds)")
|
||||
|
||||
def menu_func_import(self, context):
|
||||
self.layout.operator(Import3DS.bl_idname, text="3D Studio (.3ds)")
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_import.append(menu_func_import)
|
||||
bpy.types.INFO_MT_file_export.append(menu_func_export)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_import.remove(menu_func_import)
|
||||
bpy.types.INFO_MT_file_export.remove(menu_func_export)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
||||
# NOTES:
|
||||
# why add 1 extra vertex? and remove it when done? - "Answer - eekadoodle - would need to re-order UV's without this since face order isnt always what we give blender, BMesh will solve :D"
|
||||
# disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
||||
@@ -32,58 +32,81 @@ from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode.
|
||||
|
||||
#Some of the chunks that we will export
|
||||
#----- Primary Chunk, at the beginning of each file
|
||||
PRIMARY= int("0x4D4D",16)
|
||||
PRIMARY= 0x4D4D
|
||||
|
||||
#------ Main Chunks
|
||||
OBJECTINFO = int("0x3D3D",16); #This gives the version of the mesh and is found right before the material and object information
|
||||
VERSION = int("0x0002",16); #This gives the version of the .3ds file
|
||||
KFDATA = int("0xB000",16); #This is the header for all of the key frame info
|
||||
OBJECTINFO = 0x3D3D #This gives the version of the mesh and is found right before the material and object information
|
||||
VERSION = 0x0002 #This gives the version of the .3ds file
|
||||
KFDATA = 0xB000 #This is the header for all of the key frame info
|
||||
|
||||
#------ sub defines of OBJECTINFO
|
||||
MATERIAL=45055 #0xAFFF // This stored the texture info
|
||||
OBJECT=16384 #0x4000 // This stores the faces, vertices, etc...
|
||||
|
||||
#>------ sub defines of MATERIAL
|
||||
MATNAME = int("0xA000",16); # This holds the material name
|
||||
MATAMBIENT = int("0xA010",16); # Ambient color of the object/material
|
||||
MATDIFFUSE = int("0xA020",16); # This holds the color of the object/material
|
||||
MATSPECULAR = int("0xA030",16); # SPecular color of the object/material
|
||||
MATSHINESS = int("0xA040",16); # ??
|
||||
MATMAP = int("0xA200",16); # This is a header for a new material
|
||||
MATMAPFILE = int("0xA300",16); # This holds the file name of the texture
|
||||
MATNAME = 0xA000 # This holds the material name
|
||||
MATAMBIENT = 0xA010 # Ambient color of the object/material
|
||||
MATDIFFUSE = 0xA020 # This holds the color of the object/material
|
||||
MATSPECULAR = 0xA030 # SPecular color of the object/material
|
||||
MATSHINESS = 0xA040 # ??
|
||||
MATMAP = 0xA200 # This is a header for a new material
|
||||
MATMAPFILE = 0xA300 # This holds the file name of the texture
|
||||
|
||||
RGB1= int("0x0011",16)
|
||||
RGB2= int("0x0012",16)
|
||||
RGB1= 0x0011
|
||||
RGB2= 0x0012
|
||||
|
||||
#>------ sub defines of OBJECT
|
||||
OBJECT_MESH = int("0x4100",16); # This lets us know that we are reading a new object
|
||||
OBJECT_LIGHT = int("0x4600",16); # This lets un know we are reading a light object
|
||||
OBJECT_CAMERA= int("0x4700",16); # This lets un know we are reading a camera object
|
||||
OBJECT_MESH = 0x4100 # This lets us know that we are reading a new object
|
||||
OBJECT_LIGHT = 0x4600 # This lets un know we are reading a light object
|
||||
OBJECT_CAMERA= 0x4700 # This lets un know we are reading a camera object
|
||||
|
||||
#>------ sub defines of CAMERA
|
||||
OBJECT_CAM_RANGES= int("0x4720",16); # The camera range values
|
||||
OBJECT_CAM_RANGES= 0x4720 # The camera range values
|
||||
|
||||
#>------ sub defines of OBJECT_MESH
|
||||
OBJECT_VERTICES = int("0x4110",16); # The objects vertices
|
||||
OBJECT_FACES = int("0x4120",16); # The objects faces
|
||||
OBJECT_MATERIAL = int("0x4130",16); # This is found if the object has a material, either texture map or color
|
||||
OBJECT_UV = int("0x4140",16); # The UV texture coordinates
|
||||
OBJECT_TRANS_MATRIX = int("0x4160",16); # The Object Matrix
|
||||
OBJECT_VERTICES = 0x4110 # The objects vertices
|
||||
OBJECT_FACES = 0x4120 # The objects faces
|
||||
OBJECT_MATERIAL = 0x4130 # This is found if the object has a material, either texture map or color
|
||||
OBJECT_UV = 0x4140 # The UV texture coordinates
|
||||
OBJECT_TRANS_MATRIX = 0x4160 # The Object Matrix
|
||||
|
||||
#>------ sub defines of KFDATA
|
||||
KFDATA_KFHDR = int("0xB00A",16);
|
||||
KFDATA_KFSEG = int("0xB008",16);
|
||||
KFDATA_KFCURTIME = int("0xB009",16);
|
||||
KFDATA_OBJECT_NODE_TAG = int("0xB002",16);
|
||||
KFDATA_KFHDR = 0xB00A
|
||||
KFDATA_KFSEG = 0xB008
|
||||
KFDATA_KFCURTIME = 0xB009
|
||||
KFDATA_OBJECT_NODE_TAG = 0xB002
|
||||
|
||||
#>------ sub defines of OBJECT_NODE_TAG
|
||||
OBJECT_NODE_ID = int("0xB030",16);
|
||||
OBJECT_NODE_HDR = int("0xB010",16);
|
||||
OBJECT_PIVOT = int("0xB013",16);
|
||||
OBJECT_INSTANCE_NAME = int("0xB011",16);
|
||||
POS_TRACK_TAG = int("0xB020",16);
|
||||
ROT_TRACK_TAG = int("0xB021",16);
|
||||
SCL_TRACK_TAG = int("0xB022",16);
|
||||
OBJECT_NODE_ID = 0xB030
|
||||
OBJECT_NODE_HDR = 0xB010
|
||||
OBJECT_PIVOT = 0xB013
|
||||
OBJECT_INSTANCE_NAME = 0xB011
|
||||
POS_TRACK_TAG = 0xB020
|
||||
ROT_TRACK_TAG = 0xB021
|
||||
SCL_TRACK_TAG = 0xB022
|
||||
|
||||
import struct
|
||||
|
||||
# So 3ds max can open files, limit names to 12 in length
|
||||
# this is verry annoying for filenames!
|
||||
name_unique = []
|
||||
name_mapping = {}
|
||||
def sane_name(name):
|
||||
name_fixed = name_mapping.get(name)
|
||||
if name_fixed is not None:
|
||||
return name_fixed
|
||||
|
||||
new_name = name[:12]
|
||||
|
||||
i = 0
|
||||
|
||||
while new_name in name_unique:
|
||||
new_name = new_name[:-4] + '.%.3d' % i
|
||||
i+=1
|
||||
|
||||
name_unique.append(new_name)
|
||||
name_mapping[name] = new_name
|
||||
return new_name
|
||||
|
||||
def uv_key(uv):
|
||||
return round(uv[0], 6), round(uv[1], 6)
|
||||
@@ -293,7 +316,7 @@ class _3ds_named_variable(object):
|
||||
if (self.value!=None):
|
||||
spaces=""
|
||||
for i in range(indent):
|
||||
spaces+=" ";
|
||||
spaces += " "
|
||||
if (self.name!=""):
|
||||
print(spaces, self.name, " = ", self.value)
|
||||
else:
|
||||
@@ -358,7 +381,7 @@ class _3ds_chunk(object):
|
||||
Uses the dump function of the named variables and the subchunks to do the actual work.'''
|
||||
spaces=""
|
||||
for i in range(indent):
|
||||
spaces+=" ";
|
||||
spaces += " "
|
||||
print(spaces, "ID=", hex(self.ID.value), "size=", self.get_size())
|
||||
for variable in self.variables:
|
||||
variable.dump(indent+1)
|
||||
@@ -393,11 +416,11 @@ def make_material_subchunk(id, color):
|
||||
Used for color subchunks, such as diffuse color or ambient color subchunks.'''
|
||||
mat_sub = _3ds_chunk(id)
|
||||
col1 = _3ds_chunk(RGB1)
|
||||
col1.add_variable("color1", _3ds_rgb_color(color));
|
||||
col1.add_variable("color1", _3ds_rgb_color(color))
|
||||
mat_sub.add_subchunk(col1)
|
||||
# optional:
|
||||
# col2 = _3ds_chunk(RGB1)
|
||||
# col2.add_variable("color2", _3ds_rgb_color(color));
|
||||
# col2.add_variable("color2", _3ds_rgb_color(color))
|
||||
# mat_sub.add_subchunk(col2)
|
||||
return mat_sub
|
||||
|
||||
@@ -835,21 +858,21 @@ def make_kf_obj_node(obj, name_to_id):
|
||||
return kf_obj_node
|
||||
"""
|
||||
|
||||
# import BPyMessages
|
||||
def write(filename, context):
|
||||
|
||||
def save(operator, context, filepath=""):
|
||||
import bpy
|
||||
import time
|
||||
from io_utils import create_derived_objects, free_derived_objects
|
||||
|
||||
'''Save the Blender scene to a 3ds file.'''
|
||||
|
||||
# Time the export
|
||||
|
||||
# XXX
|
||||
# if not BPyMessages.Warning_SaveOver(filename):
|
||||
# return
|
||||
|
||||
time1 = time.clock()
|
||||
# Blender.Window.WaitCursor(1)
|
||||
|
||||
sce = context.scene
|
||||
|
||||
if context.object:
|
||||
if bpy.ops.object.mode_set.poll():
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Initialize the main chunk (primary):
|
||||
@@ -998,7 +1021,7 @@ def write(filename, context):
|
||||
# Check the size:
|
||||
primary.get_size()
|
||||
# Open the file for writing:
|
||||
file = open( filename, 'wb' )
|
||||
file = open(filepath, 'wb')
|
||||
|
||||
# Recursively write the chunks to file:
|
||||
primary.write(file)
|
||||
@@ -1006,50 +1029,15 @@ def write(filename, context):
|
||||
# Close the file:
|
||||
file.close()
|
||||
|
||||
# Clear name mapping vars, could make locals too
|
||||
name_unique[:] = []
|
||||
name_mapping.clear()
|
||||
|
||||
# Debugging only: report the exporting time:
|
||||
# Blender.Window.WaitCursor(0)
|
||||
print("3ds export time: %.2f" % (time.clock() - time1))
|
||||
# print("3ds export time: %.2f" % (Blender.sys.time() - time1))
|
||||
|
||||
# Debugging only: dump the chunk hierarchy:
|
||||
#primary.dump()
|
||||
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
from io_utils import ExportHelper
|
||||
from io_utils import create_derived_objects, free_derived_objects
|
||||
|
||||
|
||||
class Export3DS(bpy.types.Operator, ExportHelper):
|
||||
'''Export to 3DS file format (.3ds)'''
|
||||
bl_idname = "export.autodesk_3ds"
|
||||
bl_label = 'Export 3DS'
|
||||
|
||||
filename_ext = ".3ds"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context): # Poll isnt working yet
|
||||
return context.active_object != None
|
||||
|
||||
def execute(self, context):
|
||||
filepath = self.properties.filepath
|
||||
filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
|
||||
|
||||
write(filepath, context)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# Add to a menu
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(Export3DS.bl_idname, text="3D Studio (.3ds)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_export.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_export.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
return {'FINISHED'}
|
||||
|
||||
@@ -25,7 +25,7 @@ import os
|
||||
import time
|
||||
import struct
|
||||
|
||||
from import_scene_obj import load_image
|
||||
from io_utils import load_image
|
||||
|
||||
import bpy
|
||||
import mathutils
|
||||
@@ -42,9 +42,9 @@ BOUNDS_3DS = []
|
||||
PRIMARY = int('0x4D4D',16)
|
||||
|
||||
#------ Main Chunks
|
||||
OBJECTINFO = int('0x3D3D',16); #This gives the version of the mesh and is found right before the material and object information
|
||||
VERSION = int('0x0002',16); #This gives the version of the .3ds file
|
||||
EDITKEYFRAME= int('0xB000',16); #This is the header for all of the key frame info
|
||||
OBJECTINFO = 0x3D3D #This gives the version of the mesh and is found right before the material and object information
|
||||
VERSION = 0x0002 #This gives the version of the .3ds file
|
||||
EDITKEYFRAME= 0xB000 #This is the header for all of the key frame info
|
||||
|
||||
#------ sub defines of OBJECTINFO
|
||||
MATERIAL = 45055 #0xAFFF // This stored the texture info
|
||||
@@ -52,62 +52,62 @@ OBJECT = 16384 #0x4000 // This stores the faces, vertices, etc...
|
||||
|
||||
#>------ sub defines of MATERIAL
|
||||
#------ sub defines of MATERIAL_BLOCK
|
||||
MAT_NAME = int('0xA000',16) # This holds the material name
|
||||
MAT_AMBIENT = int('0xA010',16) # Ambient color of the object/material
|
||||
MAT_DIFFUSE = int('0xA020',16) # This holds the color of the object/material
|
||||
MAT_SPECULAR = int('0xA030',16) # SPecular color of the object/material
|
||||
MAT_SHINESS = int('0xA040',16) # ??
|
||||
MAT_TRANSPARENCY= int('0xA050',16) # Transparency value of material
|
||||
MAT_SELF_ILLUM = int('0xA080',16) # Self Illumination value of material
|
||||
MAT_WIRE = int('0xA085',16) # Only render's wireframe
|
||||
MAT_NAME = 0xA000 # This holds the material name
|
||||
MAT_AMBIENT = 0xA010 # Ambient color of the object/material
|
||||
MAT_DIFFUSE = 0xA020 # This holds the color of the object/material
|
||||
MAT_SPECULAR = 0xA030 # SPecular color of the object/material
|
||||
MAT_SHINESS = 0xA040 # ??
|
||||
MAT_TRANSPARENCY= 0xA050 # Transparency value of material
|
||||
MAT_SELF_ILLUM = 0xA080 # Self Illumination value of material
|
||||
MAT_WIRE = 0xA085 # Only render's wireframe
|
||||
|
||||
MAT_TEXTURE_MAP = int('0xA200',16) # This is a header for a new texture map
|
||||
MAT_SPECULAR_MAP= int('0xA204',16) # This is a header for a new specular map
|
||||
MAT_OPACITY_MAP = int('0xA210',16) # This is a header for a new opacity map
|
||||
MAT_REFLECTION_MAP= int('0xA220',16) # This is a header for a new reflection map
|
||||
MAT_BUMP_MAP = int('0xA230',16) # This is a header for a new bump map
|
||||
MAT_MAP_FILENAME = int('0xA300',16) # This holds the file name of the texture
|
||||
MAT_TEXTURE_MAP = 0xA200 # This is a header for a new texture map
|
||||
MAT_SPECULAR_MAP= 0xA204 # This is a header for a new specular map
|
||||
MAT_OPACITY_MAP = 0xA210 # This is a header for a new opacity map
|
||||
MAT_REFLECTION_MAP= 0xA220 # This is a header for a new reflection map
|
||||
MAT_BUMP_MAP = 0xA230 # This is a header for a new bump map
|
||||
MAT_MAP_FILEPATH = 0xA300 # This holds the file name of the texture
|
||||
|
||||
MAT_FLOAT_COLOR = int ('0x0010', 16) #color defined as 3 floats
|
||||
MAT_24BIT_COLOR = int ('0x0011', 16) #color defined as 3 bytes
|
||||
MAT_FLOAT_COLOR = 0x0010 #color defined as 3 floats
|
||||
MAT_24BIT_COLOR = 0x0011 #color defined as 3 bytes
|
||||
|
||||
#>------ sub defines of OBJECT
|
||||
OBJECT_MESH = int('0x4100',16); # This lets us know that we are reading a new object
|
||||
OBJECT_LAMP = int('0x4600',16); # This lets un know we are reading a light object
|
||||
OBJECT_LAMP_SPOT = int('0x4610',16); # The light is a spotloght.
|
||||
OBJECT_LAMP_OFF = int('0x4620',16); # The light off.
|
||||
OBJECT_LAMP_ATTENUATE = int('0x4625',16);
|
||||
OBJECT_LAMP_RAYSHADE = int('0x4627',16);
|
||||
OBJECT_LAMP_SHADOWED = int('0x4630',16);
|
||||
OBJECT_LAMP_LOCAL_SHADOW = int('0x4640',16);
|
||||
OBJECT_LAMP_LOCAL_SHADOW2 = int('0x4641',16);
|
||||
OBJECT_LAMP_SEE_CONE = int('0x4650',16);
|
||||
OBJECT_LAMP_SPOT_RECTANGULAR = int('0x4651',16);
|
||||
OBJECT_LAMP_SPOT_OVERSHOOT = int('0x4652',16);
|
||||
OBJECT_LAMP_SPOT_PROJECTOR = int('0x4653',16);
|
||||
OBJECT_LAMP_EXCLUDE = int('0x4654',16);
|
||||
OBJECT_LAMP_RANGE = int('0x4655',16);
|
||||
OBJECT_LAMP_ROLL = int('0x4656',16);
|
||||
OBJECT_LAMP_SPOT_ASPECT = int('0x4657',16);
|
||||
OBJECT_LAMP_RAY_BIAS = int('0x4658',16);
|
||||
OBJECT_LAMP_INNER_RANGE = int('0x4659',16);
|
||||
OBJECT_LAMP_OUTER_RANGE = int('0x465A',16);
|
||||
OBJECT_LAMP_MULTIPLIER = int('0x465B',16);
|
||||
OBJECT_LAMP_AMBIENT_LIGHT = int('0x4680',16);
|
||||
OBJECT_MESH = 0x4100 # This lets us know that we are reading a new object
|
||||
OBJECT_LAMP = 0x4600 # This lets un know we are reading a light object
|
||||
OBJECT_LAMP_SPOT = 0x4610 # The light is a spotloght.
|
||||
OBJECT_LAMP_OFF = 0x4620 # The light off.
|
||||
OBJECT_LAMP_ATTENUATE = 0x4625
|
||||
OBJECT_LAMP_RAYSHADE = 0x4627
|
||||
OBJECT_LAMP_SHADOWED = 0x4630
|
||||
OBJECT_LAMP_LOCAL_SHADOW = 0x4640
|
||||
OBJECT_LAMP_LOCAL_SHADOW2 = 0x4641
|
||||
OBJECT_LAMP_SEE_CONE = 0x4650
|
||||
OBJECT_LAMP_SPOT_RECTANGULAR = 0x4651
|
||||
OBJECT_LAMP_SPOT_OVERSHOOT = 0x4652
|
||||
OBJECT_LAMP_SPOT_PROJECTOR = 0x4653
|
||||
OBJECT_LAMP_EXCLUDE = 0x4654
|
||||
OBJECT_LAMP_RANGE = 0x4655
|
||||
OBJECT_LAMP_ROLL = 0x4656
|
||||
OBJECT_LAMP_SPOT_ASPECT = 0x4657
|
||||
OBJECT_LAMP_RAY_BIAS = 0x4658
|
||||
OBJECT_LAMP_INNER_RANGE = 0x4659
|
||||
OBJECT_LAMP_OUTER_RANGE = 0x465A
|
||||
OBJECT_LAMP_MULTIPLIER = 0x465B
|
||||
OBJECT_LAMP_AMBIENT_LIGHT = 0x4680
|
||||
|
||||
|
||||
|
||||
OBJECT_CAMERA= int('0x4700',16); # This lets un know we are reading a camera object
|
||||
OBJECT_CAMERA= 0x4700 # This lets un know we are reading a camera object
|
||||
|
||||
#>------ sub defines of CAMERA
|
||||
OBJECT_CAM_RANGES= int('0x4720',16); # The camera range values
|
||||
OBJECT_CAM_RANGES= 0x4720 # The camera range values
|
||||
|
||||
#>------ sub defines of OBJECT_MESH
|
||||
OBJECT_VERTICES = int('0x4110',16); # The objects vertices
|
||||
OBJECT_FACES = int('0x4120',16); # The objects faces
|
||||
OBJECT_MATERIAL = int('0x4130',16); # This is found if the object has a material, either texture map or color
|
||||
OBJECT_UV = int('0x4140',16); # The UV texture coordinates
|
||||
OBJECT_TRANS_MATRIX = int('0x4160',16); # The Object Matrix
|
||||
OBJECT_VERTICES = 0x4110 # The objects vertices
|
||||
OBJECT_FACES = 0x4120 # The objects faces
|
||||
OBJECT_MATERIAL = 0x4130 # This is found if the object has a material, either texture map or color
|
||||
OBJECT_UV = 0x4140 # The UV texture coordinates
|
||||
OBJECT_TRANS_MATRIX = 0x4160 # The Object Matrix
|
||||
|
||||
global scn
|
||||
scn = None
|
||||
@@ -304,7 +304,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
|
||||
#print 'MAT_TEXTURE_MAP..while', new_chunk.bytes_read, new_chunk.length
|
||||
read_chunk(file, temp_chunk)
|
||||
|
||||
if (temp_chunk.ID == MAT_MAP_FILENAME):
|
||||
if (temp_chunk.ID == MAT_MAP_FILEPATH):
|
||||
texture_name = read_string(file)
|
||||
img = TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname)
|
||||
new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
|
||||
@@ -318,7 +318,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
|
||||
if img:
|
||||
add_texture_to_material(img, new_texture, contextMaterial, mapto)
|
||||
|
||||
dirname = os.path.dirname(FILENAME)
|
||||
dirname = os.path.dirname(file.name)
|
||||
|
||||
#loop through all the data for this chunk (previous chunk) and see what it is
|
||||
while (previous_chunk.bytes_read < previous_chunk.length):
|
||||
@@ -604,14 +604,14 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
|
||||
#contextMatrix = contextMatrix * tx
|
||||
#contextMatrix = contextMatrix *tx
|
||||
|
||||
elif (new_chunk.ID == MAT_MAP_FILENAME):
|
||||
elif (new_chunk.ID == MAT_MAP_FILEPATH):
|
||||
texture_name = read_string(file)
|
||||
try:
|
||||
TEXTURE_DICT[contextMaterial.name]
|
||||
except:
|
||||
#img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
|
||||
#img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILEPATH)
|
||||
img = TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname)
|
||||
# img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
|
||||
# img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILEPATH, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
|
||||
|
||||
new_chunk.bytes_read += len(texture_name)+1 #plus one for the null character that gets removed
|
||||
|
||||
@@ -634,30 +634,27 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
|
||||
if CreateBlenderObject:
|
||||
putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials)
|
||||
|
||||
def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True, APPLY_MATRIX=False):
|
||||
global FILENAME, SCN
|
||||
# global FILENAME, SCN_OBJECTS
|
||||
def load_3ds(filepath, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True, APPLY_MATRIX=False):
|
||||
global SCN
|
||||
|
||||
# XXX
|
||||
# if BPyMessages.Error_NoFile(filename):
|
||||
# if BPyMessages.Error_NoFile(filepath):
|
||||
# return
|
||||
|
||||
print('\n\nImporting 3DS: "%s"' % (filename))
|
||||
# print('\n\nImporting 3DS: "%s"' % (Blender.sys.expandpath(filename)))
|
||||
print('\n\nImporting 3DS: %r' % (filepath))
|
||||
|
||||
time1 = time.clock()
|
||||
# time1 = Blender.sys.time()
|
||||
|
||||
FILENAME = filename
|
||||
current_chunk = chunk()
|
||||
|
||||
file = open(filename,'rb')
|
||||
file = open(filepath, 'rb')
|
||||
|
||||
#here we go!
|
||||
# print 'reading the first chunk'
|
||||
read_chunk(file, current_chunk)
|
||||
if (current_chunk.ID!=PRIMARY):
|
||||
print('\tFatal Error: Not a valid 3ds file: ', filename)
|
||||
print('\tFatal Error: Not a valid 3ds file: %r' % filepath)
|
||||
file.close()
|
||||
return
|
||||
|
||||
@@ -718,7 +715,7 @@ def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True,
|
||||
# Done DUMMYVERT
|
||||
"""
|
||||
if IMPORT_AS_INSTANCE:
|
||||
name = filename.split('\\')[-1].split('/')[-1]
|
||||
name = filepath.split('\\')[-1].split('/')[-1]
|
||||
# Create a group for this import.
|
||||
group_scn = Scene.New(name)
|
||||
for ob in importedObjects:
|
||||
@@ -776,90 +773,10 @@ def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True,
|
||||
# Done constraining to bounds.
|
||||
|
||||
# Select all new objects.
|
||||
print('finished importing: "%s" in %.4f sec.' % (filename, (time.clock()-time1)))
|
||||
# print('finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1)))
|
||||
print('finished importing: %r in %.4f sec.' % (filepath, (time.clock()-time1)))
|
||||
file.close()
|
||||
|
||||
|
||||
DEBUG = False
|
||||
# For testing compatibility
|
||||
#load_3ds('/metavr/convert/vehicle/truck_002/TruckTanker1.3DS', False)
|
||||
#load_3ds('/metavr/archive/convert/old/arranged_3ds_to_hpx-2/only-need-engine-trains/Engine2.3DS', False)
|
||||
'''
|
||||
|
||||
else:
|
||||
import os
|
||||
# DEBUG ONLY
|
||||
TIME = Blender.sys.time()
|
||||
import os
|
||||
print 'Searching for files'
|
||||
os.system('find /metavr/ -iname "*.3ds" > /tmp/temp3ds_list')
|
||||
# os.system('find /storage/ -iname "*.3ds" > /tmp/temp3ds_list')
|
||||
print '...Done'
|
||||
file = open('/tmp/temp3ds_list', 'r')
|
||||
lines = file.readlines()
|
||||
file.close()
|
||||
# sort by filesize for faster testing
|
||||
lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines]
|
||||
lines_size.sort()
|
||||
lines = [f[1] for f in lines_size]
|
||||
|
||||
|
||||
def between(v,a,b):
|
||||
if v <= max(a,b) and v >= min(a,b):
|
||||
return True
|
||||
return False
|
||||
|
||||
for i, _3ds in enumerate(lines):
|
||||
if between(i, 650,800):
|
||||
#_3ds= _3ds[:-1]
|
||||
print 'Importing', _3ds, '\nNUMBER', i, 'of', len(lines)
|
||||
_3ds_file= _3ds.split('/')[-1].split('\\')[-1]
|
||||
newScn = Blender.Scene.New(_3ds_file)
|
||||
newScn.makeCurrent()
|
||||
load_3ds(_3ds, False)
|
||||
|
||||
print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME)
|
||||
|
||||
'''
|
||||
from bpy.props import *
|
||||
from io_utils import ImportHelper
|
||||
|
||||
|
||||
class IMPORT_OT_autodesk_3ds(bpy.types.Operator, ImportHelper):
|
||||
'''Import from 3DS file format (.3ds)'''
|
||||
bl_idname = "import_scene.autodesk_3ds"
|
||||
bl_label = 'Import 3DS'
|
||||
|
||||
filename_ext = ".3ds"
|
||||
|
||||
constrain_size = FloatProperty(name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0)
|
||||
search_images = BoolProperty(name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True)
|
||||
apply_transform = BoolProperty(name="Apply Transform", description="Workaround for object transformations importing incorrectly", default=False)
|
||||
|
||||
def execute(self, context):
|
||||
load_3ds(self.properties.filepath,
|
||||
context,
|
||||
IMPORT_CONSTRAIN_BOUNDS=self.properties.constrain_size,
|
||||
IMAGE_SEARCH=self.properties.search_images,
|
||||
APPLY_MATRIX=self.properties.apply_transform)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(IMPORT_OT_autodesk_3ds.bl_idname, text="3D Studio (.3ds)")
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_import.append(menu_func)
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_import.remove(menu_func)
|
||||
|
||||
# NOTES:
|
||||
# why add 1 extra vertex? and remove it when done? - "Answer - eekadoodle - would need to re-order UV's without this since face order isnt always what we give blender, BMesh will solve :D"
|
||||
# disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
||||
def load(operator, context, filepath="", constrain_size=0.0, use_image_search=True, use_apply_transform=True):
|
||||
load_3ds(filepath, context, IMPORT_CONSTRAIN_BOUNDS=constrain_size, IMAGE_SEARCH=use_image_search, APPLY_MATRIX=use_apply_transform)
|
||||
return {'FINISHED'}
|
||||
|
||||
102
release/scripts/op/io_scene_fbx/__init__.py
Normal file
102
release/scripts/op/io_scene_fbx/__init__.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
# To support reload properly, try to access a package var, if it's there, reload everything
|
||||
if "bpy" in locals():
|
||||
# only reload if we alredy loaded, highly annoying
|
||||
import sys
|
||||
reload(sys.modules.get("io_scene_fbx.export_fbx", sys))
|
||||
|
||||
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
from io_utils import ExportHelper
|
||||
|
||||
|
||||
class ExportFBX(bpy.types.Operator, ExportHelper):
|
||||
'''Selection to an ASCII Autodesk FBX'''
|
||||
bl_idname = "export_scene.fbx"
|
||||
bl_label = "Export FBX"
|
||||
|
||||
filename_ext = ".fbx"
|
||||
|
||||
# List of operator properties, the attributes will be assigned
|
||||
# to the class instance from the operator settings before calling.
|
||||
|
||||
EXP_OBS_SELECTED = BoolProperty(name="Selected Objects", description="Export selected objects on visible layers", default=True)
|
||||
# EXP_OBS_SCENE = BoolProperty(name="Scene Objects", description="Export all objects in this scene", default=True)
|
||||
TX_SCALE = FloatProperty(name="Scale", description="Scale all data, (Note! some imports dont support scaled armatures)", min=0.01, max=1000.0, soft_min=0.01, soft_max=1000.0, default=1.0)
|
||||
TX_XROT90 = BoolProperty(name="Rot X90", description="Rotate all objects 90 degrees about the X axis", default=True)
|
||||
TX_YROT90 = BoolProperty(name="Rot Y90", description="Rotate all objects 90 degrees about the Y axis", default=False)
|
||||
TX_ZROT90 = BoolProperty(name="Rot Z90", description="Rotate all objects 90 degrees about the Z axis", default=False)
|
||||
EXP_EMPTY = BoolProperty(name="Empties", description="Export empty objects", default=True)
|
||||
EXP_CAMERA = BoolProperty(name="Cameras", description="Export camera objects", default=True)
|
||||
EXP_LAMP = BoolProperty(name="Lamps", description="Export lamp objects", default=True)
|
||||
EXP_ARMATURE = BoolProperty(name="Armatures", description="Export armature objects", default=True)
|
||||
EXP_MESH = BoolProperty(name="Meshes", description="Export mesh objects", default=True)
|
||||
EXP_MESH_APPLY_MOD = BoolProperty(name="Modifiers", description="Apply modifiers to mesh objects", default=True)
|
||||
EXP_MESH_HQ_NORMALS = BoolProperty(name="HQ Normals", description="Generate high quality normals", default=True)
|
||||
EXP_IMAGE_COPY = BoolProperty(name="Copy Image Files", description="Copy image files to the destination path", default=False)
|
||||
# armature animation
|
||||
ANIM_ENABLE = BoolProperty(name="Enable Animation", description="Export keyframe animation", default=True)
|
||||
ANIM_OPTIMIZE = BoolProperty(name="Optimize Keyframes", description="Remove double keyframes", default=True)
|
||||
ANIM_OPTIMIZE_PRECISSION = FloatProperty(name="Precision", description="Tolerence for comparing double keyframes (higher for greater accuracy)", min=1, max=16, soft_min=1, soft_max=16, default=6.0)
|
||||
# ANIM_ACTION_ALL = BoolProperty(name="Current Action", description="Use actions currently applied to the armatures (use scene start/end frame)", default=True)
|
||||
ANIM_ACTION_ALL = BoolProperty(name="All Actions", description="Use all actions for armatures, if false, use current action", default=False)
|
||||
# batch
|
||||
BATCH_ENABLE = BoolProperty(name="Enable Batch", description="Automate exporting multiple scenes or groups to files", default=False)
|
||||
BATCH_GROUP = BoolProperty(name="Group > File", description="Export each group as an FBX file, if false, export each scene as an FBX file", default=False)
|
||||
BATCH_OWN_DIR = BoolProperty(name="Own Dir", description="Create a dir for each exported file", default=True)
|
||||
BATCH_FILE_PREFIX = StringProperty(name="Prefix", description="Prefix each file with this name", maxlen=1024, default="")
|
||||
|
||||
|
||||
def execute(self, context):
|
||||
import math
|
||||
from mathutils import Matrix
|
||||
if not self.properties.filepath:
|
||||
raise Exception("filepath not set")
|
||||
|
||||
mtx4_x90n = Matrix.Rotation(-math.pi/2.0, 4, 'X')
|
||||
mtx4_y90n = Matrix.Rotation(-math.pi/2.0, 4, 'Y')
|
||||
mtx4_z90n = Matrix.Rotation(-math.pi/2.0, 4, 'Z')
|
||||
|
||||
GLOBAL_MATRIX = Matrix()
|
||||
GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = self.properties.TX_SCALE
|
||||
if self.properties.TX_XROT90: GLOBAL_MATRIX = mtx4_x90n * GLOBAL_MATRIX
|
||||
if self.properties.TX_YROT90: GLOBAL_MATRIX = mtx4_y90n * GLOBAL_MATRIX
|
||||
if self.properties.TX_ZROT90: GLOBAL_MATRIX = mtx4_z90n * GLOBAL_MATRIX
|
||||
|
||||
import io_scene_fbx.export_fbx
|
||||
return io_scene_fbx.export_fbx.save(self, context, GLOBAL_MATRIX=GLOBAL_MATRIX, **self.properties)
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX (.fbx)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_export.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_export.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
@@ -34,19 +34,10 @@ import shutil # for file copying
|
||||
import bpy
|
||||
from mathutils import Vector, Euler, Matrix
|
||||
|
||||
def copy_file(source, dest):
|
||||
# XXX - remove, can use shutil
|
||||
file = open(source, 'rb')
|
||||
data = file.read()
|
||||
file.close()
|
||||
|
||||
file = open(dest, 'wb')
|
||||
file.write(data)
|
||||
file.close()
|
||||
|
||||
|
||||
# XXX not used anymore, images are copied one at a time
|
||||
def copy_images(dest_dir, textures):
|
||||
import shutil
|
||||
|
||||
if not dest_dir.endswith(os.sep):
|
||||
dest_dir += os.sep
|
||||
|
||||
@@ -61,12 +52,12 @@ def copy_images(dest_dir, textures):
|
||||
# Make a name for the target path.
|
||||
dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
|
||||
if not Blender.sys.exists(dest_image_path): # Image isnt already there
|
||||
print('\tCopying "%s" > "%s"' % (image_path, dest_image_path))
|
||||
print("\tCopying %r > %r" % (image_path, dest_image_path))
|
||||
try:
|
||||
copy_file(image_path, dest_image_path)
|
||||
shutil.copy(image_path, dest_image_path)
|
||||
copyCount+=1
|
||||
except:
|
||||
print('\t\tWarning, file failed to copy, skipping.')
|
||||
print("\t\tWarning, file failed to copy, skipping.")
|
||||
|
||||
print('\tCopied %d images' % copyCount)
|
||||
|
||||
@@ -81,27 +72,11 @@ def eulerRadToDeg(eul):
|
||||
|
||||
return ret
|
||||
|
||||
mtx4_identity = Matrix()
|
||||
|
||||
# testing
|
||||
mtx_x90 = Matrix.Rotation( math.pi/2, 3, 'X') # used
|
||||
#mtx_x90n = Matrix.Rotation(-90, 3, 'x')
|
||||
#mtx_y90 = Matrix.Rotation( 90, 3, 'y')
|
||||
#mtx_y90n = Matrix.Rotation(-90, 3, 'y')
|
||||
#mtx_z90 = Matrix.Rotation( 90, 3, 'z')
|
||||
#mtx_z90n = Matrix.Rotation(-90, 3, 'z')
|
||||
|
||||
#mtx4_x90 = Matrix.Rotation( 90, 4, 'x')
|
||||
mtx4_x90n = Matrix.Rotation(-math.pi/2, 4, 'X') # used
|
||||
#mtx4_y90 = Matrix.Rotation( 90, 4, 'y')
|
||||
mtx4_y90n = Matrix.Rotation(-math.pi/2, 4, 'Y') # used
|
||||
mtx4_z90 = Matrix.Rotation( math.pi/2, 4, 'Z') # used
|
||||
mtx4_z90n = Matrix.Rotation(-math.pi/2, 4, 'Z') # used
|
||||
|
||||
# def strip_path(p):
|
||||
# return p.split('\\')[-1].split('/')[-1]
|
||||
|
||||
# Used to add the scene name into the filename without using odd chars
|
||||
# Used to add the scene name into the filepath without using odd chars
|
||||
sane_name_mapping_ob = {}
|
||||
sane_name_mapping_mat = {}
|
||||
sane_name_mapping_tex = {}
|
||||
@@ -174,7 +149,7 @@ def sane_groupname(data): return sane_name(data, sane_name_mapping_group)
|
||||
# '''
|
||||
# fname_orig - blender path, can be relative
|
||||
# basepath - fname_rel will be relative to this
|
||||
# FORCE_CWD - dont use the basepath, just add a ./ to the filename.
|
||||
# FORCE_CWD - dont use the basepath, just add a ./ to the filepath.
|
||||
# use when we know the file will be in the basepath.
|
||||
# '''
|
||||
# fname = bpy.path.abspath(fname_orig)
|
||||
@@ -259,19 +234,17 @@ header_comment = \
|
||||
|
||||
'''
|
||||
|
||||
# This func can be called with just the filename
|
||||
def write(filename, batch_objects = None, \
|
||||
context = None,
|
||||
# This func can be called with just the filepath
|
||||
def save(operator, context, filepath="", \
|
||||
EXP_OBS_SELECTED = True,
|
||||
EXP_MESH = True,
|
||||
EXP_MESH_APPLY_MOD = True,
|
||||
# EXP_MESH_HQ_NORMALS = False,
|
||||
EXP_ARMATURE = True,
|
||||
EXP_LAMP = True,
|
||||
EXP_CAMERA = True,
|
||||
EXP_EMPTY = True,
|
||||
EXP_IMAGE_COPY = False,
|
||||
GLOBAL_MATRIX = Matrix(),
|
||||
GLOBAL_MATRIX = None,
|
||||
ANIM_ENABLE = True,
|
||||
ANIM_OPTIMIZE = True,
|
||||
ANIM_OPTIMIZE_PRECISSION = 6,
|
||||
@@ -282,16 +255,26 @@ def write(filename, batch_objects = None, \
|
||||
BATCH_OWN_DIR = False
|
||||
):
|
||||
|
||||
if bpy.context.object:
|
||||
#XXX, missing arg
|
||||
batch_objects = None
|
||||
|
||||
# testing
|
||||
mtx_x90 = Matrix.Rotation( math.pi/2.0, 3, 'X') # used
|
||||
mtx4_z90 = Matrix.Rotation( math.pi/2.0, 4, 'Z')
|
||||
|
||||
if GLOBAL_MATRIX is None:
|
||||
GLOBAL_MATRIX = Matrix()
|
||||
|
||||
if bpy.ops.object.mode_set.poll():
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# ----------------- Batch support!
|
||||
if BATCH_ENABLE:
|
||||
if os == None: BATCH_OWN_DIR = False
|
||||
|
||||
fbxpath = filename
|
||||
fbxpath = filepath
|
||||
|
||||
# get the path component of filename
|
||||
# get the path component of filepath
|
||||
tmp_exists = bpy.utils.exists(fbxpath)
|
||||
# tmp_exists = Blender.sys.exists(fbxpath)
|
||||
|
||||
@@ -300,7 +283,7 @@ def write(filename, batch_objects = None, \
|
||||
# while fbxpath and fbxpath[-1] not in ('/', '\\'):
|
||||
# fbxpath = fbxpath[:-1]
|
||||
if not fbxpath:
|
||||
# if not filename:
|
||||
# if not filepath:
|
||||
# XXX
|
||||
print('Error%t|Directory does not exist!')
|
||||
# Draw.PupMenu('Error%t|Directory does not exist!')
|
||||
@@ -345,9 +328,9 @@ def write(filename, batch_objects = None, \
|
||||
os.mkdir(new_fbxpath)
|
||||
|
||||
|
||||
filename = new_fbxpath + newname + '.fbx'
|
||||
filepath = new_fbxpath + newname + '.fbx'
|
||||
|
||||
print('\nBatch exporting %s as...\n\t"%s"' % (data, filename))
|
||||
print('\nBatch exporting %s as...\n\t%r' % (data, filepath))
|
||||
|
||||
# XXX don't know what to do with this, probably do the same? (Arystan)
|
||||
if BATCH_GROUP: #group
|
||||
@@ -370,12 +353,11 @@ def write(filename, batch_objects = None, \
|
||||
|
||||
# Call self with modified args
|
||||
# Dont pass batch options since we already usedt them
|
||||
write(filename, data.objects,
|
||||
write(filepath, data.objects,
|
||||
context,
|
||||
False,
|
||||
EXP_MESH,
|
||||
EXP_MESH_APPLY_MOD,
|
||||
# EXP_MESH_HQ_NORMALS,
|
||||
EXP_ARMATURE,
|
||||
EXP_LAMP,
|
||||
EXP_CAMERA,
|
||||
@@ -400,9 +382,9 @@ def write(filename, batch_objects = None, \
|
||||
# end batch support
|
||||
|
||||
# Use this for working out paths relative to the export location
|
||||
basepath = os.path.dirname(filename) or '.'
|
||||
basepath = os.path.dirname(filepath) or '.'
|
||||
basepath += os.sep
|
||||
# basepath = Blender.sys.dirname(filename)
|
||||
# basepath = Blender.sys.dirname(filepath)
|
||||
|
||||
# ----------------------------------------------
|
||||
# storage classes
|
||||
@@ -549,11 +531,11 @@ def write(filename, batch_objects = None, \
|
||||
|
||||
|
||||
|
||||
print('\nFBX export starting...', filename)
|
||||
print('\nFBX export starting... %r' % filepath)
|
||||
start_time = time.clock()
|
||||
# start_time = Blender.sys.time()
|
||||
try:
|
||||
file = open(filename, 'w')
|
||||
file = open(filepath, 'w')
|
||||
except:
|
||||
return False
|
||||
|
||||
@@ -2449,7 +2431,7 @@ Objects: {''')
|
||||
file.write('\n\t\tPoseNode: {')
|
||||
file.write('\n\t\t\tNode: "Model::%s"' % fbxName )
|
||||
if matrix: file.write('\n\t\t\tMatrix: %s' % mat4x4str(matrix))
|
||||
else: file.write('\n\t\t\tMatrix: %s' % mat4x4str(mtx4_identity))
|
||||
else: file.write('\n\t\t\tMatrix: %s' % mat4x4str(Matrix()))
|
||||
file.write('\n\t\t}')
|
||||
|
||||
file.write('\n\t}')
|
||||
@@ -2946,12 +2928,10 @@ Takes: {''')
|
||||
mist_start = m.start
|
||||
mist_end = m.depth
|
||||
mist_height = m.height
|
||||
# mist_intense, mist_start, mist_end, mist_height = world.mist
|
||||
world_hor = world.horizon_color
|
||||
# world_hor = world.hor
|
||||
else:
|
||||
has_mist = mist_intense = mist_start = mist_end = mist_height = 0
|
||||
world_hor = 0,0,0
|
||||
world_hor = 0, 0, 0
|
||||
|
||||
file.write('\n;Version 5 settings')
|
||||
file.write('\n;------------------------------------------------------------------')
|
||||
@@ -3003,94 +2983,7 @@ Takes: {''')
|
||||
# bpy.util.copy_images( [ tex[1] for tex in textures if tex[1] != None ], basepath)
|
||||
|
||||
print('export finished in %.4f sec.' % (time.clock() - start_time))
|
||||
return True
|
||||
|
||||
from bpy.props import *
|
||||
from io_utils import ExportHelper
|
||||
|
||||
|
||||
class ExportFBX(bpy.types.Operator, ExportHelper):
|
||||
'''Selection to an ASCII Autodesk FBX'''
|
||||
bl_idname = "export.fbx"
|
||||
bl_label = "Export FBX"
|
||||
|
||||
filename_ext = ".fbx"
|
||||
|
||||
# List of operator properties, the attributes will be assigned
|
||||
# to the class instance from the operator settings before calling.
|
||||
|
||||
EXP_OBS_SELECTED = BoolProperty(name="Selected Objects", description="Export selected objects on visible layers", default=True)
|
||||
# EXP_OBS_SCENE = BoolProperty(name="Scene Objects", description="Export all objects in this scene", default=True)
|
||||
TX_SCALE = FloatProperty(name="Scale", description="Scale all data, (Note! some imports dont support scaled armatures)", min=0.01, max=1000.0, soft_min=0.01, soft_max=1000.0, default=1.0)
|
||||
TX_XROT90 = BoolProperty(name="Rot X90", description="Rotate all objects 90 degrees about the X axis", default=True)
|
||||
TX_YROT90 = BoolProperty(name="Rot Y90", description="Rotate all objects 90 degrees about the Y axis", default=False)
|
||||
TX_ZROT90 = BoolProperty(name="Rot Z90", description="Rotate all objects 90 degrees about the Z axis", default=False)
|
||||
EXP_EMPTY = BoolProperty(name="Empties", description="Export empty objects", default=True)
|
||||
EXP_CAMERA = BoolProperty(name="Cameras", description="Export camera objects", default=True)
|
||||
EXP_LAMP = BoolProperty(name="Lamps", description="Export lamp objects", default=True)
|
||||
EXP_ARMATURE = BoolProperty(name="Armatures", description="Export armature objects", default=True)
|
||||
EXP_MESH = BoolProperty(name="Meshes", description="Export mesh objects", default=True)
|
||||
EXP_MESH_APPLY_MOD = BoolProperty(name="Modifiers", description="Apply modifiers to mesh objects", default=True)
|
||||
EXP_MESH_HQ_NORMALS = BoolProperty(name="HQ Normals", description="Generate high quality normals", default=True)
|
||||
EXP_IMAGE_COPY = BoolProperty(name="Copy Image Files", description="Copy image files to the destination path", default=False)
|
||||
# armature animation
|
||||
ANIM_ENABLE = BoolProperty(name="Enable Animation", description="Export keyframe animation", default=True)
|
||||
ANIM_OPTIMIZE = BoolProperty(name="Optimize Keyframes", description="Remove double keyframes", default=True)
|
||||
ANIM_OPTIMIZE_PRECISSION = FloatProperty(name="Precision", description="Tolerence for comparing double keyframes (higher for greater accuracy)", min=1, max=16, soft_min=1, soft_max=16, default=6.0)
|
||||
# ANIM_ACTION_ALL = BoolProperty(name="Current Action", description="Use actions currently applied to the armatures (use scene start/end frame)", default=True)
|
||||
ANIM_ACTION_ALL = BoolProperty(name="All Actions", description="Use all actions for armatures, if false, use current action", default=False)
|
||||
# batch
|
||||
BATCH_ENABLE = BoolProperty(name="Enable Batch", description="Automate exporting multiple scenes or groups to files", default=False)
|
||||
BATCH_GROUP = BoolProperty(name="Group > File", description="Export each group as an FBX file, if false, export each scene as an FBX file", default=False)
|
||||
BATCH_OWN_DIR = BoolProperty(name="Own Dir", description="Create a dir for each exported file", default=True)
|
||||
BATCH_FILE_PREFIX = StringProperty(name="Prefix", description="Prefix each file with this name", maxlen=1024, default="")
|
||||
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.active_object
|
||||
|
||||
def execute(self, context):
|
||||
if not self.properties.filepath:
|
||||
raise Exception("filepath not set")
|
||||
|
||||
filepath = self.properties.filepath
|
||||
filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
|
||||
|
||||
GLOBAL_MATRIX = mtx4_identity
|
||||
GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = self.properties.TX_SCALE
|
||||
if self.properties.TX_XROT90: GLOBAL_MATRIX = mtx4_x90n * GLOBAL_MATRIX
|
||||
if self.properties.TX_YROT90: GLOBAL_MATRIX = mtx4_y90n * GLOBAL_MATRIX
|
||||
if self.properties.TX_ZROT90: GLOBAL_MATRIX = mtx4_z90n * GLOBAL_MATRIX
|
||||
|
||||
write(filepath,
|
||||
None, # XXX
|
||||
context,
|
||||
self.properties.EXP_OBS_SELECTED,
|
||||
self.properties.EXP_MESH,
|
||||
self.properties.EXP_MESH_APPLY_MOD,
|
||||
# self.properties.EXP_MESH_HQ_NORMALS,
|
||||
self.properties.EXP_ARMATURE,
|
||||
self.properties.EXP_LAMP,
|
||||
self.properties.EXP_CAMERA,
|
||||
self.properties.EXP_EMPTY,
|
||||
self.properties.EXP_IMAGE_COPY,
|
||||
GLOBAL_MATRIX,
|
||||
self.properties.ANIM_ENABLE,
|
||||
self.properties.ANIM_OPTIMIZE,
|
||||
self.properties.ANIM_OPTIMIZE_PRECISSION,
|
||||
self.properties.ANIM_ACTION_ALL,
|
||||
self.properties.BATCH_ENABLE,
|
||||
self.properties.BATCH_GROUP,
|
||||
self.properties.BATCH_FILE_PREFIX,
|
||||
self.properties.BATCH_OWN_DIR,
|
||||
)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# bpy.ops.EXPORT_OT_ply(filepath="/tmp/test.ply")
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# NOTES (all line numbers correspond to original export_fbx.py (under release/scripts)
|
||||
@@ -3111,21 +3004,3 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
|
||||
# - bpy.sys.time move to bpy.sys.util?
|
||||
# - new scene creation, activation: lines 327-342, 368
|
||||
# - uses bpy.path.abspath, *.relpath - replace at least relpath
|
||||
|
||||
# SMALL or COSMETICAL
|
||||
# - find a way to get blender version, and put it in bpy.util?, old was Blender.Get('version')
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX (.fbx)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_export.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_export.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
||||
144
release/scripts/op/io_scene_obj/__init__.py
Normal file
144
release/scripts/op/io_scene_obj/__init__.py
Normal file
@@ -0,0 +1,144 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
# To support reload properly, try to access a package var, if it's there, reload everything
|
||||
if "bpy" in locals():
|
||||
# only reload if we alredy loaded, highly annoying
|
||||
import sys
|
||||
reload(sys.modules.get("io_scene_obj.import_obj", sys))
|
||||
reload(sys.modules.get("io_scene_obj.export_obj", sys))
|
||||
|
||||
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
from io_utils import ExportHelper, ImportHelper
|
||||
|
||||
|
||||
class ImportOBJ(bpy.types.Operator, ImportHelper):
|
||||
'''Load a Wavefront OBJ File'''
|
||||
bl_idname = "import_scene.obj"
|
||||
bl_label = "Import OBJ"
|
||||
|
||||
filename_ext = ".obj"
|
||||
|
||||
CREATE_SMOOTH_GROUPS = BoolProperty(name="Smooth Groups", description="Surround smooth groups by sharp edges", default= True)
|
||||
CREATE_FGONS = BoolProperty(name="NGons as FGons", description="Import faces with more then 4 verts as fgons", default= True)
|
||||
CREATE_EDGES = BoolProperty(name="Lines as Edges", description="Import lines and faces with 2 verts as edge", default= True)
|
||||
SPLIT_OBJECTS = BoolProperty(name="Object", description="Import OBJ Objects into Blender Objects", default= True)
|
||||
SPLIT_GROUPS = BoolProperty(name="Group", description="Import OBJ Groups into Blender Objects", default= True)
|
||||
# old comment: only used for user feedback
|
||||
# disabled this option because in old code a handler for it disabled SPLIT* params, it's not passed to load_obj
|
||||
# KEEP_VERT_ORDER = BoolProperty(name="Keep Vert Order", description="Keep vert and face order, disables split options, enable for morph targets", default= True)
|
||||
ROTATE_X90 = BoolProperty(name="-X90", description="Rotate X 90.", default= True)
|
||||
CLAMP_SIZE = FloatProperty(name="Clamp Scale", description="Clamp the size to this maximum (Zero to Disable)", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=0.0)
|
||||
POLYGROUPS = BoolProperty(name="Poly Groups", description="Import OBJ groups as vertex groups.", default= True)
|
||||
IMAGE_SEARCH = BoolProperty(name="Image Search", description="Search subdirs for any assosiated images (Warning, may be slow)", default= True)
|
||||
|
||||
|
||||
def execute(self, context):
|
||||
# print("Selected: " + context.active_object.name)
|
||||
import io_scene_obj.import_obj
|
||||
return io_scene_obj.import_obj.load(self, context, **self.properties)
|
||||
'''
|
||||
load_obj(self.properties.filepath,
|
||||
context,
|
||||
self.properties.CLAMP_SIZE,
|
||||
self.properties.CREATE_FGONS,
|
||||
self.properties.CREATE_SMOOTH_GROUPS,
|
||||
self.properties.CREATE_EDGES,
|
||||
self.properties.SPLIT_OBJECTS,
|
||||
self.properties.SPLIT_GROUPS,
|
||||
self.properties.ROTATE_X90,
|
||||
self.properties.IMAGE_SEARCH,
|
||||
self.properties.POLYGROUPS)
|
||||
'''
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class ExportOBJ(bpy.types.Operator, ExportHelper):
|
||||
'''Save a Wavefront OBJ File'''
|
||||
|
||||
bl_idname = "export_scene.obj"
|
||||
bl_label = 'Export OBJ'
|
||||
|
||||
filename_ext = ".obj"
|
||||
|
||||
# List of operator properties, the attributes will be assigned
|
||||
# to the class instance from the operator settings before calling.
|
||||
|
||||
# context group
|
||||
use_selection = BoolProperty(name="Selection Only", description="Export selected objects only", default= False)
|
||||
use_all_scenes = BoolProperty(name="All Scenes", description="", default= False)
|
||||
use_animation = BoolProperty(name="Animation", description="", default= False)
|
||||
|
||||
# object group
|
||||
use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply modifiers (preview resolution)", default= True)
|
||||
use_rotate_x90 = BoolProperty(name="Rotate X90", description="", default= True)
|
||||
|
||||
# extra data group
|
||||
use_edges = BoolProperty(name="Edges", description="", default=True)
|
||||
use_normals = BoolProperty(name="Normals", description="", default=False)
|
||||
use_hq_normals = BoolProperty(name="High Quality Normals", description="", default=True)
|
||||
use_uvs = BoolProperty(name="UVs", description="", default= True)
|
||||
use_materials = BoolProperty(name="Materials", description="", default=True)
|
||||
copy_images = BoolProperty(name="Copy Images", description="", default=False)
|
||||
use_triangles = BoolProperty(name="Triangulate", description="", default=False)
|
||||
use_vertex_groups = BoolProperty(name="Polygroups", description="", default=False)
|
||||
use_nurbs = BoolProperty(name="Nurbs", description="", default=False)
|
||||
|
||||
# grouping group
|
||||
use_blen_objects = BoolProperty(name="Objects as OBJ Objects", description="", default= True)
|
||||
group_by_object = BoolProperty(name="Objects as OBJ Groups ", description="", default= False)
|
||||
group_by_material = BoolProperty(name="Material Groups", description="", default= False)
|
||||
keep_vertex_order = BoolProperty(name="Keep Vertex Order", description="", default= False)
|
||||
|
||||
|
||||
def execute(self, context):
|
||||
import io_scene_obj.export_obj
|
||||
print(self.properties.keys())
|
||||
return io_scene_obj.export_obj.save(self, context, **self.properties)
|
||||
|
||||
|
||||
def menu_func_import(self, context):
|
||||
self.layout.operator(ImportOBJ.bl_idname, text="Wavefront (.obj)")
|
||||
|
||||
|
||||
def menu_func_export(self, context):
|
||||
self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_import.append(menu_func_import)
|
||||
bpy.types.INFO_MT_file_export.append(menu_func_export)
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_import.remove(menu_func_import)
|
||||
bpy.types.INFO_MT_file_export.remove(menu_func_export)
|
||||
|
||||
|
||||
# CONVERSION ISSUES
|
||||
# - matrix problem
|
||||
# - duplis - only tested dupliverts
|
||||
# - all scenes export
|
||||
# + normals calculation
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
@@ -734,7 +734,8 @@ def write_file(filepath, objects, scene,
|
||||
|
||||
print("OBJ Export time: %.2f" % (time.clock() - time1))
|
||||
|
||||
def write(filepath, context,
|
||||
#
|
||||
def _write(context, filepath,
|
||||
EXPORT_TRI, # ok
|
||||
EXPORT_EDGES,
|
||||
EXPORT_NORMALS, # not yet
|
||||
@@ -760,7 +761,7 @@ def write(filepath, context,
|
||||
orig_scene = context.scene
|
||||
|
||||
# Exit edit mode before exporting, so current object states are exported properly.
|
||||
if context.object:
|
||||
if bpy.ops.object.mode_set.poll():
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# if EXPORT_ALL_SCENES:
|
||||
@@ -831,98 +832,51 @@ def write(filepath, context,
|
||||
|
||||
'''
|
||||
Currently the exporter lacks these features:
|
||||
* nurbs
|
||||
* multiple scene export (only active scene is written)
|
||||
* particles
|
||||
'''
|
||||
|
||||
from bpy.props import *
|
||||
from io_utils import ExportHelper
|
||||
|
||||
def save(operator, context, filepath="",
|
||||
use_triangles=False,
|
||||
use_edges=False,
|
||||
use_normals=False,
|
||||
use_hq_normals=False,
|
||||
use_uvs=True,
|
||||
use_materials=True,
|
||||
copy_images=False,
|
||||
use_modifiers=True,
|
||||
use_rotate_x90=True,
|
||||
use_blen_objects=True,
|
||||
group_by_object=False,
|
||||
group_by_material=False,
|
||||
keep_vertex_order=False,
|
||||
use_vertex_groups=False,
|
||||
use_nurbs=True,
|
||||
use_selection=True,
|
||||
use_all_scenes=False,
|
||||
use_animation=False,
|
||||
):
|
||||
|
||||
class ExportOBJ(bpy.types.Operator, ExportHelper):
|
||||
'''Save a Wavefront OBJ File'''
|
||||
_write(context, filepath,
|
||||
EXPORT_TRI=use_triangles,
|
||||
EXPORT_EDGES=use_edges,
|
||||
EXPORT_NORMALS=use_normals,
|
||||
EXPORT_NORMALS_HQ=use_hq_normals,
|
||||
EXPORT_UV=use_uvs,
|
||||
EXPORT_MTL=use_materials,
|
||||
EXPORT_COPY_IMAGES=copy_images,
|
||||
EXPORT_APPLY_MODIFIERS=use_modifiers,
|
||||
EXPORT_ROTX90=use_rotate_x90,
|
||||
EXPORT_BLEN_OBS=use_blen_objects,
|
||||
EXPORT_GROUP_BY_OB=group_by_object,
|
||||
EXPORT_GROUP_BY_MAT=group_by_material,
|
||||
EXPORT_KEEP_VERT_ORDER=keep_vertex_order,
|
||||
EXPORT_POLYGROUPS=use_vertex_groups,
|
||||
EXPORT_CURVE_AS_NURBS=use_nurbs,
|
||||
EXPORT_SEL_ONLY=use_selection,
|
||||
EXPORT_ALL_SCENES=use_all_scenes,
|
||||
EXPORT_ANIMATION=use_animation,
|
||||
)
|
||||
|
||||
bl_idname = "export.obj"
|
||||
bl_label = 'Export OBJ'
|
||||
|
||||
filename_ext = ".obj"
|
||||
|
||||
# List of operator properties, the attributes will be assigned
|
||||
# to the class instance from the operator settings before calling.
|
||||
|
||||
# context group
|
||||
use_selection = BoolProperty(name="Selection Only", description="Export selected objects only", default= False)
|
||||
use_all_scenes = BoolProperty(name="All Scenes", description="", default= False)
|
||||
use_animation = BoolProperty(name="Animation", description="", default= False)
|
||||
|
||||
# object group
|
||||
use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply modifiers (preview resolution)", default= True)
|
||||
use_rotate90 = BoolProperty(name="Rotate X90", description="", default= True)
|
||||
|
||||
# extra data group
|
||||
use_edges = BoolProperty(name="Edges", description="", default=True)
|
||||
use_normals = BoolProperty(name="Normals", description="", default=False)
|
||||
use_hq_normals = BoolProperty(name="High Quality Normals", description="", default=True)
|
||||
use_uvs = BoolProperty(name="UVs", description="", default= True)
|
||||
use_materials = BoolProperty(name="Materials", description="", default=True)
|
||||
copy_images = BoolProperty(name="Copy Images", description="", default=False)
|
||||
use_triangles = BoolProperty(name="Triangulate", description="", default=False)
|
||||
use_vertex_groups = BoolProperty(name="Polygroups", description="", default=False)
|
||||
use_nurbs = BoolProperty(name="Nurbs", description="", default=False)
|
||||
|
||||
# grouping group
|
||||
use_blen_objects = BoolProperty(name="Objects as OBJ Objects", description="", default= True)
|
||||
group_by_object = BoolProperty(name="Objects as OBJ Groups ", description="", default= False)
|
||||
group_by_material = BoolProperty(name="Material Groups", description="", default= False)
|
||||
keep_vertex_order = BoolProperty(name="Keep Vertex Order", description="", default= False)
|
||||
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
filepath = self.properties.filepath
|
||||
filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
|
||||
|
||||
write(filepath, context,
|
||||
EXPORT_TRI=self.properties.use_triangles,
|
||||
EXPORT_EDGES=self.properties.use_edges,
|
||||
EXPORT_NORMALS=self.properties.use_normals,
|
||||
EXPORT_NORMALS_HQ=self.properties.use_hq_normals,
|
||||
EXPORT_UV=self.properties.use_uvs,
|
||||
EXPORT_MTL=self.properties.use_materials,
|
||||
EXPORT_COPY_IMAGES=self.properties.copy_images,
|
||||
EXPORT_APPLY_MODIFIERS=self.properties.use_modifiers,
|
||||
EXPORT_ROTX90=self.properties.use_rotate90,
|
||||
EXPORT_BLEN_OBS=self.properties.use_blen_objects,
|
||||
EXPORT_GROUP_BY_OB=self.properties.group_by_object,
|
||||
EXPORT_GROUP_BY_MAT=self.properties.group_by_material,
|
||||
EXPORT_KEEP_VERT_ORDER=self.properties.keep_vertex_order,
|
||||
EXPORT_POLYGROUPS=self.properties.use_vertex_groups,
|
||||
EXPORT_CURVE_AS_NURBS=self.properties.use_nurbs,
|
||||
EXPORT_SEL_ONLY=self.properties.use_selection,
|
||||
EXPORT_ALL_SCENES=self.properties.use_all_scenes,
|
||||
EXPORT_ANIMATION=self.properties.use_animation)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_export.append(menu_func)
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_export.remove(menu_func)
|
||||
|
||||
|
||||
# CONVERSION ISSUES
|
||||
# - matrix problem
|
||||
# - duplis - only tested dupliverts
|
||||
# - NURBS - needs API additions
|
||||
# - all scenes export
|
||||
# + normals calculation
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
return {'FINISHED'}
|
||||
|
||||
@@ -36,30 +36,8 @@ import time
|
||||
import bpy
|
||||
import mathutils
|
||||
from geometry import PolyFill
|
||||
from io_utils import load_image, unpack_list, unpack_face_list
|
||||
|
||||
def unpack_list(list_of_tuples):
|
||||
l = []
|
||||
for t in list_of_tuples:
|
||||
l.extend(t)
|
||||
return l
|
||||
|
||||
# same as above except that it adds 0 for triangle faces
|
||||
def unpack_face_list(list_of_tuples):
|
||||
# allocate the entire list
|
||||
flat_ls = [0] * (len(list_of_tuples) * 4)
|
||||
i = 0
|
||||
|
||||
for t in list_of_tuples:
|
||||
if len(t) == 3:
|
||||
if t[2] == 0:
|
||||
t = t[1], t[2], t[0]
|
||||
else: # assuem quad
|
||||
if t[3] == 0 or t[2] == 0:
|
||||
t = t[2], t[3], t[0], t[1]
|
||||
|
||||
flat_ls[i:i + len(t)] = t
|
||||
i += 4
|
||||
return flat_ls
|
||||
|
||||
def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True):
|
||||
'''
|
||||
@@ -260,21 +238,6 @@ def line_value(line_split):
|
||||
elif length > 2:
|
||||
return ' '.join( line_split[1:] )
|
||||
|
||||
# limited replacement for BPyImage.comprehensiveImageLoad
|
||||
def load_image(imagepath, dirname):
|
||||
|
||||
if os.path.exists(imagepath):
|
||||
return bpy.data.images.load(imagepath)
|
||||
|
||||
variants = [imagepath, os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))]
|
||||
|
||||
for filepath in variants:
|
||||
for nfilepath in (filepath, bpy.path.resolve_ncase(filepath)):
|
||||
if os.path.exists(nfilepath):
|
||||
return bpy.data.images.load(nfilepath)
|
||||
|
||||
# TODO comprehensiveImageLoad also searched in bpy.config.textureDir
|
||||
return None
|
||||
|
||||
def obj_image_load(imagepath, DIR, IMAGE_SEARCH):
|
||||
if '_' in imagepath:
|
||||
@@ -874,17 +837,16 @@ def get_float_func(filepath):
|
||||
# incase all vert values were ints
|
||||
return float
|
||||
|
||||
def load_obj(filepath,
|
||||
context,
|
||||
CLAMP_SIZE= 0.0,
|
||||
CREATE_FGONS= True,
|
||||
CREATE_SMOOTH_GROUPS= True,
|
||||
CREATE_EDGES= True,
|
||||
SPLIT_OBJECTS= True,
|
||||
SPLIT_GROUPS= True,
|
||||
ROTATE_X90= True,
|
||||
IMAGE_SEARCH=True,
|
||||
POLYGROUPS=False):
|
||||
def load(operator, context, filepath,
|
||||
CLAMP_SIZE= 0.0,
|
||||
CREATE_FGONS= True,
|
||||
CREATE_SMOOTH_GROUPS= True,
|
||||
CREATE_EDGES= True,
|
||||
SPLIT_OBJECTS= True,
|
||||
SPLIT_GROUPS= True,
|
||||
ROTATE_X90= True,
|
||||
IMAGE_SEARCH=True,
|
||||
POLYGROUPS=False):
|
||||
'''
|
||||
Called by the user interface or another script.
|
||||
load_obj(path) - should give acceptable results.
|
||||
@@ -1218,295 +1180,8 @@ def load_obj(filepath,
|
||||
time_new= time.time()
|
||||
# time_new= sys.time()
|
||||
|
||||
print('%.4f sec' % (time_new-time_sub))
|
||||
print('finished importing: %r in %.4f sec.' % (filepath, (time_new-time_main)))
|
||||
|
||||
|
||||
DEBUG= True
|
||||
|
||||
|
||||
def load_obj_ui(filepath, BATCH_LOAD= False):
|
||||
if BPyMessages.Error_NoFile(filepath):
|
||||
return
|
||||
|
||||
global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90
|
||||
|
||||
CREATE_SMOOTH_GROUPS= Draw.Create(0)
|
||||
CREATE_FGONS= Draw.Create(1)
|
||||
CREATE_EDGES= Draw.Create(1)
|
||||
SPLIT_OBJECTS= Draw.Create(0)
|
||||
SPLIT_GROUPS= Draw.Create(0)
|
||||
CLAMP_SIZE= Draw.Create(10.0)
|
||||
IMAGE_SEARCH= Draw.Create(1)
|
||||
POLYGROUPS= Draw.Create(0)
|
||||
KEEP_VERT_ORDER= Draw.Create(1)
|
||||
ROTATE_X90= Draw.Create(1)
|
||||
|
||||
|
||||
# Get USER Options
|
||||
# Note, Works but not pretty, instead use a more complicated GUI
|
||||
'''
|
||||
pup_block= [\
|
||||
'Import...',\
|
||||
('Smooth Groups', CREATE_SMOOTH_GROUPS, 'Surround smooth groups by sharp edges'),\
|
||||
('Create FGons', CREATE_FGONS, 'Import faces with more then 4 verts as fgons.'),\
|
||||
('Lines', CREATE_EDGES, 'Import lines and faces with 2 verts as edges'),\
|
||||
'Separate objects from obj...',\
|
||||
('Object', SPLIT_OBJECTS, 'Import OBJ Objects into Blender Objects'),\
|
||||
('Group', SPLIT_GROUPS, 'Import OBJ Groups into Blender Objects'),\
|
||||
'Options...',\
|
||||
('Keep Vert Order', KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\
|
||||
('Clamp Scale:', CLAMP_SIZE, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)'),\
|
||||
('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\
|
||||
]
|
||||
|
||||
if not Draw.PupBlock('Import OBJ...', pup_block):
|
||||
return
|
||||
|
||||
if KEEP_VERT_ORDER.val:
|
||||
SPLIT_OBJECTS.val = False
|
||||
SPLIT_GROUPS.val = False
|
||||
'''
|
||||
|
||||
|
||||
|
||||
# BEGIN ALTERNATIVE UI *******************
|
||||
if True:
|
||||
|
||||
EVENT_NONE = 0
|
||||
EVENT_EXIT = 1
|
||||
EVENT_REDRAW = 2
|
||||
EVENT_IMPORT = 3
|
||||
|
||||
GLOBALS = {}
|
||||
GLOBALS['EVENT'] = EVENT_REDRAW
|
||||
#GLOBALS['MOUSE'] = Window.GetMouseCoords()
|
||||
GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()]
|
||||
|
||||
def obj_ui_set_event(e,v):
|
||||
GLOBALS['EVENT'] = e
|
||||
|
||||
def do_split(e,v):
|
||||
global SPLIT_OBJECTS, SPLIT_GROUPS, KEEP_VERT_ORDER, POLYGROUPS
|
||||
if SPLIT_OBJECTS.val or SPLIT_GROUPS.val:
|
||||
KEEP_VERT_ORDER.val = 0
|
||||
POLYGROUPS.val = 0
|
||||
else:
|
||||
KEEP_VERT_ORDER.val = 1
|
||||
|
||||
def do_vertorder(e,v):
|
||||
global SPLIT_OBJECTS, SPLIT_GROUPS, KEEP_VERT_ORDER
|
||||
if KEEP_VERT_ORDER.val:
|
||||
SPLIT_OBJECTS.val = SPLIT_GROUPS.val = 0
|
||||
else:
|
||||
if not (SPLIT_OBJECTS.val or SPLIT_GROUPS.val):
|
||||
KEEP_VERT_ORDER.val = 1
|
||||
|
||||
def do_polygroups(e,v):
|
||||
global SPLIT_OBJECTS, SPLIT_GROUPS, KEEP_VERT_ORDER, POLYGROUPS
|
||||
if POLYGROUPS.val:
|
||||
SPLIT_OBJECTS.val = SPLIT_GROUPS.val = 0
|
||||
|
||||
def do_help(e,v):
|
||||
url = __url__[0]
|
||||
print('Trying to open web browser with documentation at this address...')
|
||||
print('\t' + url)
|
||||
|
||||
try:
|
||||
import webbrowser
|
||||
webbrowser.open(url)
|
||||
except:
|
||||
print('...could not open a browser window.')
|
||||
|
||||
def obj_ui():
|
||||
ui_x, ui_y = GLOBALS['MOUSE']
|
||||
|
||||
# Center based on overall pup size
|
||||
ui_x -= 165
|
||||
ui_y -= 90
|
||||
|
||||
global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90
|
||||
|
||||
Draw.Label('Import...', ui_x+9, ui_y+159, 220, 21)
|
||||
Draw.BeginAlign()
|
||||
CREATE_SMOOTH_GROUPS = Draw.Toggle('Smooth Groups', EVENT_NONE, ui_x+9, ui_y+139, 110, 20, CREATE_SMOOTH_GROUPS.val, 'Surround smooth groups by sharp edges')
|
||||
CREATE_FGONS = Draw.Toggle('NGons as FGons', EVENT_NONE, ui_x+119, ui_y+139, 110, 20, CREATE_FGONS.val, 'Import faces with more then 4 verts as fgons')
|
||||
CREATE_EDGES = Draw.Toggle('Lines as Edges', EVENT_NONE, ui_x+229, ui_y+139, 110, 20, CREATE_EDGES.val, 'Import lines and faces with 2 verts as edges')
|
||||
Draw.EndAlign()
|
||||
|
||||
Draw.Label('Separate objects by OBJ...', ui_x+9, ui_y+110, 220, 20)
|
||||
Draw.BeginAlign()
|
||||
SPLIT_OBJECTS = Draw.Toggle('Object', EVENT_REDRAW, ui_x+9, ui_y+89, 55, 21, SPLIT_OBJECTS.val, 'Import OBJ Objects into Blender Objects', do_split)
|
||||
SPLIT_GROUPS = Draw.Toggle('Group', EVENT_REDRAW, ui_x+64, ui_y+89, 55, 21, SPLIT_GROUPS.val, 'Import OBJ Groups into Blender Objects', do_split)
|
||||
Draw.EndAlign()
|
||||
|
||||
# Only used for user feedback
|
||||
KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+184, ui_y+89, 113, 21, KEEP_VERT_ORDER.val, 'Keep vert and face order, disables split options, enable for morph targets', do_vertorder)
|
||||
|
||||
ROTATE_X90 = Draw.Toggle('-X90', EVENT_REDRAW, ui_x+302, ui_y+89, 38, 21, ROTATE_X90.val, 'Rotate X 90.')
|
||||
|
||||
Draw.Label('Options...', ui_x+9, ui_y+60, 211, 20)
|
||||
CLAMP_SIZE = Draw.Number('Clamp Scale: ', EVENT_NONE, ui_x+9, ui_y+39, 130, 21, CLAMP_SIZE.val, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)')
|
||||
POLYGROUPS = Draw.Toggle('Poly Groups', EVENT_REDRAW, ui_x+144, ui_y+39, 90, 21, POLYGROUPS.val, 'Import OBJ groups as vertex groups.', do_polygroups)
|
||||
IMAGE_SEARCH = Draw.Toggle('Image Search', EVENT_NONE, ui_x+239, ui_y+39, 100, 21, IMAGE_SEARCH.val, 'Search subdirs for any assosiated images (Warning, may be slow)')
|
||||
Draw.BeginAlign()
|
||||
Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 21, 'Load the wiki page for this script', do_help)
|
||||
Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 21, '', obj_ui_set_event)
|
||||
Draw.PushButton('Import', EVENT_IMPORT, ui_x+229, ui_y+9, 110, 21, 'Import with these settings', obj_ui_set_event)
|
||||
Draw.EndAlign()
|
||||
|
||||
|
||||
# hack so the toggle buttons redraw. this is not nice at all
|
||||
while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_IMPORT):
|
||||
Draw.UIBlock(obj_ui, 0)
|
||||
|
||||
if GLOBALS['EVENT'] != EVENT_IMPORT:
|
||||
return
|
||||
|
||||
# END ALTERNATIVE UI *********************
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Window.WaitCursor(1)
|
||||
|
||||
if BATCH_LOAD: # load the dir
|
||||
try:
|
||||
files= [ f for f in os.listdir(filepath) if f.lower().endswith('.obj') ]
|
||||
except:
|
||||
Window.WaitCursor(0)
|
||||
Draw.PupMenu('Error%t|Could not open path ' + filepath)
|
||||
return
|
||||
|
||||
if not files:
|
||||
Window.WaitCursor(0)
|
||||
Draw.PupMenu('Error%t|No files at path ' + filepath)
|
||||
return
|
||||
|
||||
for f in files:
|
||||
scn= bpy.data.scenes.new(os.path.splitext(f)[0])
|
||||
scn.makeCurrent()
|
||||
|
||||
load_obj(sys.join(filepath, f),\
|
||||
CLAMP_SIZE.val,\
|
||||
CREATE_FGONS.val,\
|
||||
CREATE_SMOOTH_GROUPS.val,\
|
||||
CREATE_EDGES.val,\
|
||||
SPLIT_OBJECTS.val,\
|
||||
SPLIT_GROUPS.val,\
|
||||
ROTATE_X90.val,\
|
||||
IMAGE_SEARCH.val,\
|
||||
POLYGROUPS.val
|
||||
)
|
||||
|
||||
else: # Normal load
|
||||
load_obj(filepath,\
|
||||
CLAMP_SIZE.val,\
|
||||
CREATE_FGONS.val,\
|
||||
CREATE_SMOOTH_GROUPS.val,\
|
||||
CREATE_EDGES.val,\
|
||||
SPLIT_OBJECTS.val,\
|
||||
SPLIT_GROUPS.val,\
|
||||
ROTATE_X90.val,\
|
||||
IMAGE_SEARCH.val,\
|
||||
POLYGROUPS.val
|
||||
)
|
||||
|
||||
Window.WaitCursor(0)
|
||||
|
||||
|
||||
def load_obj_ui_batch(file):
|
||||
load_obj_ui(file, True)
|
||||
|
||||
DEBUG= False
|
||||
|
||||
# if __name__=='__main__' and not DEBUG:
|
||||
# if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT:
|
||||
# Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '')
|
||||
# else:
|
||||
# Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj')
|
||||
|
||||
# For testing compatibility
|
||||
'''
|
||||
else:
|
||||
# DEBUG ONLY
|
||||
TIME= sys.time()
|
||||
DIR = '/fe/obj'
|
||||
import os
|
||||
print 'Searching for files'
|
||||
def fileList(path):
|
||||
for dirpath, dirnames, filenames in os.walk(path):
|
||||
for filename in filenames:
|
||||
yield os.path.join(dirpath, filename)
|
||||
|
||||
files = [f for f in fileList(DIR) if f.lower().endswith('.obj')]
|
||||
files.sort()
|
||||
|
||||
for i, obj_file in enumerate(files):
|
||||
if 0 < i < 20:
|
||||
print 'Importing', obj_file, '\nNUMBER', i, 'of', len(files)
|
||||
newScn= bpy.data.scenes.new(os.path.basename(obj_file))
|
||||
newScn.makeCurrent()
|
||||
load_obj(obj_file, False, IMAGE_SEARCH=0)
|
||||
|
||||
print 'TOTAL TIME: %.6f' % (sys.time() - TIME)
|
||||
'''
|
||||
|
||||
from bpy.props import *
|
||||
from io_utils import ImportHelper
|
||||
|
||||
|
||||
class IMPORT_OT_obj(bpy.types.Operator, ImportHelper):
|
||||
'''Load a Wavefront OBJ File'''
|
||||
bl_idname = "import_scene.obj"
|
||||
bl_label = "Import OBJ"
|
||||
|
||||
filename_ext = ".obj"
|
||||
|
||||
CREATE_SMOOTH_GROUPS = BoolProperty(name="Smooth Groups", description="Surround smooth groups by sharp edges", default= True)
|
||||
CREATE_FGONS = BoolProperty(name="NGons as FGons", description="Import faces with more then 4 verts as fgons", default= True)
|
||||
CREATE_EDGES = BoolProperty(name="Lines as Edges", description="Import lines and faces with 2 verts as edge", default= True)
|
||||
SPLIT_OBJECTS = BoolProperty(name="Object", description="Import OBJ Objects into Blender Objects", default= True)
|
||||
SPLIT_GROUPS = BoolProperty(name="Group", description="Import OBJ Groups into Blender Objects", default= True)
|
||||
# old comment: only used for user feedback
|
||||
# disabled this option because in old code a handler for it disabled SPLIT* params, it's not passed to load_obj
|
||||
# KEEP_VERT_ORDER = BoolProperty(name="Keep Vert Order", description="Keep vert and face order, disables split options, enable for morph targets", default= True)
|
||||
ROTATE_X90 = BoolProperty(name="-X90", description="Rotate X 90.", default= True)
|
||||
CLAMP_SIZE = FloatProperty(name="Clamp Scale", description="Clamp the size to this maximum (Zero to Disable)", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=0.0)
|
||||
POLYGROUPS = BoolProperty(name="Poly Groups", description="Import OBJ groups as vertex groups.", default= True)
|
||||
IMAGE_SEARCH = BoolProperty(name="Image Search", description="Search subdirs for any assosiated images (Warning, may be slow)", default= True)
|
||||
|
||||
|
||||
def execute(self, context):
|
||||
# print("Selected: " + context.active_object.name)
|
||||
|
||||
load_obj(self.properties.filepath,
|
||||
context,
|
||||
self.properties.CLAMP_SIZE,
|
||||
self.properties.CREATE_FGONS,
|
||||
self.properties.CREATE_SMOOTH_GROUPS,
|
||||
self.properties.CREATE_EDGES,
|
||||
self.properties.SPLIT_OBJECTS,
|
||||
self.properties.SPLIT_GROUPS,
|
||||
self.properties.ROTATE_X90,
|
||||
self.properties.IMAGE_SEARCH,
|
||||
self.properties.POLYGROUPS)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(IMPORT_OT_obj.bl_idname, text="Wavefront (.obj)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_import.append(menu_func)
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_import.remove(menu_func)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# NOTES (all line numbers refer to 2.4x import_obj.py, not this file)
|
||||
|
||||
61
release/scripts/op/io_scene_x3d/__init__.py
Normal file
61
release/scripts/op/io_scene_x3d/__init__.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# To support reload properly, try to access a package var, if it's there, reload everything
|
||||
if "bpy" in locals():
|
||||
# only reload if we alredy loaded, highly annoying
|
||||
import sys
|
||||
reload(sys.modules.get("io_scene_x3d.export_x3d", sys))
|
||||
|
||||
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
from io_utils import ExportHelper
|
||||
|
||||
|
||||
class ExportX3D(bpy.types.Operator, ExportHelper):
|
||||
'''Export selection to Extensible 3D file (.x3d)'''
|
||||
bl_idname = "export_scene.x3d"
|
||||
bl_label = 'Export X3D'
|
||||
|
||||
filename_ext = ".x3d"
|
||||
|
||||
use_apply_modifiers = BoolProperty(name="Apply Modifiers", description="Use transformed mesh data from each object", default=True)
|
||||
use_triangulate = BoolProperty(name="Triangulate", description="Triangulate quads.", default=False)
|
||||
use_compress = BoolProperty(name="Compress", description="GZip the resulting file, requires a full python install", default=False)
|
||||
|
||||
def execute(self, context):
|
||||
import io_scene_x3d.export_x3d
|
||||
return io_scene_x3d.export_x3d.save(self, context, **self.properties)
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_export.append(menu_func)
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_export.remove(menu_func)
|
||||
|
||||
# NOTES
|
||||
# - blender version is hardcoded
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
@@ -48,8 +48,7 @@ MATWORLD= mathutils.Matrix.Rotation(-90, 4, 'X')
|
||||
# Global Variables
|
||||
####################################
|
||||
|
||||
filename = ""
|
||||
# filename = Blender.Get('filename')
|
||||
filepath = ""
|
||||
_safeOverwrite = True
|
||||
|
||||
extension = ''
|
||||
@@ -60,7 +59,7 @@ extension = ''
|
||||
|
||||
class x3d_class:
|
||||
|
||||
def __init__(self, filename):
|
||||
def __init__(self, filepath):
|
||||
#--- public you can change these ---
|
||||
self.writingcolor = 0
|
||||
self.writingtexture = 0
|
||||
@@ -83,18 +82,18 @@ class x3d_class:
|
||||
self.matNames={} # dictionary of materiaNames
|
||||
self.meshNames={} # dictionary of meshNames
|
||||
self.indentLevel=0 # keeps track of current indenting
|
||||
self.filename=filename
|
||||
self.filepath=filepath
|
||||
self.file = None
|
||||
if filename.lower().endswith('.x3dz'):
|
||||
if filepath.lower().endswith('.x3dz'):
|
||||
try:
|
||||
import gzip
|
||||
self.file = gzip.open(filename, "w")
|
||||
self.file = gzip.open(filepath, "w")
|
||||
except:
|
||||
print("failed to import compression modules, exporting uncompressed")
|
||||
self.filename = filename[:-1] # remove trailing z
|
||||
self.filepath = filepath[:-1] # remove trailing z
|
||||
|
||||
if self.file == None:
|
||||
self.file = open(self.filename, "w")
|
||||
self.file = open(self.filepath, "w")
|
||||
|
||||
self.bNav=0
|
||||
self.nodeID=0
|
||||
@@ -136,8 +135,8 @@ class x3d_class:
|
||||
##########################################################
|
||||
|
||||
def writeHeader(self):
|
||||
#bfile = sys.expandpath( Blender.Get('filename') ).replace('<', '<').replace('>', '>')
|
||||
bfile = self.filename.replace('<', '<').replace('>', '>') # use outfile name
|
||||
#bfile = sys.expandpath( Blender.Get('filepath') ).replace('<', '<').replace('>', '>')
|
||||
bfile = self.filepath.replace('<', '<').replace('>', '>') # use outfile name
|
||||
self.file.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
|
||||
self.file.write("<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.0//EN\" \"http://www.web3d.org/specifications/x3d-3.0.dtd\">\n")
|
||||
self.file.write("<X3D version=\"3.0\" profile=\"Immersive\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema-instance\" xsd:noNamespaceSchemaLocation=\"http://www.web3d.org/specifications/x3d-3.0.xsd\">\n")
|
||||
@@ -426,6 +425,7 @@ class x3d_class:
|
||||
self.writeIndented("<Appearance>\n", 1)
|
||||
# right now this script can only handle a single material per mesh.
|
||||
if len(maters) >= 1 and maters[0].use_face_texture == False:
|
||||
mat = maters[0]
|
||||
self.writeMaterial(mat, self.cleanStr(mat.name,''), world)
|
||||
if len(maters) > 1:
|
||||
print("Warning: mesh named %s has multiple materials" % meshName)
|
||||
@@ -672,13 +672,13 @@ class x3d_class:
|
||||
|
||||
def writeImageTexture(self, image):
|
||||
name = image.name
|
||||
filename = os.path.basename(image.filepath)
|
||||
filepath = os.path.basename(image.filepath)
|
||||
if name in self.texNames:
|
||||
self.writeIndented("<ImageTexture USE=\"%s\" />\n" % self.cleanStr(name))
|
||||
self.texNames[name] += 1
|
||||
else:
|
||||
self.writeIndented("<ImageTexture DEF=\"%s\" " % self.cleanStr(name), 1)
|
||||
self.file.write("url=\"%s\" />" % filename)
|
||||
self.file.write("url=\"%s\" />" % filepath)
|
||||
self.writeIndented("\n",-1)
|
||||
self.texNames[name] = 1
|
||||
|
||||
@@ -781,7 +781,7 @@ class x3d_class:
|
||||
EXPORT_TRI= False,\
|
||||
):
|
||||
|
||||
print("Info: starting X3D export to " + self.filename + "...")
|
||||
print("Info: starting X3D export to " + self.filepath + "...")
|
||||
self.writeHeader()
|
||||
# self.writeScript()
|
||||
self.writeNavigationInfo(scene)
|
||||
@@ -879,7 +879,7 @@ class x3d_class:
|
||||
self.texNames={}
|
||||
self.matNames={}
|
||||
self.indentLevel=0
|
||||
print("Info: finished X3D export to %s\n" % self.filename)
|
||||
print("Info: finished X3D export to %s\n" % self.filepath)
|
||||
|
||||
def cleanStr(self, name, prefix='rsvd_'):
|
||||
"""cleanStr(name,prefix) - try to create a valid VRML DEF name from object name"""
|
||||
@@ -1089,82 +1089,35 @@ class x3d_class:
|
||||
# Callbacks, needed before Main
|
||||
##########################################################
|
||||
|
||||
def write(filename,
|
||||
context,
|
||||
EXPORT_APPLY_MODIFIERS=False,
|
||||
EXPORT_TRI=False,
|
||||
EXPORT_GZIP=False):
|
||||
def save(operator, context, filepath="",
|
||||
use_apply_modifiers=False,
|
||||
use_triangulate=False,
|
||||
use_compress=False):
|
||||
|
||||
if EXPORT_GZIP:
|
||||
if not filename.lower().endswith('.x3dz'):
|
||||
filename = '.'.join(filename.split('.')[:-1]) + '.x3dz'
|
||||
if use_compress:
|
||||
if not filepath.lower().endswith('.x3dz'):
|
||||
filepath = '.'.join(filepath.split('.')[:-1]) + '.x3dz'
|
||||
else:
|
||||
if not filename.lower().endswith('.x3d'):
|
||||
filename = '.'.join(filename.split('.')[:-1]) + '.x3d'
|
||||
|
||||
if not filepath.lower().endswith('.x3d'):
|
||||
filepath = '.'.join(filepath.split('.')[:-1]) + '.x3d'
|
||||
|
||||
scene = context.scene
|
||||
world = scene.world
|
||||
|
||||
if scene.objects.active:
|
||||
if bpy.ops.object.mode_set.poll():
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# XXX these are global textures while .Get() returned only scene's?
|
||||
alltextures = bpy.data.textures
|
||||
# alltextures = Blender.Texture.Get()
|
||||
|
||||
wrlexport=x3d_class(filename)
|
||||
wrlexport.export(\
|
||||
scene,\
|
||||
world,\
|
||||
alltextures,\
|
||||
\
|
||||
EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS,\
|
||||
EXPORT_TRI = EXPORT_TRI,\
|
||||
)
|
||||
wrlexport = x3d_class(filepath)
|
||||
wrlexport.export(scene,
|
||||
world,
|
||||
alltextures,
|
||||
EXPORT_APPLY_MODIFIERS=use_apply_modifiers,
|
||||
EXPORT_TRI=use_triangulate,
|
||||
)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
from bpy.props import *
|
||||
from io_utils import ExportHelper
|
||||
|
||||
|
||||
class ExportX3D(bpy.types.Operator, ExportHelper):
|
||||
'''Export selection to Extensible 3D file (.x3d)'''
|
||||
bl_idname = "export.x3d"
|
||||
bl_label = 'Export X3D'
|
||||
|
||||
filename_ext = ".x3d"
|
||||
|
||||
apply_modifiers = BoolProperty(name="Apply Modifiers", description="Use transformed mesh data from each object", default=True)
|
||||
triangulate = BoolProperty(name="Triangulate", description="Triangulate quads.", default=False)
|
||||
compress = BoolProperty(name="Compress", description="GZip the resulting file, requires a full python install", default=False)
|
||||
|
||||
def execute(self, context):
|
||||
filepath = self.properties.filepath
|
||||
filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
|
||||
|
||||
write(filepath,
|
||||
context,
|
||||
self.properties.apply_modifiers,
|
||||
self.properties.triangulate,
|
||||
self.properties.compress,
|
||||
)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_export.append(menu_func)
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_export.remove(menu_func)
|
||||
|
||||
# NOTES
|
||||
# - blender version is hardcoded
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
||||
115
release/scripts/op/io_shape_mdd/__init__.py
Normal file
115
release/scripts/op/io_shape_mdd/__init__.py
Normal file
@@ -0,0 +1,115 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
# To support reload properly, try to access a package var, if it's there, reload everything
|
||||
if "bpy" in locals():
|
||||
# only reload if we alredy loaded, highly annoying
|
||||
import sys
|
||||
reload(sys.modules.get("io_shape_mdd.import_mdd", sys))
|
||||
reload(sys.modules.get("io_shape_mdd.export_mdd", sys))
|
||||
|
||||
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
from io_utils import ExportHelper, ImportHelper
|
||||
|
||||
|
||||
class ImportMDD(bpy.types.Operator, ImportHelper):
|
||||
'''Import MDD vertex keyframe file to shape keys'''
|
||||
bl_idname = "import_shape.mdd"
|
||||
bl_label = "Import MDD"
|
||||
|
||||
filename_ext = ".mdd"
|
||||
frame_start = IntProperty(name="Start Frame", description="Start frame for inserting animation", min=-300000, max=300000, default=0)
|
||||
frame_step = IntProperty(name="Step", min=1, max=1000, default=1)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
ob = context.active_object
|
||||
return (ob and ob.type == 'MESH')
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
# initialize from scene if unset
|
||||
scene = context.scene
|
||||
if not self.properties.is_property_set("frame_start"):
|
||||
self.properties.frame_start = scene.frame_current
|
||||
|
||||
import io_shape_mdd.import_mdd
|
||||
return io_shape_mdd.import_mdd.load(self, context, **self.properties)
|
||||
|
||||
class ExportMDD(bpy.types.Operator, ExportHelper):
|
||||
'''Animated mesh to MDD vertex keyframe file'''
|
||||
bl_idname = "export_shape.mdd"
|
||||
bl_label = "Export MDD"
|
||||
|
||||
filename_ext = ".mdd"
|
||||
|
||||
# get first scene to get min and max properties for frames, fps
|
||||
|
||||
minframe = 1
|
||||
maxframe = 300000
|
||||
minfps = 1
|
||||
maxfps = 120
|
||||
|
||||
# List of operator properties, the attributes will be assigned
|
||||
# to the class instance from the operator settings before calling.
|
||||
fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default=25)
|
||||
frame_start = IntProperty(name="Start Frame", description="Start frame for baking", min=minframe, max=maxframe, default=1)
|
||||
frame_end = IntProperty(name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default=250)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
obj = context.active_object
|
||||
return (obj and obj.type == 'MESH')
|
||||
|
||||
def execute(self, context):
|
||||
# initialize from scene if unset
|
||||
scene = context.scene
|
||||
if not self.properties.is_property_set("frame_start"):
|
||||
self.properties.frame_start = scene.frame_start
|
||||
if not self.properties.is_property_set("frame_end"):
|
||||
self.properties.frame_end = scene.frame_end
|
||||
if not self.properties.is_property_set("fps"):
|
||||
self.properties.fps = scene.render.fps
|
||||
|
||||
import io_shape_mdd.export_mdd
|
||||
return io_shape_mdd.export_mdd.save(self, context, **self.properties)
|
||||
|
||||
|
||||
def menu_func_import(self, context):
|
||||
self.layout.operator(ImportMDD.bl_idname, text="Lightwave Point Cache (.mdd)")
|
||||
|
||||
|
||||
def menu_func_export(self, context):
|
||||
self.layout.operator(ExportMDD.bl_idname, text="Lightwave Point Cache (.mdd)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_import.append(menu_func_import)
|
||||
bpy.types.INFO_MT_file_export.append(menu_func_export)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_import.remove(menu_func_import)
|
||||
bpy.types.INFO_MT_file_export.remove(menu_func_export)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
@@ -54,19 +54,23 @@ def check_vertcount(mesh, vertcount):
|
||||
return
|
||||
|
||||
|
||||
def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
|
||||
def save(operator, context, filepath="", frame_start=1, frame_end=300, fps=25):
|
||||
"""
|
||||
Blender.Window.WaitCursor(1)
|
||||
|
||||
mesh_orig = Mesh.New()
|
||||
mesh_orig.getFromObject(ob.name)
|
||||
mesh_orig.getFromObject(obj.name)
|
||||
"""
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
scene = context.scene
|
||||
obj = context.object
|
||||
|
||||
orig_frame = sce.frame_current
|
||||
sce.set_frame(PREF_STARTFRAME)
|
||||
me = ob.create_mesh(sce, True, 'PREVIEW')
|
||||
if bpy.ops.object.mode_set.poll():
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
orig_frame = scene.frame_current
|
||||
scene.set_frame(frame_start)
|
||||
me = obj.create_mesh(scene, True, 'PREVIEW')
|
||||
|
||||
#Flip y and z
|
||||
mat_flip = mathutils.Matrix(\
|
||||
@@ -78,36 +82,36 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
|
||||
|
||||
numverts = len(me.vertices)
|
||||
|
||||
numframes = PREF_ENDFRAME - PREF_STARTFRAME + 1
|
||||
PREF_FPS = float(PREF_FPS)
|
||||
f = open(filename, 'wb') #no Errors yet:Safe to create file
|
||||
numframes = frame_end - frame_start + 1
|
||||
fps = float(fps)
|
||||
f = open(filepath, 'wb') #no Errors yet:Safe to create file
|
||||
|
||||
# Write the header
|
||||
f.write(pack(">2i", numframes, numverts))
|
||||
|
||||
# Write the frame times (should we use the time IPO??)
|
||||
f.write(pack(">%df" % (numframes), *[frame / PREF_FPS for frame in range(numframes)])) # seconds
|
||||
f.write(pack(">%df" % (numframes), *[frame / fps for frame in range(numframes)])) # seconds
|
||||
|
||||
#rest frame needed to keep frames in sync
|
||||
"""
|
||||
Blender.Set('curframe', PREF_STARTFRAME)
|
||||
me_tmp.getFromObject(ob.name)
|
||||
Blender.Set('curframe', frame_start)
|
||||
me_tmp.getFromObject(obj.name)
|
||||
"""
|
||||
|
||||
check_vertcount(me, numverts)
|
||||
me.transform(mat_flip * ob.matrix_world)
|
||||
me.transform(mat_flip * obj.matrix_world)
|
||||
f.write(pack(">%df" % (numverts * 3), *[axis for v in me.vertices for axis in v.co]))
|
||||
|
||||
for frame in range(PREF_STARTFRAME, PREF_ENDFRAME + 1):#in order to start at desired frame
|
||||
for frame in range(frame_start, frame_end + 1):#in order to start at desired frame
|
||||
"""
|
||||
Blender.Set('curframe', frame)
|
||||
me_tmp.getFromObject(ob.name)
|
||||
me_tmp.getFromObject(obj.name)
|
||||
"""
|
||||
|
||||
sce.set_frame(frame)
|
||||
me = ob.create_mesh(sce, True, 'PREVIEW')
|
||||
scene.set_frame(frame)
|
||||
me = obj.create_mesh(scene, True, 'PREVIEW')
|
||||
check_vertcount(me, numverts)
|
||||
me.transform(mat_flip * ob.matrix_world)
|
||||
me.transform(mat_flip * obj.matrix_world)
|
||||
|
||||
# Write the vertex data
|
||||
f.write(pack(">%df" % (numverts * 3), *[axis for v in me.vertices for axis in v.co]))
|
||||
@@ -117,67 +121,11 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
|
||||
"""
|
||||
f.close()
|
||||
|
||||
print('MDD Exported: %s frames:%d\n' % (filename, numframes - 1))
|
||||
print('MDD Exported: %r frames:%d\n' % (filepath, numframes - 1))
|
||||
"""
|
||||
Blender.Window.WaitCursor(0)
|
||||
Blender.Set('curframe', orig_frame)
|
||||
"""
|
||||
sce.set_frame(orig_frame)
|
||||
|
||||
from bpy.props import *
|
||||
from io_utils import ExportHelper
|
||||
|
||||
|
||||
class ExportMDD(bpy.types.Operator, ExportHelper):
|
||||
'''Animated mesh to MDD vertex keyframe file'''
|
||||
bl_idname = "export.mdd"
|
||||
bl_label = "Export MDD"
|
||||
scene.set_frame(orig_frame)
|
||||
|
||||
filename_ext = ".mdd"
|
||||
|
||||
# get first scene to get min and max properties for frames, fps
|
||||
|
||||
minframe = 1
|
||||
maxframe = 300000
|
||||
minfps = 1
|
||||
maxfps = 120
|
||||
|
||||
# List of operator properties, the attributes will be assigned
|
||||
# to the class instance from the operator settings before calling.
|
||||
fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default=25)
|
||||
frame_start = IntProperty(name="Start Frame", description="Start frame for baking", min=minframe, max=maxframe, default=1)
|
||||
frame_end = IntProperty(name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default=250)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
ob = context.active_object
|
||||
return (ob and ob.type == 'MESH')
|
||||
|
||||
def execute(self, context):
|
||||
filepath = self.properties.filepath
|
||||
filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
|
||||
|
||||
write(filepath,
|
||||
context.scene,
|
||||
context.active_object,
|
||||
self.properties.frame_start,
|
||||
self.properties.frame_end,
|
||||
self.properties.fps,
|
||||
)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(ExportMDD.bl_idname, text="Lightwave Point Cache (.mdd)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_export.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_export.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
return {'FINISHED'}
|
||||
|
||||
@@ -35,11 +35,15 @@ import bpy
|
||||
from struct import unpack
|
||||
|
||||
|
||||
def mdd_import(filepath, ob, scene, PREF_START_FRAME=0, PREF_JUMP=1):
|
||||
def load(operator, context, filepath, frame_start=0, frame_step=1):
|
||||
|
||||
scene = context.scene
|
||||
obj = context.object
|
||||
|
||||
print('\n\nimporting mdd %r' % filepath)
|
||||
|
||||
print('\n\nimporting mdd "%s"' % filepath)
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
if bpy.ops.object.mode_set.poll():
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
file = open(filepath, 'rb')
|
||||
frames, points = unpack(">2i", file.read(8))
|
||||
@@ -49,92 +53,53 @@ def mdd_import(filepath, ob, scene, PREF_START_FRAME=0, PREF_JUMP=1):
|
||||
|
||||
# If target object doesn't have Basis shape key, create it.
|
||||
try:
|
||||
num_keys = len(ob.data.shape_keys.keys)
|
||||
num_keys = len(obj.data.shape_keys.keys)
|
||||
except:
|
||||
basis = ob.add_shape_key()
|
||||
basis = obj.add_shape_key()
|
||||
basis.name = "Basis"
|
||||
ob.data.update()
|
||||
obj.data.update()
|
||||
|
||||
scene.frame_current = PREF_START_FRAME
|
||||
scene.frame_current = frame_start
|
||||
|
||||
def UpdateMesh(ob, fr):
|
||||
|
||||
# Insert new shape key
|
||||
new_shapekey = ob.add_shape_key()
|
||||
new_shapekey = obj.add_shape_key()
|
||||
new_shapekey.name = ("frame_%.4d" % fr)
|
||||
new_shapekey_name = new_shapekey.name
|
||||
|
||||
ob.active_shape_key_index = len(ob.data.shape_keys.keys)-1
|
||||
index = len(ob.data.shape_keys.keys)-1
|
||||
ob.show_shape_key = True
|
||||
obj.active_shape_key_index = len(obj.data.shape_keys.keys)-1
|
||||
index = len(obj.data.shape_keys.keys)-1
|
||||
obj.show_shape_key = True
|
||||
|
||||
verts = ob.data.shape_keys.keys[len(ob.data.shape_keys.keys)-1].data
|
||||
verts = obj.data.shape_keys.keys[len(obj.data.shape_keys.keys)-1].data
|
||||
|
||||
|
||||
for v in verts: # 12 is the size of 3 floats
|
||||
v.co[:] = unpack('>3f', file.read(12))
|
||||
#me.update()
|
||||
ob.show_shape_key = False
|
||||
obj.show_shape_key = False
|
||||
|
||||
|
||||
# insert keyframes
|
||||
shape_keys = ob.data.shape_keys
|
||||
shape_keys = obj.data.shape_keys
|
||||
|
||||
scene.frame_current -= 1
|
||||
ob.data.shape_keys.keys[index].value = 0.0
|
||||
shape_keys.keys[len(ob.data.shape_keys.keys)-1].keyframe_insert("value")
|
||||
obj.data.shape_keys.keys[index].value = 0.0
|
||||
shape_keys.keys[len(obj.data.shape_keys.keys)-1].keyframe_insert("value")
|
||||
|
||||
scene.frame_current += 1
|
||||
ob.data.shape_keys.keys[index].value = 1.0
|
||||
shape_keys.keys[len(ob.data.shape_keys.keys)-1].keyframe_insert("value")
|
||||
obj.data.shape_keys.keys[index].value = 1.0
|
||||
shape_keys.keys[len(obj.data.shape_keys.keys)-1].keyframe_insert("value")
|
||||
|
||||
scene.frame_current += 1
|
||||
ob.data.shape_keys.keys[index].value = 0.0
|
||||
shape_keys.keys[len(ob.data.shape_keys.keys)-1].keyframe_insert("value")
|
||||
obj.data.shape_keys.keys[index].value = 0.0
|
||||
shape_keys.keys[len(obj.data.shape_keys.keys)-1].keyframe_insert("value")
|
||||
|
||||
ob.data.update()
|
||||
obj.data.update()
|
||||
|
||||
|
||||
for i in range(frames):
|
||||
UpdateMesh(ob, i)
|
||||
UpdateMesh(obj, i)
|
||||
|
||||
|
||||
from bpy.props import *
|
||||
from io_utils import ImportHelper
|
||||
|
||||
|
||||
class importMDD(bpy.types.Operator, ImportHelper):
|
||||
'''Import MDD vertex keyframe file to shape keys'''
|
||||
bl_idname = "import_shape.mdd"
|
||||
bl_label = "Import MDD"
|
||||
|
||||
filename_ext = ".mdd"
|
||||
frame_start = IntProperty(name="Start Frame", description="Start frame for inserting animation", min=-300000, max=300000, default=0)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
ob = context.active_object
|
||||
return (ob and ob.type == 'MESH')
|
||||
|
||||
def execute(self, context):
|
||||
if not self.properties.filepath:
|
||||
raise Exception("filename not set")
|
||||
|
||||
mdd_import(self.properties.filepath, bpy.context.active_object, context.scene, self.properties.frame_start, 1)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(importMDD.bl_idname, text="Lightwave Point Cache (.mdd)")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_file_import.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_file_import.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
return {'FINISHED'}
|
||||
|
||||
Reference in New Issue
Block a user