Skip to content
Snippets Groups Projects
Commit f47802fb authored by Campbell Barton's avatar Campbell Barton
Browse files

scripts from bf-blender which are now maintained in bf-extensions.

parent c7c6d6d8
No related branches found
No related tags found
No related merge requests found
Showing
with 12450 additions and 0 deletions
# ##### 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>
bl_info = {
"name": "BioVision Motion Capture (BVH) format",
"author": "Campbell Barton",
"location": "File > Import-Export",
"description": "Import-Export BVH from armature objects",
"warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
"Scripts/Import-Export/MotionCapture_BVH",
"tracker_url": "",
"support": 'OFFICIAL',
"category": "Import-Export"}
# To support reload properly, try to access a package var, if it's there, reload everything
if "bpy" in locals():
import imp
if "import_bvh" in locals():
imp.reload(import_bvh)
import bpy
from bpy.props import *
from io_utils import ImportHelper, ExportHelper
class ImportBVH(bpy.types.Operator, ImportHelper):
'''Load a BVH motion capture file'''
bl_idname = "import_anim.bvh"
bl_label = "Import BVH"
filename_ext = ".bvh"
filter_glob = StringProperty(default="*.bvh", options={'HIDDEN'})
target = EnumProperty(items=(
('ARMATURE', "Armature", ""),
('OBJECT', "Object", ""),
),
name="Target",
description="Import target type.",
default='ARMATURE')
global_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=1.0)
frame_start = IntProperty(name="Start Frame", description="Starting frame for the animation", default=1)
use_cyclic = 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):
from . import import_bvh
return import_bvh.load(self, context, **self.as_keywords(ignore=("filter_glob",)))
class ExportBVH(bpy.types.Operator, ExportHelper):
'''Save a BVH motion capture file from an armature'''
bl_idname = "export_anim.bvh"
bl_label = "Export BVH"
filename_ext = ".bvh"
filter_glob = StringProperty(default="*.bvh", options={'HIDDEN'})
global_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=1.0)
frame_start = IntProperty(name="Start Frame", description="Starting frame to export", default=0)
frame_end = IntProperty(name="End Frame", description="End frame to export", default=0)
@classmethod
def poll(cls, context):
obj = context.object
return obj and obj.type == 'ARMATURE'
def invoke(self, context, event):
self.frame_start = context.scene.frame_start
self.frame_end = context.scene.frame_end
return super().invoke(context, event)
def execute(self, context):
if self.frame_start == 0 and self.frame_end == 0:
self.frame_start = context.scene.frame_start
self.frame_end = context.scene.frame_end
from . import export_bvh
return export_bvh.save(self, context, **self.as_keywords(ignore=("check_existing", "filter_glob")))
def menu_func_import(self, context):
self.layout.operator(ImportBVH.bl_idname, text="Motion Capture (.bvh)")
def menu_func_export(self, context):
self.layout.operator(ExportBVH.bl_idname, text="Motion Capture (.bvh)")
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()
# ##### 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>
# Script copyright (C) Campbell Barton
# fixes from Andrea Rugliancich
import bpy
def write_armature(context, filepath, frame_start, frame_end, global_scale=1.0):
from mathutils import Matrix, Vector, Euler
from math import degrees
file = open(filepath, "w")
obj = context.object
arm = obj.data
# Build a dictionary of children.
# None for parentless
children = {None: []}
# initialize with blank lists
for bone in arm.bones:
children[bone.name] = []
for bone in arm.bones:
children[getattr(bone.parent, "name", None)].append(bone.name)
# sort the children
for children_list in children.values():
children_list.sort()
# bone name list in the order that the bones are written
serialized_names = []
node_locations = {}
file.write("HIERARCHY\n")
def write_recursive_nodes(bone_name, indent):
my_children = children[bone_name]
indent_str = "\t" * indent
bone = arm.bones[bone_name]
loc = bone.head_local
node_locations[bone_name] = loc
# make relative if we can
if bone.parent:
loc = loc - node_locations[bone.parent.name]
if indent:
file.write("%sJOINT %s\n" % (indent_str, bone_name))
else:
file.write("%sROOT %s\n" % (indent_str, bone_name))
file.write("%s{\n" % indent_str)
file.write("%s\tOFFSET %.6f %.6f %.6f\n" % (indent_str, loc.x * global_scale, loc.y * global_scale, loc.z * global_scale))
if bone.use_connect and bone.parent:
file.write("%s\tCHANNELS 3 Xrotation Yrotation Zrotation\n" % indent_str)
else:
file.write("%s\tCHANNELS 6 Xposition Yposition Zposition Xrotation Yrotation Zrotation\n" % indent_str)
if my_children:
# store the location for the children
# to het their relative offset
# Write children
for child_bone in my_children:
serialized_names.append(child_bone)
write_recursive_nodes(child_bone, indent + 1)
else:
# Write the bone end.
file.write("%s\tEnd Site\n" % indent_str)
file.write("%s\t{\n" % indent_str)
loc = bone.tail_local - node_locations[bone_name]
file.write("%s\t\tOFFSET %.6f %.6f %.6f\n" % (indent_str, loc.x * global_scale, loc.y * global_scale, loc.z * global_scale))
file.write("%s\t}\n" % indent_str)
file.write("%s}\n" % indent_str)
if len(children[None]) == 1:
key = children[None][0]
serialized_names.append(key)
indent = 0
write_recursive_nodes(key, indent)
else:
# Write a dummy parent node
file.write("ROOT %s\n" % key)
file.write("{\n")
file.write("\tOFFSET 0.0 0.0 0.0\n")
file.write("\tCHANNELS 0\n") # Xposition Yposition Zposition Xrotation Yrotation Zrotation
key = None
indent = 1
write_recursive_nodes(key, indent)
file.write("}\n")
# redefine bones as sorted by serialized_names
# so we can write motion
class decorated_bone(object):
__slots__ = (\
"name", # bone name, used as key in many places
"parent", # decorated bone parent, set in a later loop
"rest_bone", # blender armature bone
"pose_bone", # blender pose bone
"pose_mat", # blender pose matrix
"rest_arm_mat", # blender rest matrix (armature space)
"rest_local_mat", # blender rest batrix (local space)
"pose_imat", # pose_mat inverted
"rest_arm_imat", # rest_arm_mat inverted
"rest_local_imat", # rest_local_mat inverted
"prev_euler", # last used euler to preserve euler compability in between keyframes
"connected", # is the bone connected to the parent bone?
)
def __init__(self, bone_name):
self.name = bone_name
self.rest_bone = arm.bones[bone_name]
self.pose_bone = obj.pose.bones[bone_name]
self.pose_mat = self.pose_bone.matrix
mat = self.rest_bone.matrix
self.rest_arm_mat = self.rest_bone.matrix_local
self.rest_local_mat = self.rest_bone.matrix
# inverted mats
self.pose_imat = self.pose_mat.copy().invert()
self.rest_arm_imat = self.rest_arm_mat.copy().invert()
self.rest_local_imat = self.rest_local_mat.copy().invert()
self.parent = None
self.prev_euler = Euler((0.0, 0.0, 0.0))
self.connected = (self.rest_bone.use_connect and self.rest_bone.parent)
def update_posedata(self):
self.pose_mat = self.pose_bone.matrix
self.pose_imat = self.pose_mat.copy().invert()
def __repr__(self):
if self.parent:
return "[\"%s\" child on \"%s\"]\n" % (self.name, self.parent.name)
else:
return "[\"%s\" root bone]\n" % (self.name)
bones_decorated = [decorated_bone(bone_name) for bone_name in serialized_names]
# Assign parents
bones_decorated_dict = {}
for dbone in bones_decorated:
bones_decorated_dict[dbone.name] = dbone
for dbone in bones_decorated:
parent = dbone.rest_bone.parent
if parent:
dbone.parent = bones_decorated_dict[parent.name]
del bones_decorated_dict
# finish assigning parents
scene = bpy.context.scene
file.write("MOTION\n")
file.write("Frames: %d\n" % (frame_end - frame_start + 1))
file.write("Frame Time: %.6f\n" % (1.0 / (scene.render.fps / scene.render.fps_base)))
for frame in range(frame_start, frame_end + 1):
scene.frame_set(frame)
for dbone in bones_decorated:
dbone.update_posedata()
for dbone in bones_decorated:
trans = Matrix.Translation(dbone.rest_bone.head_local)
itrans = Matrix.Translation(-dbone.rest_bone.head_local)
if dbone.parent:
mat_final = dbone.parent.rest_arm_mat * dbone.parent.pose_imat * dbone.pose_mat * dbone.rest_arm_imat
mat_final = itrans * mat_final * trans
loc = mat_final.translation_part() + (dbone.rest_bone.head_local - dbone.parent.rest_bone.head_local)
else:
mat_final = dbone.pose_mat * dbone.rest_arm_imat
mat_final = itrans * mat_final * trans
loc = mat_final.translation_part() + dbone.rest_bone.head
# keep eulers compatible, no jumping on interpolation.
rot = mat_final.rotation_part().invert().to_euler('XYZ', dbone.prev_euler)
if not dbone.connected:
file.write("%.6f %.6f %.6f " % (loc * global_scale)[:])
file.write("%.6f %.6f %.6f " % (-degrees(rot[0]), -degrees(rot[1]), -degrees(rot[2])))
dbone.prev_euler = rot
file.write("\n")
file.close()
print("BVH Exported: %s frames:%d\n" % (filepath, frame_end - frame_start + 1))
def save(operator, context, filepath="",
frame_start=-1,
frame_end=-1,
global_scale=1.0,
):
write_armature(context, filepath,
frame_start=frame_start,
frame_end=frame_end,
global_scale=global_scale,
)
return {'FINISHED'}
if __name__ == "__main__":
scene = bpy.context.scene
_read(bpy.data.filepath.rstrip(".blend") + ".bvh", bpy.context.object, scene.frame_start, scene.frame_end, 1.0)
This diff is collapsed.
# ##### 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>
bl_info = {
"name": "Stanford PLY format",
"author": "Bruce Merry, Campbell Barton",
"location": "File > Import-Export",
"description": "Import-Export PLY mesh data withs UV's and vertex colors",
"warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
"Scripts/Import-Export/Stanford_PLY",
"tracker_url": "",
"support": 'OFFICIAL',
"category": "Import-Export"}
# To support reload properly, try to access a package var, if it's there, reload everything
if "bpy" in locals():
import imp
if "export_ply" in locals():
imp.reload(export_ply)
if "import_ply" in locals():
imp.reload(import_ply)
import bpy
from bpy.props import *
from io_utils import ImportHelper, ExportHelper
class ImportPLY(bpy.types.Operator, ImportHelper):
'''Load a BVH motion capture file'''
bl_idname = "import_mesh.ply"
bl_label = "Import PLY"
filename_ext = ".ply"
filter_glob = StringProperty(default="*.ply", options={'HIDDEN'})
def execute(self, context):
from . import import_ply
return import_ply.load(self, context, **self.as_keywords(ignore=("filter_glob",)))
class ExportPLY(bpy.types.Operator, ExportHelper):
'''Export a single object as a stanford PLY with normals, colours and texture coordinates.'''
bl_idname = "export_mesh.ply"
bl_label = "Export PLY"
filename_ext = ".ply"
filter_glob = StringProperty(default="*.ply", options={'HIDDEN'})
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.filepath
filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
from . import export_ply
return export_ply.save(self, context, **self.as_keywords(ignore=("check_existing", "filter_glob")))
def draw(self, context):
layout = self.layout
row = layout.row()
row.prop(self, "use_modifiers")
row.prop(self, "use_normals")
row = layout.row()
row.prop(self, "use_uv_coords")
row.prop(self, "use_colors")
def menu_func_import(self, context):
self.layout.operator(ImportPLY.bl_idname, text="Stanford (.ply)")
def menu_func_export(self, context):
self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)")
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()
# ##### 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>
# Copyright (C) 2004, 2005: Bruce Merry, bmerry@cs.uct.ac.za
# Contributors: Bruce Merry, Campbell Barton
"""
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.
"""
import bpy
import os
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 rvec2d(v):
return round(v[0], 6), round(v[1], 6)
scene = context.scene
obj = context.object
if not obj:
raise Exception("Error, Select 1 active object")
file = open(filepath, 'w')
if scene.objects.active:
bpy.ops.object.mode_set(mode='OBJECT')
if use_modifiers:
mesh = obj.create_mesh(scene, True, 'PREVIEW')
else:
mesh = obj.data
if not mesh:
raise Exception("Error, could not get mesh data from active object")
# 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):
use_uv_coords = False
if not vertexColors:
use_colors = False
if not use_uv_coords:
faceUV = vertexUV = False
if not use_colors:
vertexColors = False
if faceUV:
active_uv_layer = mesh.uv_textures.active
if not active_uv_layer:
use_uv_coords = False
faceUV = None
else:
active_uv_layer = active_uv_layer.data
if vertexColors:
active_col_layer = mesh.vertex_colors.active
if not active_col_layer:
use_colors = False
vertexColors = None
else:
active_col_layer = active_col_layer.data
# incase
color = uvcoord = uvcoord_key = normal = normal_key = None
mesh_verts = mesh.vertices # save a lookup
ply_verts = [] # list of dictionaries
# vdict = {} # (index, normal, uv) -> new index
vdict = [{} for i in range(len(mesh_verts))]
ply_faces = [[] for f in range(len(mesh.faces))]
vert_count = 0
for i, f in enumerate(mesh.faces):
smooth = f.use_smooth
if not smooth:
normal = tuple(f.normal)
normal_key = rvec3d(normal)
if faceUV:
uv = active_uv_layer[i]
uv = uv.uv1, uv.uv2, uv.uv3, uv.uv4 # XXX - crufty :/
if vertexColors:
col = active_col_layer[i]
col = col.color1[:], col.color2[:], col.color3[:], col.color4[:]
f_verts = f.vertices
pf = ply_faces[i]
for j, vidx in enumerate(f_verts):
v = mesh_verts[vidx]
if smooth:
normal = tuple(v.normal)
normal_key = rvec3d(normal)
if faceUV:
uvcoord = uv[j][0], 1.0 - uv[j][1]
uvcoord_key = rvec2d(uvcoord)
elif vertexUV:
uvcoord = v.uvco[0], 1.0 - v.uvco[1]
uvcoord_key = rvec2d(uvcoord)
if vertexColors:
color = col[j]
color = int(color[0] * 255.0), int(color[1] * 255.0), int(color[2] * 255.0)
key = normal_key, uvcoord_key, color
vdict_local = vdict[vidx]
pf_vidx = vdict_local.get(key) # Will be None initially
if pf_vidx is None: # same as vdict_local.has_key(key)
pf_vidx = vdict_local[key] = vert_count
ply_verts.append((vidx, normal, uvcoord, color))
vert_count += 1
pf.append(pf_vidx)
file.write('ply\n')
file.write('format ascii 1.0\n')
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))
file.write('property float x\n')
file.write('property float y\n')
file.write('property float z\n')
if use_normals:
file.write('property float nx\n')
file.write('property float ny\n')
file.write('property float nz\n')
if use_uv_coords:
file.write('property float s\n')
file.write('property float t\n')
if use_colors:
file.write('property uchar red\n')
file.write('property uchar green\n')
file.write('property uchar blue\n')
file.write('element face %d\n' % len(mesh.faces))
file.write('property list uchar uint vertex_indices\n')
file.write('end_header\n')
for i, v in enumerate(ply_verts):
file.write('%.6f %.6f %.6f ' % mesh_verts[v[0]].co[:]) # co
if use_normals:
file.write('%.6f %.6f %.6f ' % v[1]) # no
if use_uv_coords:
file.write('%.6f %.6f ' % v[2]) # uv
if use_colors:
file.write('%u %u %u' % v[3]) # col
file.write('\n')
for pf in ply_faces:
if len(pf) == 3:
file.write('3 %d %d %d\n' % tuple(pf))
else:
file.write('4 %d %d %d %d\n' % tuple(pf))
file.close()
print("writing %r done" % filepath)
if use_modifiers:
bpy.data.meshes.remove(mesh)
# XXX
"""
if is_editmode:
Blender.Window.EditMode(1, '', 0)
"""
return {'FINISHED'}
# ##### 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>
import re
import struct
class element_spec(object):
__slots__ = ("name",
"count",
"properties",
)
def __init__(self, name, count):
self.name = name
self.count = count
self.properties = []
def load(self, format, stream):
if format == 'ascii':
stream = re.split('\s+', stream.readline())
return [x.load(format, stream) for x in self.properties]
def index(self, name):
for i, p in enumerate(self.properties):
if p.name == name:
return i
return -1
class property_spec(object):
__slots__ = ("name",
"list_type",
"numeric_type",
)
def __init__(self, name, list_type, numeric_type):
self.name = name
self.list_type = list_type
self.numeric_type = numeric_type
def read_format(self, format, count, num_type, stream):
if format == 'ascii':
if num_type == 's':
ans = []
for i in range(count):
s = stream[i]
if len(s) < 2 or s[0] != '"' or s[-1] != '"':
print('Invalid string', s)
print('Note: ply_import.py does not handle whitespace in strings')
return None
ans.append(s[1:-1])
stream[:count] = []
return ans
if num_type == 'f' or num_type == 'd':
mapper = float
else:
mapper = int
ans = [mapper(x) for x in stream[:count]]
stream[:count] = []
return ans
else:
if num_type == 's':
ans = []
for i in range(count):
fmt = format + 'i'
data = stream.read(struct.calcsize(fmt))
length = struct.unpack(fmt, data)[0]
fmt = '%s%is' % (format, length)
data = stream.read(struct.calcsize(fmt))
s = struct.unpack(fmt, data)[0]
ans.append(s[:-1]) # strip the NULL
return ans
else:
fmt = '%s%i%s' % (format, count, num_type)
data = stream.read(struct.calcsize(fmt))
return struct.unpack(fmt, data)
def load(self, format, stream):
if self.list_type is not None:
count = int(self.read_format(format, 1, self.list_type, stream)[0])
return self.read_format(format, count, self.numeric_type, stream)
else:
return self.read_format(format, 1, self.numeric_type, stream)[0]
class object_spec(object):
__slots__ = ("specs",
)
'A list of element_specs'
def __init__(self):
self.specs = []
def load(self, format, stream):
return dict([(i.name, [i.load(format, stream) for j in range(i.count)]) for i in self.specs])
'''
# Longhand for above LC
answer = {}
for i in self.specs:
answer[i.name] = []
for j in range(i.count):
if not j % 100 and meshtools.show_progress:
Blender.Window.DrawProgressBar(float(j) / i.count, 'Loading ' + i.name)
answer[i.name].append(i.load(format, stream))
return answer
'''
def read(filepath):
format = ''
version = '1.0'
format_specs = {'binary_little_endian': '<',
'binary_big_endian': '>',
'ascii': 'ascii'}
type_specs = {'char': 'b',
'uchar': 'B',
'int8': 'b',
'uint8': 'B',
'int16': 'h',
'uint16': 'H',
'ushort': 'H',
'int': 'i',
'int32': 'i',
'uint': 'I',
'uint32': 'I',
'float': 'f',
'float32': 'f',
'float64': 'd',
'double': 'd',
'string': 's'}
obj_spec = object_spec()
try:
file = open(filepath, 'rU') # Only for parsing the header, not binary data
signature = file.readline()
if not signature.startswith('ply'):
print('Signature line was invalid')
return None
while 1:
tokens = re.split(r'[ \n]+', file.readline())
if len(tokens) == 0:
continue
if tokens[0] == 'end_header':
break
elif tokens[0] == 'comment' or tokens[0] == 'obj_info':
continue
elif tokens[0] == 'format':
if len(tokens) < 3:
print('Invalid format line')
return None
if tokens[1] not in format_specs: # .keys(): # keys is implicit
print('Unknown format', tokens[1])
return None
if tokens[2] != version:
print('Unknown version', tokens[2])
return None
format = tokens[1]
elif tokens[0] == 'element':
if len(tokens) < 3:
print('Invalid element line')
return None
obj_spec.specs.append(element_spec(tokens[1], int(tokens[2])))
elif tokens[0] == 'property':
if not len(obj_spec.specs):
print('Property without element')
return None
if tokens[1] == 'list':
obj_spec.specs[-1].properties.append(property_spec(tokens[4], type_specs[tokens[2]], type_specs[tokens[3]]))
else:
obj_spec.specs[-1].properties.append(property_spec(tokens[2], None, type_specs[tokens[1]]))
if format != 'ascii':
file.close() # was ascii, now binary
file = open(filepath, 'rb')
# skip the header...
while not file.readline().startswith('end_header'):
pass
obj = obj_spec.load(format_specs[format], file)
except IOError:
try:
file.close()
except:
pass
return None
try:
file.close()
except:
pass
return obj_spec, obj
import bpy
def load_ply(filepath):
import time
from io_utils import load_image, unpack_list, unpack_face_list
t = time.time()
obj_spec, obj = read(filepath)
if obj is None:
print('Invalid file')
return
uvindices = colindices = None
# noindices = None # Ignore normals
for el in obj_spec.specs:
if el.name == 'vertex':
vindices = vindices_x, vindices_y, vindices_z = (el.index('x'), el.index('y'), el.index('z'))
# noindices = (el.index('nx'), el.index('ny'), el.index('nz'))
# if -1 in noindices: noindices = None
uvindices = (el.index('s'), el.index('t'))
if -1 in uvindices:
uvindices = None
colindices = (el.index('red'), el.index('green'), el.index('blue'))
if -1 in colindices:
colindices = None
elif el.name == 'face':
findex = el.index('vertex_indices')
mesh_faces = []
mesh_uvs = []
mesh_colors = []
def add_face(vertices, indices, uvindices, colindices):
mesh_faces.append(indices)
if uvindices:
mesh_uvs.append([(vertices[index][uvindices[0]], 1.0 - vertices[index][uvindices[1]]) for index in indices])
if colindices:
mesh_colors.append([(vertices[index][colindices[0]], vertices[index][colindices[1]], vertices[index][colindices[2]]) for index in indices])
if uvindices or colindices:
# If we have Cols or UVs then we need to check the face order.
add_face_simple = add_face
# EVIL EEKADOODLE - face order annoyance.
def add_face(vertices, indices, uvindices, colindices):
if len(indices) == 4:
if indices[2] == 0 or indices[3] == 0:
indices = indices[2], indices[3], indices[0], indices[1]
elif len(indices) == 3:
if indices[2] == 0:
indices = indices[1], indices[2], indices[0]
add_face_simple(vertices, indices, uvindices, colindices)
verts = obj['vertex']
if 'face' in obj:
for f in obj['face']:
ind = f[findex]
len_ind = len(ind)
if len_ind <= 4:
add_face(verts, ind, uvindices, colindices)
else:
# Fan fill the face
for j in range(len_ind - 2):
add_face(verts, (ind[0], ind[j + 1], ind[j + 2]), uvindices, colindices)
ply_name = bpy.path.display_name_from_filepath(filepath)
mesh = bpy.data.meshes.new(name=ply_name)
mesh.vertices.add(len(obj['vertex']))
mesh.vertices.foreach_set("co", [a for v in obj['vertex'] for a in (v[vindices_x], v[vindices_y], v[vindices_z])])
if mesh_faces:
mesh.faces.add(len(mesh_faces))
mesh.faces.foreach_set("vertices_raw", unpack_face_list(mesh_faces))
if uvindices or colindices:
if uvindices:
uvlay = mesh.uv_textures.new()
if colindices:
vcol_lay = mesh.vertex_colors.new()
if uvindices:
for i, f in enumerate(uvlay.data):
ply_uv = mesh_uvs[i]
for j, uv in enumerate(f.uv):
uv[:] = ply_uv[j]
if colindices:
faces = obj['face']
for i, f in enumerate(vcol_lay.data):
# XXX, colors dont come in right, needs further investigation.
ply_col = mesh_colors[i]
if len(faces[i]) == 4:
f_col = f.color1, f.color2, f.color3, f.color4
else:
f_col = f.color1, f.color2, f.color3
for j, col in enumerate(f_col):
col.r, col.g, col.b = ply_col[j]
mesh.update()
scn = bpy.context.scene
#scn.objects.selected = [] # XXX25
obj = bpy.data.objects.new(ply_name, mesh)
scn.objects.link(obj)
scn.objects.active = obj
obj.select = True
print('\nSuccessfully imported %r in %.3f sec' % (filepath, time.time() - t))
def load(operator, context, filepath=""):
load_ply(filepath)
return {'FINISHED'}
# ##### 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>
bl_info = {
"name": "Autodesk 3DS format",
"author": "Bob Holcomb, Campbell Barton",
"location": "File > Import-Export",
"description": "Import-Export 3DS, meshes, uvs, materials, textures, cameras & lamps",
"warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
"Scripts/Import-Export/Autodesk_3DS",
"tracker_url": "",
"support": 'OFFICIAL',
"category": "Import-Export"}
# To support reload properly, try to access a package var, if it's there, reload everything
if "bpy" in locals():
import imp
if "import_3ds" in locals():
imp.reload(import_3ds)
if "export_3ds" in locals():
imp.reload(export_3ds)
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"
filter_glob = StringProperty(default="*.3ds", options={'HIDDEN'})
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=True)
def execute(self, context):
from . import import_3ds
return import_3ds.load(self, context, **self.as_keywords(ignore=("filter_glob",)))
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"
filter_glob = StringProperty(default="*.3ds", options={'HIDDEN'})
def execute(self, context):
from . import export_3ds
return export_3ds.save(self, context, **self.as_keywords(ignore=("check_existing", "filter_glob")))
# 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)
# 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()
This diff is collapsed.
This diff is collapsed.
# ##### 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>
bl_info = {
"name": "Autodesk FBX format",
"author": "Campbell Barton",
"location": "File > Import-Export",
"description": "Import-Export FBX meshes, UV's, vertex colors, materials, textures, cameras and lamps",
"warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
"Scripts/Import-Export/Autodesk_FBX",
"tracker_url": "",
"support": 'OFFICIAL',
"category": "Import-Export"}
# To support reload properly, try to access a package var, if it's there, reload everything
if "bpy" in locals():
import imp
if "export_fbx" in locals():
imp.reload(export_fbx)
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"
bl_options = {'PRESET'}
filename_ext = ".fbx"
filter_glob = StringProperty(default="*.fbx", options={'HIDDEN'})
# 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.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.TX_SCALE
if self.TX_XROT90:
GLOBAL_MATRIX = mtx4_x90n * GLOBAL_MATRIX
if self.TX_YROT90:
GLOBAL_MATRIX = mtx4_y90n * GLOBAL_MATRIX
if self.TX_ZROT90:
GLOBAL_MATRIX = mtx4_z90n * GLOBAL_MATRIX
keywords = self.as_keywords(ignore=("TX_XROT90", "TX_YROT90", "TX_ZROT90", "TX_SCALE", "check_existing", "filter_glob"))
keywords["GLOBAL_MATRIX"] = GLOBAL_MATRIX
import io_scene_fbx.export_fbx
return io_scene_fbx.export_fbx.save(self, context, **keywords)
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()
This diff is collapsed.
# ##### 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>
bl_info = {
"name": "Wavefront OBJ format",
"author": "Campbell Barton",
"location": "File > Import-Export",
"description": "Import-Export X3D, Import OBJ mesh, UV's, materials and textures",
"warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
"Scripts/Import-Export/Wavefront_OBJ",
"tracker_url": "",
"support": 'OFFICIAL',
"category": "Import-Export"}
# To support reload properly, try to access a package var, if it's there, reload everything
if "bpy" in locals():
import imp
if "import_obj" in locals():
imp.reload(import_obj)
if "export_obj" in locals():
imp.reload(export_obj)
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"
filter_glob = StringProperty(default="*.obj;*.mtl", options={'HIDDEN'})
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)
from . import import_obj
return import_obj.load(self, context, **self.as_keywords(ignore=("filter_glob",)))
class ExportOBJ(bpy.types.Operator, ExportHelper):
'''Save a Wavefront OBJ File'''
bl_idname = "export_scene.obj"
bl_label = 'Export OBJ'
bl_options = {'PRESET'}
filename_ext = ".obj"
filter_glob = StringProperty(default="*.obj;*.mtl", options={'HIDDEN'})
# 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):
from . import export_obj
return export_obj.save(self, context, **self.as_keywords(ignore=("check_existing", "filter_glob")))
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()
This diff is collapsed.
This diff is collapsed.
# ##### 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>
bl_info = {
"name": "Web3D X3D/VRML format",
"author": "Campbell Barton, Bart",
"location": "File > Import-Export",
"description": "Import-Export X3D, Import VRML",
"warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
"Scripts/Import-Export/Web3D",
"tracker_url": "",
"support": 'OFFICIAL',
"category": "Import-Export"}
# To support reload properly, try to access a package var, if it's there, reload everything
if "bpy" in locals():
import imp
if "export_x3d" in locals():
imp.reload(export_x3d)
import bpy
from bpy.props import *
from io_utils import ImportHelper, ExportHelper
class ImportX3D(bpy.types.Operator, ImportHelper):
'''Load a BVH motion capture file'''
bl_idname = "import_scene.x3d"
bl_label = "Import X3D/VRML"
filename_ext = ".x3d"
filter_glob = StringProperty(default="*.x3d;*.wrl", options={'HIDDEN'})
def execute(self, context):
from . import import_x3d
return import_x3d.load(self, context, **self.as_keywords(ignore=("filter_glob",)))
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"
filter_glob = StringProperty(default="*.x3d", options={'HIDDEN'})
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):
from . import export_x3d
return export_x3d.save(self, context, **self.as_keywords(ignore=("check_existing", "filter_glob")))
def menu_func_import(self, context):
self.layout.operator(ImportX3D.bl_idname, text="X3D Extensible 3D (.x3d/.wrl)")
def menu_func_export(self, context):
self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)")
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)
# NOTES
# - blender version is hardcoded
if __name__ == "__main__":
register()
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment