diff --git a/docs/list.js b/docs/list.js
index fca71268ae9e4eba16a6fe107240dfcf6c08a285..7be9db7e388088835c0f58871582cc9a76887ea8 100644
--- a/docs/list.js
+++ b/docs/list.js
@@ -10,6 +10,7 @@ var list = {
"How to run things locally": "manual/introduction/How-to-run-things-locally",
"Drawing Lines": "manual/introduction/Drawing-lines",
"Creating Text": "manual/introduction/Creating-text",
+ "Loading 3D Models": "manual/introduction/Loading-3D-models",
"Migration Guide": "manual/introduction/Migration-guide",
"Code Style Guide": "manual/introduction/Code-style-guide",
"FAQ": "manual/introduction/FAQ",
diff --git a/docs/manual/introduction/Animation-system.html b/docs/manual/introduction/Animation-system.html
index ac70163075ffabdb19194ec0bcc57be091f0fcbb..19a665df5dce62dad3681accf8493a9e03079739 100644
--- a/docs/manual/introduction/Animation-system.html
+++ b/docs/manual/introduction/Animation-system.html
@@ -35,11 +35,11 @@
If you have successfully imported an animated 3D object (it doesn't matter if it has
- bones or morph targets or both) - for example exporting it from Blender with the
- [link:https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender/addons/io_three Blender exporter] and
- loading it into a three.js scene using [page:JSONLoader] -, one of the geometry's
- properties of the loaded mesh should be an array named "animations", containing the
- [page:AnimationClip AnimationClips] for this model (see a list of possible loaders below).
+ bones or morph targets or both) — for example exporting, it from Blender with the
+ [link:https://github.com/KhronosGroup/glTF-Blender-Exporter glTF Blender exporter] and
+ loading it into a three.js scene using [page:GLTFLoader] — one of the response fields
+ should be an array named "animations", containing the [page:AnimationClip AnimationClips]
+ for this model (see a list of possible loaders below).
Each *AnimationClip* usually holds the data for a certain activity of the object. If the
mesh is a character, for example, there may be one AnimationClip for a walkcycle, a second
diff --git a/docs/manual/introduction/FAQ.html b/docs/manual/introduction/FAQ.html
index 8753f54d136b2881b42e7c88d58c29e43f64ae54..944e8086054fa4a5979b49e3a6ad79b4874f59a2 100644
--- a/docs/manual/introduction/FAQ.html
+++ b/docs/manual/introduction/FAQ.html
@@ -16,7 +16,7 @@
The recommended format for importing and exporting assets is glTF (GL Transmission Format). Because glTF is focused on runtime asset delivery, it is compact to transmit and fast to load.
- three.js provides loaders for many other popular formats like FBX, Collada or OBJ as well. Nevertheless, you should always try to establish a glTF based workflow in your projects first.
+ three.js provides loaders for many other popular formats like FBX, Collada or OBJ as well. Nevertheless, you should always try to establish a glTF based workflow in your projects first. For more information, see [link:#manual/introduction/Loading-3D-models loading 3D models].
+ 3D models are available in hundreds of file formats, each with different
+ purposes, assorted features, and varying complexity. Although
+
+ three.js provides many loaders, choosing the right format and
+ workflow will save time and frustration later on. Some formats are
+ difficult to work with, inefficient for realtime experiences, or simply not
+ fully supported at this time.
+
+
+
+ This guide provides a workflow recommended for most users, and suggestions
+ for what to try if things don't go as expected.
+
+
+
Before we start
+
+
+ If you're new to running a local server, begin with
+ [link:#manual/introduction/How-to-run-things-locally how to run things locally]
+ first. Many common errors viewing 3D models can be avoided by hosting files
+ correctly.
+
+
+
Recommended workflow
+
+
+ Where possible, we recommend using glTF (GL Transmission Format). Both
+ .GLB and .GLTF versions of the format are
+ well supported. Because glTF is focused on runtime asset delivery, it is
+ compact to transmit and fast to load. Features include meshes, materials,
+ textures, skins, skeletons, morph targets, animations, lights, and
+ cameras.
+
+
+
+ Public-domain glTF files are available on sites like
+
+ Sketchfab, or various tools include glTF export:
+
+ If your preferred tools do not support glTF, consider requesting glTF
+ export from the authors, or posting on
+ the glTF roadmap thread.
+
+
+
+ When glTF is not an option, popular formats such as FBX, OBJ, or COLLADA
+ are also available and regularly maintained.
+
+
+
Troubleshooting
+
+
+ You've spent hours modeling an artisanal masterpiece, you load it into
+ the webpage, and — oh no! 😭 It's distorted, miscolored, or missing entirely.
+ Start with these troubleshooting steps:
+
+
+
+
+ Check the JavaScript console for errors, and make sure you've used an
+ onError callback when calling .load() to log the result.
+
+
+ View the model in another application. For glTF, drag-and-drop viewers
+ are available for
+ three.js and
+ babylon.js. If the model
+ appears correctly in one or more applications,
+ file a bug against three.js.
+ If the model cannot be shown in any application, we strongly encourage
+ filing a bug with the application used to create the model.
+
+
+ Try scaling the model up or down by a factor of 1000. Many models are
+ scaled differently, and large models may not appear if the camera is
+ inside the model.
+
+
+ Look for failed texture requests in the network tab, like
+ C:\\Path\To\Model\texture.jpg. Use paths relative to your
+ model instead, such as images/texture.jpg — this may require
+ editing the model file in a text editor.
+
+
+
+
Asking for help
+
+
+ If you've gone through the troubleshooting process above and your model
+ still isn't working, the right approach to asking for help will get you to
+ a solution faster. Whenever possible, include your model (or a simpler
+ model with the same problem) in any formats you have available. Include
+ enough information for someone else to reproduce the issue quickly —
+ ideally, a live demo.
+
+
+
+ TODO: Do we recommend model-related questions go to GitHub, Stack Overflow,
+ or the Discourse forum?
+
+
+
+
\ No newline at end of file
diff --git a/utils/exporters/blender/.gitignore b/utils/exporters/blender/.gitignore
deleted file mode 100644
index c1c6da1922d327bdeb30d154a06ee998cfccc0db..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-tests/review
-__pycache__/
-tmp/
diff --git a/utils/exporters/blender/README.md b/utils/exporters/blender/README.md
index 5860d90c9432579655675cb564981eca229bb157..7eab0b90eb6ba90ba82c08e0d3477807f4e77fd8 100644
--- a/utils/exporters/blender/README.md
+++ b/utils/exporters/blender/README.md
@@ -1,68 +1,3 @@
# Three.js Blender Export
-Exports Three.js' ASCII JSON format.
-
-## IMPORTANT
-
-The exporter (r69 and earlier) has been completely replaced. Please ensure you have removed the io_three_mesh addon from your Blender addons directory before installing the current addon (io_three).
-
-## Installation
-
-
-Recommended Blender version **>= 2.73.0**
-
-Copy the io_three folder to the scripts/addons folder. If it doesn't exist, create it. The full path is OS-dependent (see below).
-
-Once that is done, you need to activate the plugin. Open Blender preferences, look for
-Addons, search for `three`, enable the checkbox next to the `Import-Export: Three.js Format` entry.
-
-Goto Usage.
-
-### Windows
-
-Should look like this:
-
- C:\Program Files\Blender Foundation\Blender\2.7X\scripts\addons
-
-OR (for 2.6)
-
- C:\Users\USERNAME\AppData\Roaming\Blender Foundation\Blender\2.6X\scripts\addons
-
-### OSX
-
-In your user's library for user installed Blender addons:
-
- /Users/(myuser)/Library/Application Support/Blender/2.7X/scripts/addons
-
-OR (for 2.79)
-
- /Applications/Blender/blender.app/Contents/Resources/2.79/scripts/addons
-
-### Linux
-
-By default, this should look like:
-
- /home/USERNAME/.config/blender/2.6X/scripts/addons
-
-For Ubuntu users who installed Blender 2.68 via apt-get, this is the location:
-
- /usr/lib/blender/scripts/addons
-
-For Ubuntu users who installed Blender 2.7x via apt-get, this is the location:
-
- /usr/share/blender/scripts/addons
-
-
-## Usage
-
-Activate the Import-Export addon under "User Preferences" > "Addons" and then use the regular Export menu within Blender, select `Three.js (json)`.
-
-
-## Enabling msgpack
-
-To enable msgpack compression copy the msgpack to scripts/modules.
-
-
-## Importer
-
-Currently there is no import functionality available.
+> **NOTICE:** The Blender exporter for the Three.js JSON format has been removed, to focus on better support for other workflows. For recommended alternatives, see [Loading 3D Models](https://threejs.org/docs/#manual/introduction/loading-3d-models). The Three.js JSON format is still fully supported for use with [Object3D.toJSON](https://threejs.org/docs/#api/core/Object3D.toJSON), the [Editor](https://threejs.org/editor/), [THREE.ObjectLoader](https://threejs.org/docs/#api/loaders/ObjectLoader), [THREE.JSONLoader](https://threejs.org/docs/#api/loaders/JSONLoader), and [converters](https://github.com/mrdoob/three.js/tree/dev/utils/converters).
diff --git a/utils/exporters/blender/addons/io_three/__init__.py b/utils/exporters/blender/addons/io_three/__init__.py
deleted file mode 100644
index b26539c9c655be1ef374625729560ecc6f2fcc12..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/__init__.py
+++ /dev/null
@@ -1,1059 +0,0 @@
-# ##### 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 #####
-
-import os
-import json
-import logging
-
-import bpy
-from bpy_extras.io_utils import ExportHelper
-from bpy.props import (
- EnumProperty,
- BoolProperty,
- FloatProperty,
- IntProperty,
- StringProperty
-)
-
-from . import constants
-
-logging.basicConfig(
- format='%(levelname)s:THREE:%(message)s',
- level=logging.DEBUG)
-
-bl_info = {
- 'name': "Three.js Format",
- 'author': "repsac, mrdoob, yomotsu, mpk, jpweeks, rkusa, tschw, jackcaron, bhouston",
- 'version': (1, 5, 0),
- 'blender': (2, 74, 0),
- 'location': "File > Export",
- 'description': "Export Three.js formatted JSON files.",
- 'warning': "Importer not included.",
- 'wiki_url': "https://github.com/mrdoob/three.js/tree/"\
- "master/utils/exporters/blender",
- 'tracker_url': "https://github.com/mrdoob/three.js/issues",
- 'category': 'Import-Export'
-}
-
-
-def _geometry_types():
- """The valid geometry types that are supported by Three.js
-
- :return: list of tuples
-
- """
- keys = (constants.GLOBAL,
- constants.GEOMETRY,
- constants.BUFFER_GEOMETRY)
- types = []
- for key in keys:
- types.append((key, key.title(), key))
-
- return types
-
-bpy.types.Mesh.THREE_geometry_type = EnumProperty(
- name="Geometry type",
- description="Geometry type",
- items=_geometry_types(),
- default=constants.GLOBAL)
-
-class ThreeMesh(bpy.types.Panel):
- """Creates custom properties on a mesh node"""
-
- bl_label = 'THREE'
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = 'data'
-
- def draw(self, context):
- """
-
- :param context:
-
- """
- row = self.layout.row()
- if context.mesh:
- row.prop(context.mesh,
- 'THREE_geometry_type',
- text="Type")
-
-def _blending_types(index):
- """Supported blending types for Three.js
-
- :param index:
- :type index: int
- :returns: tuple if types (str, str, str)
-
- """
- types = (constants.BLENDING_TYPES.NONE,
- constants.BLENDING_TYPES.NORMAL,
- constants.BLENDING_TYPES.ADDITIVE,
- constants.BLENDING_TYPES.SUBTRACTIVE,
- constants.BLENDING_TYPES.MULTIPLY,
- constants.BLENDING_TYPES.CUSTOM)
- return (types[index], types[index], types[index])
-
-bpy.types.Material.THREE_blending_type = EnumProperty(
- name="Blending type",
- description="Blending type",
- items=[_blending_types(x) for x in range(6)],
- default=constants.BLENDING_TYPES.NORMAL)
-
-bpy.types.Material.THREE_depth_write = BoolProperty(default=True)
-bpy.types.Material.THREE_depth_test = BoolProperty(default=True)
-bpy.types.Material.THREE_double_sided = BoolProperty(default=False)
-
-class ThreeMaterial(bpy.types.Panel):
- """Adds custom properties to the Materials of an object"""
-
- bl_label = 'THREE'
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = 'material'
-
- def draw(self, context):
- """
-
- :param context:
-
- """
- layout = self.layout
- mat = context.material
-
- if mat is not None:
- row = layout.row()
- row.label(text="Selected material: %s" % mat.name)
-
- row = layout.row()
- row.prop(mat, 'THREE_blending_type',
- text="Blending type")
-
- row = layout.row()
- row.prop(mat, 'THREE_depth_write',
- text="Enable depth writing")
-
- row = layout.row()
- row.prop(mat, 'THREE_depth_test',
- text="Enable depth testing")
-
- row = layout.row()
- row.prop(mat, 'THREE_double_sided',
- text="Double-sided")
-
-def _mag_filters(index):
- """Three.js mag filters
-
- :param index:
- :type index: int
- :returns: tuple with the filter values
-
- """
- types = (constants.LINEAR_FILTERS.LINEAR,
- constants.NEAREST_FILTERS.NEAREST)
- return (types[index], types[index], types[index])
-
-bpy.types.Texture.THREE_mag_filter = EnumProperty(
- name="Mag Filter",
- items=[_mag_filters(x) for x in range(2)],
- default=constants.LINEAR_FILTERS.LINEAR)
-
-def _min_filters(index):
- """Three.js min filters
-
- :param index:
- :type index: int
- :returns: tuple with the filter values
-
- """
- types = (constants.LINEAR_FILTERS.LINEAR,
- constants.LINEAR_FILTERS.MIP_MAP_NEAREST,
- constants.LINEAR_FILTERS.MIP_MAP_LINEAR,
- constants.NEAREST_FILTERS.NEAREST,
- constants.NEAREST_FILTERS.MIP_MAP_NEAREST,
- constants.NEAREST_FILTERS.MIP_MAP_LINEAR)
- return (types[index], types[index], types[index])
-
-bpy.types.Texture.THREE_min_filter = EnumProperty(
- name="Min Filter",
- items=[_min_filters(x) for x in range(6)],
- default=constants.LINEAR_FILTERS.MIP_MAP_LINEAR)
-
-def _mapping(index):
- """Three.js texture mappings types
-
- :param index:
- :type index: int
- :returns: tuple with the mapping values
-
- """
- types = (constants.MAPPING_TYPES.UV,
- constants.MAPPING_TYPES.CUBE_REFLECTION,
- constants.MAPPING_TYPES.CUBE_REFRACTION,
- constants.MAPPING_TYPES.SPHERICAL_REFLECTION)
- return (types[index], types[index], types[index])
-
-bpy.types.Texture.THREE_mapping = EnumProperty(
- name="Mapping",
- items=[_mapping(x) for x in range(4)],
- default=constants.MAPPING_TYPES.UV)
-
-class ThreeTexture(bpy.types.Panel):
- """Adds custom properties to a texture"""
- bl_label = 'THREE'
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = 'texture'
-
- #@TODO: possible to make cycles compatible?
- def draw(self, context):
- """
-
- :param context:
-
- """
- layout = self.layout
- tex = context.texture
-
- if tex is not None:
- row = layout.row()
- row.prop(tex, 'THREE_mapping', text="Mapping")
-
- row = layout.row()
- row.prop(tex, 'THREE_mag_filter', text="Mag Filter")
-
- row = layout.row()
- row.prop(tex, 'THREE_min_filter', text="Min Filter")
-
-bpy.types.Object.THREE_export = bpy.props.BoolProperty(default=True)
-
-class ThreeObject(bpy.types.Panel):
- """Adds custom properties to an object"""
- bl_label = 'THREE'
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = 'object'
-
- def draw(self, context):
- """
-
- :param context:
-
- """
- layout = self.layout
- obj = context.object
-
- row = layout.row()
- row.prop(obj, 'THREE_export', text='Export')
-
-class ThreeExportSettings(bpy.types.Operator):
- """Save the current export settings (gets saved in .blend)"""
- bl_label = "Save Settings"
- bl_idname = "scene.three_export_settings_set"
-
- def execute(self, context):
- cycles = context.scene.cycles
- cycles.use_samples_final = True
-
- context.scene[constants.EXPORT_SETTINGS_KEY] = set_settings(context.active_operator.properties)
-
- self.report({"INFO"}, "Three Export Settings Saved")
-
- return {"FINISHED"}
-
-def restore_export_settings(properties, settings):
- """Restore the settings
-
- :param properties:
-
- """
-
- ## Geometry {
- properties.option_vertices = settings.get(
- constants.VERTICES,
- constants.EXPORT_OPTIONS[constants.VERTICES])
-
- properties.option_faces = settings.get(
- constants.FACES,
- constants.EXPORT_OPTIONS[constants.FACES])
- properties.option_normals = settings.get(
- constants.NORMALS,
- constants.EXPORT_OPTIONS[constants.NORMALS])
-
- properties.option_skinning = settings.get(
- constants.SKINNING,
- constants.EXPORT_OPTIONS[constants.SKINNING])
-
- properties.option_bones = settings.get(
- constants.BONES,
- constants.EXPORT_OPTIONS[constants.BONES])
-
- properties.option_influences = settings.get(
- constants.INFLUENCES_PER_VERTEX,
- constants.EXPORT_OPTIONS[constants.INFLUENCES_PER_VERTEX])
-
- properties.option_apply_modifiers = settings.get(
- constants.APPLY_MODIFIERS,
- constants.EXPORT_OPTIONS[constants.APPLY_MODIFIERS])
-
- properties.option_extra_vgroups = settings.get(
- constants.EXTRA_VGROUPS,
- constants.EXPORT_OPTIONS[constants.EXTRA_VGROUPS])
-
- properties.option_geometry_type = settings.get(
- constants.GEOMETRY_TYPE,
- constants.EXPORT_OPTIONS[constants.GEOMETRY_TYPE])
-
- properties.option_index_type = settings.get(
- constants.INDEX_TYPE,
- constants.EXPORT_OPTIONS[constants.INDEX_TYPE])
- ## }
-
- ## Materials {
- properties.option_materials = settings.get(
- constants.MATERIALS,
- constants.EXPORT_OPTIONS[constants.MATERIALS])
-
- properties.option_uv_coords = settings.get(
- constants.UVS,
- constants.EXPORT_OPTIONS[constants.UVS])
-
- properties.option_face_materials = settings.get(
- constants.FACE_MATERIALS,
- constants.EXPORT_OPTIONS[constants.FACE_MATERIALS])
-
- properties.option_maps = settings.get(
- constants.MAPS,
- constants.EXPORT_OPTIONS[constants.MAPS])
-
- properties.option_colors = settings.get(
- constants.COLORS,
- constants.EXPORT_OPTIONS[constants.COLORS])
-
- properties.option_mix_colors = settings.get(
- constants.MIX_COLORS,
- constants.EXPORT_OPTIONS[constants.MIX_COLORS])
- ## }
-
- ## Settings {
- properties.option_scale = settings.get(
- constants.SCALE,
- constants.EXPORT_OPTIONS[constants.SCALE])
-
- properties.option_round_off = settings.get(
- constants.ENABLE_PRECISION,
- constants.EXPORT_OPTIONS[constants.ENABLE_PRECISION])
-
- properties.option_round_value = settings.get(
- constants.PRECISION,
- constants.EXPORT_OPTIONS[constants.PRECISION])
-
- properties.option_custom_properties = settings.get(
- constants.CUSTOM_PROPERTIES,
- constants.EXPORT_OPTIONS[constants.CUSTOM_PROPERTIES])
-
- properties.option_logging = settings.get(
- constants.LOGGING,
- constants.EXPORT_OPTIONS[constants.LOGGING])
-
- properties.option_compression = settings.get(
- constants.COMPRESSION,
- constants.NONE)
-
- properties.option_indent = settings.get(
- constants.INDENT,
- constants.EXPORT_OPTIONS[constants.INDENT])
-
- properties.option_export_textures = settings.get(
- constants.EXPORT_TEXTURES,
- constants.EXPORT_OPTIONS[constants.EXPORT_TEXTURES])
-
- properties.option_embed_textures = settings.get(
- constants.EMBED_TEXTURES,
- constants.EXPORT_OPTIONS[constants.EMBED_TEXTURES])
-
- properties.option_texture_folder = settings.get(
- constants.TEXTURE_FOLDER,
- constants.EXPORT_OPTIONS[constants.TEXTURE_FOLDER])
-
- properties.option_embed_animation = settings.get(
- constants.EMBED_ANIMATION,
- constants.EXPORT_OPTIONS[constants.EMBED_ANIMATION])
- ## }
-
- ## Scene {
- properties.option_export_scene = settings.get(
- constants.SCENE,
- constants.EXPORT_OPTIONS[constants.SCENE])
-
- #properties.option_embed_geometry = settings.get(
- # constants.EMBED_GEOMETRY,
- # constants.EXPORT_OPTIONS[constants.EMBED_GEOMETRY])
-
- properties.option_lights = settings.get(
- constants.LIGHTS,
- constants.EXPORT_OPTIONS[constants.LIGHTS])
-
- properties.option_cameras = settings.get(
- constants.CAMERAS,
- constants.EXPORT_OPTIONS[constants.CAMERAS])
-
- properties.option_hierarchy = settings.get(
- constants.HIERARCHY,
- constants.EXPORT_OPTIONS[constants.HIERARCHY])
- ## }
-
- ## Animation {
- properties.option_animation_morph = settings.get(
- constants.MORPH_TARGETS,
- constants.EXPORT_OPTIONS[constants.MORPH_TARGETS])
-
- properties.option_blend_shape = settings.get(
- constants.BLEND_SHAPES,
- constants.EXPORT_OPTIONS[constants.BLEND_SHAPES])
-
- properties.option_animation_skeletal = settings.get(
- constants.ANIMATION,
- constants.EXPORT_OPTIONS[constants.ANIMATION])
-
- properties.option_keyframes = settings.get(
- constants.KEYFRAMES,
- constants.EXPORT_OPTIONS[constants.KEYFRAMES])
-
- properties.option_bake_keyframes = settings.get(
- constants.BAKE_KEYFRAMES,
- constants.EXPORT_OPTIONS[constants.BAKE_KEYFRAMES])
-
- properties.option_frame_step = settings.get(
- constants.FRAME_STEP,
- constants.EXPORT_OPTIONS[constants.FRAME_STEP])
-
- properties.option_frame_index_as_time = settings.get(
- constants.FRAME_INDEX_AS_TIME,
- constants.EXPORT_OPTIONS[constants.FRAME_INDEX_AS_TIME])
- ## }
-
-def set_settings(properties):
- """Set the export settings to the correct keys.
-
- :param properties:
- :returns: settings
- :rtype: dict
-
- """
- settings = {
- constants.VERTICES: properties.option_vertices,
- constants.FACES: properties.option_faces,
- constants.NORMALS: properties.option_normals,
- constants.SKINNING: properties.option_skinning,
- constants.BONES: properties.option_bones,
- constants.EXTRA_VGROUPS: properties.option_extra_vgroups,
- constants.APPLY_MODIFIERS: properties.option_apply_modifiers,
- constants.GEOMETRY_TYPE: properties.option_geometry_type,
- constants.INDEX_TYPE: properties.option_index_type,
-
- constants.MATERIALS: properties.option_materials,
- constants.UVS: properties.option_uv_coords,
- constants.FACE_MATERIALS: properties.option_face_materials,
- constants.MAPS: properties.option_maps,
- constants.COLORS: properties.option_colors,
- constants.MIX_COLORS: properties.option_mix_colors,
-
- constants.SCALE: properties.option_scale,
- constants.ENABLE_PRECISION: properties.option_round_off,
- constants.PRECISION: properties.option_round_value,
- constants.CUSTOM_PROPERTIES: properties.option_custom_properties,
- constants.LOGGING: properties.option_logging,
- constants.COMPRESSION: properties.option_compression,
- constants.INDENT: properties.option_indent,
- constants.EXPORT_TEXTURES: properties.option_export_textures,
- constants.EMBED_TEXTURES: properties.option_embed_textures,
- constants.TEXTURE_FOLDER: properties.option_texture_folder,
-
- constants.SCENE: properties.option_export_scene,
- #constants.EMBED_GEOMETRY: properties.option_embed_geometry,
- constants.EMBED_ANIMATION: properties.option_embed_animation,
- constants.LIGHTS: properties.option_lights,
- constants.CAMERAS: properties.option_cameras,
- constants.HIERARCHY: properties.option_hierarchy,
-
- constants.MORPH_TARGETS: properties.option_animation_morph,
- constants.BLEND_SHAPES: properties.option_blend_shape,
- constants.ANIMATION: properties.option_animation_skeletal,
- constants.KEYFRAMES: properties.option_keyframes,
- constants.BAKE_KEYFRAMES: properties.option_bake_keyframes,
- constants.FRAME_STEP: properties.option_frame_step,
- constants.FRAME_INDEX_AS_TIME: properties.option_frame_index_as_time,
- constants.INFLUENCES_PER_VERTEX: properties.option_influences
- }
-
- return settings
-
-
-def compression_types():
- """Supported compression formats
-
- :rtype: tuple
-
- """
- types = [(constants.NONE, constants.NONE, constants.NONE)]
-
- try:
- import msgpack
- types.append((constants.MSGPACK, constants.MSGPACK,
- constants.MSGPACK))
- except ImportError:
- pass
-
- return types
-
-
-def animation_options():
- """The supported skeletal animation types
-
- :returns: list of tuples
-
- """
- anim = [
- (constants.OFF, constants.OFF.title(), constants.OFF),
- (constants.POSE, constants.POSE.title(), constants.POSE),
- (constants.REST, constants.REST.title(), constants.REST)
- ]
-
- return anim
-
-def resolve_conflicts(self, context):
- if(not self.option_export_textures):
- self.option_embed_textures = False;
-
-class ExportThree(bpy.types.Operator, ExportHelper):
- """Class that handles the export properties"""
-
- bl_idname = 'export.three'
- bl_label = 'Export THREE'
- bl_options = {'PRESET'}
-
- filename_ext = constants.EXTENSION
-
- option_vertices = BoolProperty(
- name="Vertices",
- description="Export vertices",
- default=constants.EXPORT_OPTIONS[constants.VERTICES])
-
- option_faces = BoolProperty(
- name="Faces",
- description="Export faces (Geometry only)",
- default=constants.EXPORT_OPTIONS[constants.FACES])
-
- option_normals = BoolProperty(
- name="Normals",
- description="Export normals",
- default=constants.EXPORT_OPTIONS[constants.NORMALS])
-
- option_colors = BoolProperty(
- name="Vertex Colors",
- description="Export vertex colors",
- default=constants.EXPORT_OPTIONS[constants.COLORS])
-
- option_mix_colors = BoolProperty(
- name="Mix Colors",
- description="Mix material and vertex colors",
- default=constants.EXPORT_OPTIONS[constants.MIX_COLORS])
-
- option_uv_coords = BoolProperty(
- name="UVs",
- description="Export texture coordinates",
- default=constants.EXPORT_OPTIONS[constants.UVS])
-
- option_materials = BoolProperty(
- name="Materials",
- description="Export materials",
- default=constants.EXPORT_OPTIONS[constants.MATERIALS])
-
- option_face_materials = BoolProperty(
- name="Face Materials",
- description="Face mapping materials (Geometry only)",
- default=constants.EXPORT_OPTIONS[constants.FACE_MATERIALS])
-
- option_maps = BoolProperty(
- name="Textures",
- description="Include texture maps",
- default=constants.EXPORT_OPTIONS[constants.MAPS])
-
- option_skinning = BoolProperty(
- name="Skinning",
- description="Export skin data",
- default=constants.EXPORT_OPTIONS[constants.SKINNING])
-
- option_bones = BoolProperty(
- name="Bones",
- description="Export bones",
- default=constants.EXPORT_OPTIONS[constants.BONES])
-
- option_extra_vgroups = StringProperty(
- name="Extra Vertex Groups",
- description="Non-skinning vertex groups to export (comma-separated, w/ star wildcard, BufferGeometry only).",
- default=constants.EXPORT_OPTIONS[constants.EXTRA_VGROUPS])
-
- option_apply_modifiers = BoolProperty(
- name="Apply Modifiers",
- description="Apply Modifiers to mesh objects",
- default=constants.EXPORT_OPTIONS[constants.APPLY_MODIFIERS]
- )
-
- index_buffer_types = [
- (constants.NONE,) * 3,
- (constants.UINT_16,) * 3,
- (constants.UINT_32,) * 3]
-
- option_index_type = EnumProperty(
- name="Index Buffer",
- description="Index buffer type that will be used for BufferGeometry objects.",
- items=index_buffer_types,
- default=constants.EXPORT_OPTIONS[constants.INDEX_TYPE])
-
- option_scale = FloatProperty(
- name="Scale",
- description="Scale vertices",
- min=0.01,
- max=1000.0,
- soft_min=0.01,
- soft_max=1000.0,
- default=constants.EXPORT_OPTIONS[constants.SCALE])
-
- option_round_off = BoolProperty(
- name="Enable Precision",
- description="Round off floating point values",
- default=constants.EXPORT_OPTIONS[constants.ENABLE_PRECISION])
-
- option_round_value = IntProperty(
- name="",
- min=0,
- max=16,
- description="Floating point precision",
- default=constants.EXPORT_OPTIONS[constants.PRECISION])
-
- option_custom_properties = BoolProperty(
- name="Custom Properties",
- description="Export custom properties as userData",
- default=False)
-
- logging_types = [
- (constants.DISABLED, constants.DISABLED, constants.DISABLED),
- (constants.DEBUG, constants.DEBUG, constants.DEBUG),
- (constants.INFO, constants.INFO, constants.INFO),
- (constants.WARNING, constants.WARNING, constants.WARNING),
- (constants.ERROR, constants.ERROR, constants.ERROR),
- (constants.CRITICAL, constants.CRITICAL, constants.CRITICAL)]
-
- option_logging = EnumProperty(
- name="",
- description="Logging verbosity level",
- items=logging_types,
- default=constants.DISABLED)
-
- option_geometry_type = EnumProperty(
- name="Type",
- description="Geometry type",
- items=_geometry_types()[1:],
- default=constants.EXPORT_OPTIONS[constants.GEOMETRY_TYPE])
-
- option_export_scene = BoolProperty(
- name="Scene",
- description="Export scene",
- default=constants.EXPORT_OPTIONS[constants.SCENE])
-
- #@TODO: removing this option since the ObjectLoader doesn't have
- # support for handling external geometry data
- #option_embed_geometry = BoolProperty(
- # name="Embed geometry",
- # description="Embed geometry",
- # default=constants.EXPORT_OPTIONS[constants.EMBED_GEOMETRY])
-
- option_embed_animation = BoolProperty(
- name="Embed animation",
- description="Embed animation data with the geometry data",
- default=constants.EXPORT_OPTIONS[constants.EMBED_ANIMATION])
-
- option_export_textures = BoolProperty(
- name="Export textures",
- description="Export textures",
- default=constants.EXPORT_OPTIONS[constants.EXPORT_TEXTURES],
- update=resolve_conflicts)
-
- option_embed_textures = BoolProperty(
- name="Embed textures",
- description="Embed base64 textures in .json",
- default=constants.EXPORT_OPTIONS[constants.EMBED_TEXTURES])
-
- option_texture_folder = StringProperty(
- name="Texture folder",
- description="add this folder to textures path",
- default=constants.EXPORT_OPTIONS[constants.TEXTURE_FOLDER])
-
- option_lights = BoolProperty(
- name="Lights",
- description="Export default scene lights",
- default=False)
-
- option_cameras = BoolProperty(
- name="Cameras",
- description="Export default scene cameras",
- default=False)
-
- option_hierarchy = BoolProperty(
- name="Hierarchy",
- description="Export object hierarchy",
- default=False)
-
- option_animation_morph = BoolProperty(
- name="Morph animation",
- description="Export animation (morphs)",
- default=constants.EXPORT_OPTIONS[constants.MORPH_TARGETS])
-
- option_blend_shape = BoolProperty(
- name="Blend Shape animation",
- description="Export Blend Shapes",
- default=constants.EXPORT_OPTIONS[constants.BLEND_SHAPES])
-
- option_animation_skeletal = EnumProperty(
- name="",
- description="Export animation (skeletal)",
- items=animation_options(),
- default=constants.OFF)
-
- option_keyframes = BoolProperty(
- name="Keyframe animation",
- description="Export animation (keyframes)",
- default=constants.EXPORT_OPTIONS[constants.KEYFRAMES])
-
- option_bake_keyframes = BoolProperty(
- name="Bake keyframe animation",
- description="Bake keyframe animation each frame step",
- default=constants.EXPORT_OPTIONS[constants.BAKE_KEYFRAMES])
-
- option_frame_index_as_time = BoolProperty(
- name="Frame index as time",
- description="Use (original) frame index as frame time",
- default=constants.EXPORT_OPTIONS[constants.FRAME_INDEX_AS_TIME])
-
- option_frame_step = IntProperty(
- name="Frame step",
- description="Animation frame step",
- min=1,
- max=1000,
- soft_min=1,
- soft_max=1000,
- default=1)
-
- option_indent = BoolProperty(
- name="Indent JSON",
- description="Disable this to reduce the file size",
- default=constants.EXPORT_OPTIONS[constants.INDENT])
-
- option_compression = EnumProperty(
- name="",
- description="Compression options",
- items=compression_types(),
- default=constants.NONE)
-
- option_influences = IntProperty(
- name="Influences",
- description="Maximum number of bone influences",
- min=1,
- max=4,
- default=2)
-
- def invoke(self, context, event):
-
- settings = context.scene.get(constants.EXPORT_SETTINGS_KEY)
- if settings:
- try:
- restore_export_settings(self.properties, settings)
- except AttributeError as e:
- logging.error("Loading export settings failed:")
- logging.exception(e)
- logging.debug("Removed corrupted settings")
-
- del context.scene[constants.EXPORT_SETTINGS_KEY]
-
- return ExportHelper.invoke(self, context, event)
-
- @classmethod
- def poll(cls, context):
- """
-
- :param context:
-
- """
- return context.active_object is not None
-
- def execute(self, context):
- """
-
- :param context:
-
- """
-
- if not self.properties.filepath:
- raise Exception("filename not set")
-
- settings = set_settings(self.properties)
- settings['addon_version'] = bl_info['version']
-
- filepath = self.filepath
- if settings[constants.COMPRESSION] == constants.MSGPACK:
- filepath = "%s%s" % (filepath[:-4], constants.PACK)
-
- from io_three import exporter
- if settings[constants.SCENE]:
- exporter.export_scene(filepath, settings)
- else:
- exporter.export_geometry(filepath, settings)
-
- return {'FINISHED'}
-
- def draw(self, context):
- """
-
- :param context:
-
- """
-
- using_geometry = self.option_geometry_type == constants.GEOMETRY
-
- layout = self.layout
-
- ## Scene {
- box = layout.box()
- column = box.column(True)
- row = column.row(True)
- row.alignment = 'CENTER'
-
- row.label(text="SCENE", icon="SCENE_DATA")
-
- row = box.row()
- row.prop(self.properties, 'option_export_scene')
- row.prop(self.properties, 'option_materials')
-
- #row = box.row()
- #row.prop(self.properties, 'option_embed_geometry')
-
- row = box.row()
- row.prop(self.properties, 'option_lights')
- row.prop(self.properties, 'option_cameras')
-
- row = box.row()
- row.prop(self.properties, 'option_hierarchy')
- ## }
-
- layout.separator()
-
- ## Geometry {
- box = layout.box()
- column = box.column(True)
- row = column.row(True)
- row.alignment = 'CENTER'
-
- row.label(text="GEOMETRY", icon="MESH_DATA")
-
- row = box.row()
- row.prop(self.properties, 'option_geometry_type')
-
- row = box.row()
- row.prop(self.properties, 'option_index_type')
-
- row = box.row()
- row.prop(self.properties, 'option_vertices')
- col = row.column()
- col.prop(self.properties, 'option_faces')
- col.enabled = using_geometry
-
- row = box.row()
- row.prop(self.properties, 'option_normals')
- row.prop(self.properties, 'option_uv_coords')
-
- row = box.row()
- row.prop(self.properties, 'option_apply_modifiers')
-
- row = box.row()
- row.prop(self.properties, 'option_extra_vgroups')
- row.enabled = not using_geometry
- ## }
-
- layout.separator()
-
- ## Materials {
- box = layout.box()
- column = box.column(True)
- row = column.row(True)
- row.alignment = 'CENTER'
- row.label(text="MATERIAL", icon="MATERIAL_DATA")
-
- row = box.row()
- row.prop(self.properties, 'option_colors')
- row.prop(self.properties, 'option_mix_colors')
-
- row = box.row()
- row.prop(self.properties, 'option_face_materials')
- row.enabled = using_geometry
- ## }
-
- layout.separator()
-
- ## Textures {
- box = layout.box()
- column = box.column(True)
- row = column.row(True)
- row.alignment = 'CENTER'
-
- row.label(text="TEXTURE", icon="TEXTURE_DATA")
-
- row = box.row()
- row.prop(self.properties, 'option_maps')
- row.prop(self.properties, 'option_export_textures')
-
- row = box.row()
- row.prop(self.properties, 'option_embed_textures')
- row.enabled = self.properties.option_export_textures
-
- row = box.row()
- row.prop(self.properties, 'option_texture_folder')
- ## }
-
- layout.separator()
-
- ## Armature {
- box = layout.box()
- column = box.column(True)
- row = column.row(True)
- row.alignment = 'CENTER'
-
- row.label(text="ARMATURE", icon="ARMATURE_DATA")
-
- row = box.row()
- row.prop(self.properties, 'option_bones')
- row.prop(self.properties, 'option_skinning')
- ## }
-
- layout.separator()
-
- ## Animation {
- box = layout.box()
- column = box.column(True)
- row = column.row(True)
- row.alignment = 'CENTER'
-
- row.label(text="ANIMATION", icon="POSE_DATA")
-
- row = box.row()
- row.prop(self.properties, 'option_animation_morph')
- row.prop(self.properties, 'option_blend_shape')
-
- row = box.row()
- row.label(text="Skeletal animations:")
- row.prop(self.properties, 'option_animation_skeletal')
-
- row = box.row()
- row.prop(self.properties, 'option_keyframes')
-
- row = box.row()
- row.prop(self.properties, 'option_bake_keyframes')
-
- row = box.row()
- row.prop(self.properties, 'option_influences')
-
- row = box.row()
- row.prop(self.properties, 'option_frame_step')
-
- row = box.row()
- row.prop(self.properties, 'option_frame_index_as_time')
-
- row = box.row()
- row.prop(self.properties, 'option_embed_animation')
- ## }
-
- layout.separator()
-
- ## Settings {
- box = layout.box()
- column = box.column(True)
- row = column.row(True)
- row.alignment = 'CENTER'
-
- row.label(text="SETTINGS", icon="SETTINGS")
-
- row = box.row()
- row.prop(self.properties, 'option_scale')
-
- row = box.row()
- row.prop(self.properties, 'option_round_off')
- row.prop(self.properties, 'option_round_value')
-
- row = box.row()
- row.prop(self.properties, 'option_custom_properties')
-
- row = box.row()
- row.prop(self.properties, 'option_indent')
-
- row = box.row()
- row.label(text="Logging verbosity:")
- row.prop(self.properties, 'option_logging')
-
- row = box.row()
- row.label(text="File compression format:")
- row.prop(self.properties, 'option_compression')
- ## }
-
- ## Operators {
- has_settings = context.scene.get(constants.EXPORT_SETTINGS_KEY, False)
- row = layout.row()
- row.operator(
- ThreeExportSettings.bl_idname,
- ThreeExportSettings.bl_label,
- icon="%s" % "PINNED" if has_settings else "UNPINNED")
- ## }
-
-
-
-def menu_func_export(self, context):
- """
-
- :param self:
- :param context:
-
- """
- default_path = bpy.data.filepath.replace('.blend', constants.EXTENSION)
- text = "Three.js (%s)" % constants.EXTENSION
- operator = self.layout.operator(ExportThree.bl_idname, text=text)
- operator.filepath = default_path
-
-
-def register():
- """Registers the addon (Blender boilerplate)"""
- bpy.utils.register_module(__name__)
- bpy.types.INFO_MT_file_export.append(menu_func_export)
-
-
-def unregister():
- """Unregisters the addon (Blender boilerplate)"""
- bpy.utils.unregister_module(__name__)
- bpy.types.INFO_MT_file_export.remove(menu_func_export)
-
-
-if __name__ == '__main__':
- register()
diff --git a/utils/exporters/blender/addons/io_three/constants.py b/utils/exporters/blender/addons/io_three/constants.py
deleted file mode 100644
index 7dc1f6fb480153d171fe9f6b20c3df9509c4db25..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/constants.py
+++ /dev/null
@@ -1,398 +0,0 @@
-'''
-All constant data used in the package should be defined here.
-'''
-
-from collections import OrderedDict as BASE_DICT
-
-BLENDING_TYPES = type('Blending', (), {
- 'NONE': 'NoBlending',
- 'NORMAL': 'NormalBlending',
- 'ADDITIVE': 'AdditiveBlending',
- 'SUBTRACTIVE': 'SubtractiveBlending',
- 'MULTIPLY': 'MultiplyBlending',
- 'CUSTOM': 'CustomBlending'
-})
-
-BLENDING_CONSTANTS = type('BlendingConstant', (), {
- 'NoBlending':0,
- 'NormalBlending':1,
- 'AdditiveBlending':2,
- 'SubtractiveBlending':3,
- 'MultiplyBlending':4,
- 'CustomBlending':5
-})
-
-NEAREST_FILTERS = type('NearestFilters', (), {
- 'NEAREST': 'NearestFilter',
- 'MIP_MAP_NEAREST': 'NearestMipMapNearestFilter',
- 'MIP_MAP_LINEAR': 'NearestMipMapLinearFilter'
-})
-
-LINEAR_FILTERS = type('LinearFilters', (), {
- 'LINEAR': 'LinearFilter',
- 'MIP_MAP_NEAREST': 'LinearMipMapNearestFilter',
- 'MIP_MAP_LINEAR': 'LinearMipMapLinearFilter'
-})
-
-MAPPING_TYPES = type('Mapping', (), {
- 'UV': 'UVMapping',
- 'CUBE_REFLECTION': 'CubeReflectionMapping',
- 'CUBE_REFRACTION': 'CubeRefractionMapping',
- 'SPHERICAL_REFLECTION': 'SphericalReflectionMapping'
-})
-
-NUMERIC = {
- 'UVMapping': 300,
- 'CubeReflectionMapping': 301,
- 'CubeRefractionMapping': 302,
- 'EquirectangularReflectionMapping': 303,
- 'EquirectangularRefractionMapping': 304,
- 'SphericalReflectionMapping': 305,
-
- 'RepeatWrapping': 1000,
- 'repeat': 1000,
- 'ClampToEdgeWrapping': 1001,
- 'MirroredRepeatWrapping': 1002,
-
- 'NearestFilter': 1003,
- 'NearestMipMapNearestFilter': 1004,
- 'NearestMipMapLinearFilter': 1005,
- 'LinearFilter': 1006,
- 'LinearMipMapNearestFilter': 1007,
- 'LinearMipMapLinearFilter': 1008
-}
-JSON = 'json'
-EXTENSION = '.%s' % JSON
-INDENT = 'indent'
-
-
-MATERIALS = 'materials'
-SCENE = 'scene'
-VERTICES = 'vertices'
-FACES = 'faces'
-NORMALS = 'normals'
-BONES = 'bones'
-UVS = 'uvs'
-APPLY_MODIFIERS = 'applyModifiers'
-COLORS = 'colors'
-MIX_COLORS = 'mixColors'
-EXTRA_VGROUPS = 'extraVertexGroups'
-INDEX = 'index'
-DRAW_CALLS = 'drawcalls'
-DC_START = 'start'
-DC_COUNT = 'count'
-DC_INDEX = 'index'
-
-GROUPS = 'groups'
-
-SCALE = 'scale'
-COMPRESSION = 'compression'
-MAPS = 'maps'
-FRAME_STEP = 'frameStep'
-FRAME_INDEX_AS_TIME = 'frameIndexAsTime'
-ANIMATION = 'animations'
-CLIPS="clips"
-KEYFRAMES = 'tracks'
-BAKE_KEYFRAMES = 'bake_tracks'
-MORPH_TARGETS = 'morphTargets'
-MORPH_TARGETS_ANIM = 'morphTargetsAnimation'
-BLEND_SHAPES = 'blendShapes'
-POSE = 'pose'
-REST = 'rest'
-SKIN_INDICES = 'skinIndices'
-SKIN_WEIGHTS = 'skinWeights'
-LOGGING = 'logging'
-CAMERAS = 'cameras'
-LIGHTS = 'lights'
-HIERARCHY = 'hierarchy'
-FACE_MATERIALS = 'faceMaterials'
-SKINNING = 'skinning'
-EXPORT_TEXTURES = 'exportTextures'
-EMBED_TEXTURES = 'embedTextures'
-TEXTURE_FOLDER = 'textureFolder'
-ENABLE_PRECISION = 'enablePrecision'
-PRECISION = 'precision'
-DEFAULT_PRECISION = 6
-CUSTOM_PROPERTIES = 'customProperties'
-EMBED_GEOMETRY = 'embedGeometry'
-EMBED_ANIMATION = 'embedAnimation'
-OFF = 'off'
-
-GLOBAL = 'global'
-BUFFER_GEOMETRY = 'BufferGeometry'
-GEOMETRY = 'geometry'
-GEOMETRY_TYPE = 'geometryType'
-INDEX_TYPE = 'indexType'
-
-CRITICAL = 'critical'
-ERROR = 'error'
-WARNING = 'warning'
-INFO = 'info'
-DEBUG = 'debug'
-DISABLED = 'disabled'
-
-NONE = 'None'
-MSGPACK = 'msgpack'
-
-PACK = 'pack'
-
-FLOAT_32 = 'Float32Array'
-UINT_16 = 'Uint16Array'
-UINT_32 = 'Uint32Array'
-
-INFLUENCES_PER_VERTEX = 'influencesPerVertex'
-
-EXPORT_OPTIONS = {
- FACES: True,
- VERTICES: True,
- NORMALS: True,
- UVS: True,
- APPLY_MODIFIERS: True,
- COLORS: False,
- EXTRA_VGROUPS: '',
- INDEX_TYPE: UINT_16,
- MATERIALS: False,
- FACE_MATERIALS: False,
- SCALE: 1,
- FRAME_STEP: 1,
- FRAME_INDEX_AS_TIME: False,
- SCENE: False,
- MIX_COLORS: False,
- COMPRESSION: None,
- MAPS: False,
- ANIMATION: OFF,
- KEYFRAMES: False,
- BAKE_KEYFRAMES: False,
- BONES: False,
- SKINNING: False,
- MORPH_TARGETS: False,
- BLEND_SHAPES: False,
- CAMERAS: False,
- LIGHTS: False,
- HIERARCHY: False,
- EXPORT_TEXTURES: True,
- EMBED_TEXTURES: False,
- TEXTURE_FOLDER: '',
- LOGGING: DEBUG,
- ENABLE_PRECISION: False,
- PRECISION: DEFAULT_PRECISION,
- CUSTOM_PROPERTIES: False,
- EMBED_GEOMETRY: True,
- EMBED_ANIMATION: True,
- GEOMETRY_TYPE: BUFFER_GEOMETRY,
- INFLUENCES_PER_VERTEX: 2,
- INDENT: True
-}
-
-
-FORMAT_VERSION = 4.4
-VERSION = 'version'
-THREE = 'io_three'
-GENERATOR = 'generator'
-SOURCE_FILE = 'sourceFile'
-VALID_DATA_TYPES = (str, int, float, bool, list, tuple, dict)
-
-JSON = 'json'
-GZIP = 'gzip'
-
-EXTENSIONS = {
- JSON: '.json',
- MSGPACK: '.pack',
- GZIP: '.gz'
-}
-
-METADATA = 'metadata'
-GEOMETRIES = 'geometries'
-IMAGES = 'images'
-TEXTURE = 'texture'
-TEXTURES = 'textures'
-
-USER_DATA = 'userData'
-DATA = 'data'
-TYPE = 'type'
-
-MATERIAL = 'material'
-OBJECT = 'object'
-PERSPECTIVE_CAMERA = 'PerspectiveCamera'
-ORTHOGRAPHIC_CAMERA = 'OrthographicCamera'
-AMBIENT_LIGHT = 'AmbientLight'
-DIRECTIONAL_LIGHT = 'DirectionalLight'
-POINT_LIGHT = 'PointLight'
-SPOT_LIGHT = 'SpotLight'
-# TODO (abelnation): confirm this is correct area light string for exporter
-RECT_AREA_LIGHT = 'RectAreaLight'
-HEMISPHERE_LIGHT = 'HemisphereLight'
-# TODO: RectAreaLight support
-MESH = 'Mesh'
-EMPTY = 'Empty'
-SPRITE = 'Sprite'
-
-DEFAULT_METADATA = {
- VERSION: FORMAT_VERSION,
- TYPE: OBJECT.title(),
- GENERATOR: THREE
-}
-
-UUID = 'uuid'
-
-MATRIX = 'matrix'
-POSITION = 'position'
-QUATERNION = 'quaternion'
-ROTATION = 'rotation'
-SCALE = 'scale'
-
-UV = 'uv'
-UV2 = 'uv2'
-ATTRIBUTES = 'attributes'
-NORMAL = 'normal'
-ITEM_SIZE = 'itemSize'
-ARRAY = 'array'
-
-VISIBLE = 'visible'
-CAST_SHADOW = 'castShadow'
-RECEIVE_SHADOW = 'receiveShadow'
-QUAD = 'quad'
-
-MASK = {
- QUAD: 0,
- MATERIALS: 1,
- UVS: 3,
- NORMALS: 5,
- COLORS: 7
-}
-
-
-CHILDREN = 'children'
-
-URL = 'url'
-WRAP = 'wrap'
-REPEAT = 'repeat'
-WRAPPING = type('Wrapping', (), {
- 'REPEAT': 'repeat',
- 'CLAMP': 'clamp',
- 'MIRROR': 'mirror'
-})
-ANISOTROPY = 'anisotropy'
-MAG_FILTER = 'magFilter'
-MIN_FILTER = 'minFilter'
-MAPPING = 'mapping'
-
-IMAGE = 'image'
-
-NAME = 'name'
-PARENT = 'parent'
-LENGTH = 'length'
-FPS = 'fps'
-HIERARCHY = 'hierarchy'
-POS = 'pos'
-ROTQ = 'rotq'
-ROT = 'rot'
-SCL = 'scl'
-TIME = 'time'
-KEYS = 'keys'
-
-COLOR = 'color'
-EMISSIVE = 'emissive'
-SPECULAR = 'specular'
-SPECULAR_COEF = 'specularCoef'
-SHININESS = 'shininess'
-SIDE = 'side'
-OPACITY = 'opacity'
-TRANSPARENT = 'transparent'
-WIREFRAME = 'wireframe'
-BLENDING = 'blending'
-VERTEX_COLORS = 'vertexColors'
-DEPTH_WRITE = 'depthWrite'
-DEPTH_TEST = 'depthTest'
-
-MAP = 'map'
-SPECULAR_MAP = 'specularMap'
-LIGHT_MAP = 'lightMap'
-BUMP_MAP = 'bumpMap'
-BUMP_SCALE = 'bumpScale'
-NORMAL_MAP = 'normalMap'
-NORMAL_SCALE = 'normalScale'
-
-#@TODO ENV_MAP, REFLECTIVITY, REFRACTION_RATIO, COMBINE
-
-MAP_DIFFUSE = 'mapDiffuse'
-MAP_DIFFUSE_REPEAT = 'mapDiffuseRepeat'
-MAP_DIFFUSE_WRAP = 'mapDiffuseWrap'
-MAP_DIFFUSE_ANISOTROPY = 'mapDiffuseAnisotropy'
-
-MAP_SPECULAR = 'mapSpecular'
-MAP_SPECULAR_REPEAT = 'mapSpecularRepeat'
-MAP_SPECULAR_WRAP = 'mapSpecularWrap'
-MAP_SPECULAR_ANISOTROPY = 'mapSpecularAnisotropy'
-
-MAP_LIGHT = 'mapLight'
-MAP_LIGHT_REPEAT = 'mapLightRepeat'
-MAP_LIGHT_WRAP = 'mapLightWrap'
-MAP_LIGHT_ANISOTROPY = 'mapLightAnisotropy'
-
-MAP_NORMAL = 'mapNormal'
-MAP_NORMAL_FACTOR = 'mapNormalFactor'
-MAP_NORMAL_REPEAT = 'mapNormalRepeat'
-MAP_NORMAL_WRAP = 'mapNormalWrap'
-MAP_NORMAL_ANISOTROPY = 'mapNormalAnisotropy'
-
-MAP_BUMP = 'mapBump'
-MAP_BUMP_REPEAT = 'mapBumpRepeat'
-MAP_BUMP_WRAP = 'mapBumpWrap'
-MAP_BUMP_ANISOTROPY = 'mapBumpAnisotropy'
-MAP_BUMP_SCALE = 'mapBumpScale'
-
-NORMAL_BLENDING = 0
-
-VERTEX_COLORS_ON = 2
-VERTEX_COLORS_OFF = 0
-
-SIDE_DOUBLE = 2
-
-THREE_BASIC = 'MeshBasicMaterial'
-THREE_LAMBERT = 'MeshLambertMaterial'
-THREE_PHONG = 'MeshPhongMaterial'
-
-INTENSITY = 'intensity'
-DISTANCE = 'distance'
-ANGLE = 'angle'
-DECAY = 'decayExponent'
-
-FOV = 'fov'
-ASPECT = 'aspect'
-NEAR = 'near'
-FAR = 'far'
-
-LEFT = 'left'
-RIGHT = 'right'
-TOP = 'top'
-BOTTOM = 'bottom'
-
-SHADING = 'shading'
-COLOR_DIFFUSE = 'colorDiffuse'
-COLOR_EMISSIVE = 'colorEmissive'
-COLOR_SPECULAR = 'colorSpecular'
-DBG_NAME = 'DbgName'
-DBG_COLOR = 'DbgColor'
-DBG_INDEX = 'DbgIndex'
-EMIT = 'emit'
-
-PHONG = 'phong'
-LAMBERT = 'lambert'
-BASIC = 'basic'
-
-NORMAL_BLENDING = 'NormalBlending'
-
-DBG_COLORS = (0xeeeeee, 0xee0000, 0x00ee00, 0x0000ee,
- 0xeeee00, 0x00eeee, 0xee00ee)
-
-DOUBLE_SIDED = 'doubleSided'
-
-EXPORT_SETTINGS_KEY = 'threeExportSettings'
-
-# flips vectors
-
-XZ_Y = "XZ_Y"
-X_ZY = "X_ZY"
-XYZ = "XYZ"
-_XY_Z = "_XY_Z"
diff --git a/utils/exporters/blender/addons/io_three/dialogs.py b/utils/exporters/blender/addons/io_three/dialogs.py
deleted file mode 100644
index 01baf18eeb2f29755fed09ec528566424370e50c..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/dialogs.py
+++ /dev/null
@@ -1,112 +0,0 @@
-from bpy import context
-
-CONTEXT = {
- 0: {
- 'title': "Error Message",
- 'icon': 'CANCEL'
- },
- 1: {
- 'title': "Warning Message",
- 'icon': 'ERROR' # I prefer this icon for warnings
- },
- 2: {
- 'title': "Message",
- 'icon': 'NONE'
- },
- 3: {
- 'title': "Question",
- 'icon': 'QUESTION'
- }
-}
-
-
-def error(message, title="", wrap=40):
- """Creates an error dialog.
-
- :param message: text of the message body
- :param title: text to append to the title
- (Default value = "")
- :param wrap: line width (Default value = 40)
-
- """
- _draw(message, title, wrap, 0)
-
-
-def warning(message, title="", wrap=40):
- """Creates an error dialog.
-
- :param message: text of the message body
- :param title: text to append to the title
- (Default value = "")
- :param wrap: line width (Default value = 40)
-
- """
- _draw(message, title, wrap, 1)
-
-
-
-def info(message, title="", wrap=40):
- """Creates an error dialog.
-
- :param message: text of the message body
- :param title: text to append to the title
- (Default value = "")
- :param wrap: line width (Default value = 40)
-
- """
- _draw(message, title, wrap, 2)
-
-
-
-def question(message, title="", wrap=40):
- """Creates an error dialog.
-
- :param message: text of the message body
- :param title: text to append to the title
- (Default value = "")
- :param wrap: line width (Default value = 40)
-
- """
- _draw(message, title, wrap, 3)
-
-
-
-# Great idea borrowed from
-# http://community.cgcookie.com/t/code-snippet-easy-error-messages/203
-def _draw(message, title, wrap, key):
- """
-
- :type message: str
- :type title: str
- :type wrap: int
- :type key: int
-
- """
- lines = []
- if wrap > 0:
- while len(message) > wrap:
- i = message.rfind(' ', 0, wrap)
- if i == -1:
- lines += [message[:wrap]]
- message = message[wrap:]
- else:
- lines += [message[:i]]
- message = message[i+1:]
- if message:
- lines += [message]
-
- def draw(self, *args):
- """
-
- :param self:
- :param *args:
-
- """
- for line in lines:
- self.layout.label(line)
-
- title = "%s: %s" % (title, CONTEXT[key]['title'])
- icon = CONTEXT[key]['icon']
-
- context.window_manager.popup_menu(
- draw, title=title.strip(), icon=icon)
diff --git a/utils/exporters/blender/addons/io_three/exceptions.py b/utils/exporters/blender/addons/io_three/exceptions.py
deleted file mode 100644
index bf4cf7ee8d67b8444fcdd6c7632c197ccf5a62fe..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/exceptions.py
+++ /dev/null
@@ -1,9 +0,0 @@
-class ThreeError(Exception): pass
-class UnimplementedFeatureError(ThreeError): pass
-class ThreeValueError(ThreeError): pass
-class UnsupportedObjectType(ThreeError): pass
-class GeometryError(ThreeError): pass
-class MaterialError(ThreeError): pass
-class SelectionError(ThreeError): pass
-class NGonError(ThreeError): pass
-class BufferGeometryError(ThreeError): pass
diff --git a/utils/exporters/blender/addons/io_three/exporter/__init__.py b/utils/exporters/blender/addons/io_three/exporter/__init__.py
deleted file mode 100644
index 3ca23d63b70e7863fc84652f735eac767919c678..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/exporter/__init__.py
+++ /dev/null
@@ -1,96 +0,0 @@
-import os
-import sys
-import traceback
-from .. import constants, logger, exceptions, dialogs
-from . import scene, geometry, api, base_classes
-
-
-def _error_handler(func):
-
- def inner(filepath, options, *args, **kwargs):
- level = options.get(constants.LOGGING, constants.DISABLED)
- version = options.get('addon_version')
- if level != constants.DISABLED:
- logger.init('io_three.export.log', level=level)
- if version is not None:
- logger.debug("Addon Version %s", version)
- api.init()
-
- try:
- func(filepath, options, *args, **kwargs)
- except:
- info = sys.exc_info()
- trace = traceback.format_exception(
- info[0], info[1], info[2].tb_next)
- trace = ''.join(trace)
- logger.error(trace)
-
- print('Error recorded to %s' % logger.LOG_FILE)
-
- raise
- else:
- print('Log: %s' % logger.LOG_FILE)
-
- return inner
-
-
-@_error_handler
-def export_scene(filepath, options):
- selected = []
-
- # during scene exports unselect everything. this is needed for
- # applying modifiers, if it is necessary
- # record the selected nodes so that selection is restored later
- for obj in api.selected_objects():
- api.object.unselect(obj)
- selected.append(obj)
- active = api.active_object()
-
- try:
- scene_ = scene.Scene(filepath, options=options)
- scene_.parse()
- scene_.write()
- except:
- _restore_selection(selected, active)
- raise
-
- _restore_selection(selected, active)
-
-
-@_error_handler
-def export_geometry(filepath, options, node=None):
- msg = ""
- exception = None
- if node is None:
- node = api.active_object()
- if node is None:
- msg = "Nothing selected"
- logger.error(msg)
- exception = exceptions.SelectionError
- if node.type != 'MESH':
- msg = "%s is not a valid mesh object" % node.name
- logger.error(msg)
- exception = exceptions.GeometryError
-
- if exception is not None:
- if api.batch_mode():
- raise exception(msg)
- else:
- dialogs.error(msg)
- return
-
- mesh = api.object.mesh(node, options)
- parent = base_classes.BaseScene(filepath, options)
- geo = geometry.Geometry(mesh, parent)
- geo.parse()
- geo.write()
-
- if not options.get(constants.EMBED_ANIMATION, True):
- geo.write_animation(os.path.dirname(filepath))
-
-
-def _restore_selection(objects, active):
- for obj in objects:
- api.object.select(obj)
-
- api.set_active_object(active)
diff --git a/utils/exporters/blender/addons/io_three/exporter/_json.py b/utils/exporters/blender/addons/io_three/exporter/_json.py
deleted file mode 100644
index 50031c323d07a87d75ef210aa58888ee51378f2a..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/exporter/_json.py
+++ /dev/null
@@ -1,208 +0,0 @@
-import json
-from .. import constants
-
-ROUND = constants.DEFAULT_PRECISION
-
-## THREE override function
-def _json_floatstr(o):
- if ROUND is not None:
- o = round(o, ROUND)
-
- return '%g' % o
-
-
-def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
- _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
- ## HACK: hand-optimized bytecode; turn globals into locals
- ValueError=ValueError,
- dict=dict,
- float=float,
- id=id,
- int=int,
- isinstance=isinstance,
- list=list,
- str=str,
- tuple=tuple,
- ):
- '''
- Overwrite json.encoder for Python 2.7 and above to not
- assign each index of a list or tuple to its own row as
- this is completely asinine behaviour
- '''
-
- ## @THREE
- # Override the function
- _floatstr = _json_floatstr
-
- if _indent is not None and not isinstance(_indent, str):
- _indent = ' ' * _indent
-
- def _iterencode_list(lst, _current_indent_level):
- if not lst:
- yield '[]'
- return
- if markers is not None:
- markerid = id(lst)
- if markerid in markers:
- raise ValueError("Circular reference detected")
- markers[markerid] = lst
- buf = '['
- ## @THREEJS
- # - block the moronic functionality that puts each
- # index on its own line causing insane row counts
- #if _indent is not None:
- # _current_indent_level += 1
- # newline_indent = '\n' + _indent * _current_indent_level
- # separator = _item_separator + newline_indent
- # buf += newline_indent
- #else:
- newline_indent = None
- separator = _item_separator
- first = True
- for value in lst:
- if first:
- first = False
- else:
- buf = separator
- if isinstance(value, str):
- yield buf + _encoder(value)
- elif value is None:
- yield buf + 'null'
- elif value is True:
- yield buf + 'true'
- elif value is False:
- yield buf + 'false'
- elif isinstance(value, int):
- yield buf + str(value)
- elif isinstance(value, float):
- yield buf + _floatstr(value)
- else:
- yield buf
- if isinstance(value, (list, tuple)):
- chunks = _iterencode_list(value, _current_indent_level)
- elif isinstance(value, dict):
- chunks = _iterencode_dict(value, _current_indent_level)
- else:
- chunks = _iterencode(value, _current_indent_level)
- for chunk in chunks:
- yield chunk
- if newline_indent is not None:
- _current_indent_level -= 1
- yield '\n' + _indent * _current_indent_level
- yield ']'
- if markers is not None:
- del markers[markerid]
-
- def _iterencode_dict(dct, _current_indent_level):
- if not dct:
- yield '{}'
- return
- if markers is not None:
- markerid = id(dct)
- if markerid in markers:
- raise ValueError("Circular reference detected")
- markers[markerid] = dct
- yield '{'
- if _indent is not None:
- _current_indent_level += 1
- newline_indent = '\n' + _indent * _current_indent_level
- item_separator = _item_separator + newline_indent
- yield newline_indent
- else:
- newline_indent = None
- item_separator = _item_separator
- first = True
- if _sort_keys:
- items = sorted(dct.items(), key=lambda kv: kv[0])
- else:
- items = dct.items()
- for key, value in items:
- if isinstance(key, str):
- pass
- # JavaScript is weakly typed for these, so it makes sense to
- # also allow them. Many encoders seem to do something like this.
- elif isinstance(key, float):
- key = _floatstr(key)
- elif key is True:
- key = 'true'
- elif key is False:
- key = 'false'
- elif key is None:
- key = 'null'
- elif isinstance(key, int):
- key = str(key)
- elif _skipkeys:
- continue
- else:
- raise TypeError("key " + repr(key) + " is not a string")
- if first:
- first = False
- else:
- yield item_separator
- yield _encoder(key)
- yield _key_separator
- if isinstance(value, str):
- yield _encoder(value)
- elif value is None:
- yield 'null'
- elif value is True:
- yield 'true'
- elif value is False:
- yield 'false'
- elif isinstance(value, int):
- yield str(value)
- elif isinstance(value, float):
- yield _floatstr(value)
- else:
- if isinstance(value, (list, tuple)):
- chunks = _iterencode_list(value, _current_indent_level)
- elif isinstance(value, dict):
- chunks = _iterencode_dict(value, _current_indent_level)
- else:
- chunks = _iterencode(value, _current_indent_level)
- for chunk in chunks:
- yield chunk
- if newline_indent is not None:
- _current_indent_level -= 1
- yield '\n' + _indent * _current_indent_level
- yield '}'
- if markers is not None:
- del markers[markerid]
-
- def _iterencode(o, _current_indent_level):
- if isinstance(o, str):
- yield _encoder(o)
- elif o is None:
- yield 'null'
- elif o is True:
- yield 'true'
- elif o is False:
- yield 'false'
- elif isinstance(o, int):
- yield str(o)
- elif isinstance(o, float):
- yield _floatstr(o)
- elif isinstance(o, (list, tuple)):
- for chunk in _iterencode_list(o, _current_indent_level):
- yield chunk
- elif isinstance(o, dict):
- for chunk in _iterencode_dict(o, _current_indent_level):
- yield chunk
- else:
- if markers is not None:
- markerid = id(o)
- if markerid in markers:
- raise ValueError("Circular reference detected")
- markers[markerid] = o
- o = _default(o)
- for chunk in _iterencode(o, _current_indent_level):
- yield chunk
- if markers is not None:
- del markers[markerid]
- return _iterencode
-
-
-# override the encoder
-json.encoder._make_iterencode = _make_iterencode
-
-
diff --git a/utils/exporters/blender/addons/io_three/exporter/api/__init__.py b/utils/exporters/blender/addons/io_three/exporter/api/__init__.py
deleted file mode 100644
index 36f940343cb7cdd9831735f49929ad2d6f1b9ee6..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/exporter/api/__init__.py
+++ /dev/null
@@ -1,77 +0,0 @@
-import os
-import bpy
-from . import object as object_, mesh, material, camera, light
-from .. import logger
-
-
-def active_object():
- """
-
- :return: The actively selected object
-
- """
- return bpy.context.scene.objects.active
-
-
-def batch_mode():
- """
-
- :return: Whether or not the session is interactive
- :rtype: bool
-
- """
- return bpy.context.area is None
-
-
-def data(node):
- """
-
- :param node: name of an object node
- :returns: the data block of the node
-
- """
- try:
- return bpy.data.objects[node].data
- except KeyError:
- pass
-
-
-def init():
- """Initializing the api module. Required first step before
- initializing the actual export process.
- """
- logger.debug("Initializing API")
- object_.clear_mesh_map()
-
-
-def selected_objects(valid_types=None):
- """Selected objects.
-
- :param valid_types: Filter for valid types (Default value = None)
-
- """
- logger.debug("api.selected_objects(%s)", valid_types)
- for node in bpy.context.selected_objects:
- if valid_types is None:
- yield node.name
- elif valid_types is not None and node.type in valid_types:
- yield node.name
-
-
-def set_active_object(obj):
- """Set the object as active in the scene
-
- :param obj:
-
- """
- logger.debug("api.set_active_object(%s)", obj)
- bpy.context.scene.objects.active = obj
-
-
-def scene_name():
- """
-
- :return: name of the current scene
-
- """
- return os.path.basename(bpy.data.filepath)
diff --git a/utils/exporters/blender/addons/io_three/exporter/api/animation.py b/utils/exporters/blender/addons/io_three/exporter/api/animation.py
deleted file mode 100644
index 7dd906767dfe9cfcbbdeb3573bc6d62287cd593c..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/exporter/api/animation.py
+++ /dev/null
@@ -1,683 +0,0 @@
-"""
-Module for handling the parsing of skeletal animation data.
-updated on 2/07/2016: bones scaling support (@uthor verteAzur verteAzur@multivers3d.fr)
-"""
-
-import math
-import mathutils
-from bpy import data, context, ops
-from .. import constants, logger
-
-def pose_animation(armature, options):
- """Query armature animation using pose bones
-
- :param armature:
- :param options:
- :returns: list dictionaries containing animationdata
- :rtype: [{}, {}, ...]
-
- """
- logger.debug("animation.pose_animation(%s)", armature)
- func = _parse_pose_action
- return _parse_action(func, armature, options)
-
-
-def rest_animation(armature, options):
- """Query armature animation (REST position)
-
- :param armature:
- :param options:
- :returns: list dictionaries containing animationdata
- :rtype: [{}, {}, ...]
-
- """
- logger.debug("animation.rest_animation(%s)", armature)
- func = _parse_rest_action
- return _parse_action(func, armature, options)
-
-
-def _parse_action(func, armature, options):
- """
-
- :param func:
- :param armature:
- :param options:
-
- """
- animations = []
- logger.info("Parsing %d actions", len(data.actions))
- for action in data.actions:
- logger.info("Parsing action %s", action.name)
- animation = func(action, armature, options)
- animations.append(animation)
- return animations
-
-
-def _parse_rest_action(action, armature, options):
- """
-
- :param action:
- :param armature:
- :param options:
-
- """
- end_frame = action.frame_range[1]
- start_frame = action.frame_range[0]
- frame_length = end_frame - start_frame
- rot = armature.matrix_world.decompose()[1]
- rotation_matrix = rot.to_matrix()
- hierarchy = []
- parent_index = -1
- frame_step = options.get(constants.FRAME_STEP, 1)
- fps = context.scene.render.fps
-
- start = int(start_frame)
- end = int(end_frame / frame_step) + 1
-
- for bone in armature.data.bones:
- # I believe this was meant to skip control bones, may
- # not be useful. needs more testing
- if bone.use_deform is False:
- logger.info("Skipping animation data for bone %s", bone.name)
- continue
-
- logger.info("Parsing animation data for bone %s", bone.name)
-
- keys = []
- for frame in range(start, end):
- computed_frame = frame * frame_step
- pos, pchange = _position(bone, computed_frame,
- action, armature.matrix_world)
- rot, rchange = _rotation(bone, computed_frame,
- action, rotation_matrix)
- rot = _normalize_quaternion(rot)
-
- sca, schange = _scale(bone, computed_frame,
- action, armature.matrix_world)
-
- pos_x, pos_y, pos_z = pos.x, pos.z, -pos.y
- rot_x, rot_y, rot_z, rot_w = rot.x, rot.z, -rot.y, rot.w
- sca_x, sca_y, sca_z = sca.x, sca.z, sca.y
-
- if frame == start_frame:
-
- time = (frame * frame_step - start_frame) / fps
-
- keyframe = {
- constants.TIME: time,
- constants.POS: [pos_x, pos_y, pos_z],
- constants.ROT: [rot_x, rot_y, rot_z, rot_w],
- constants.SCL: [sca_x, sca_y, sca_z]
- }
- keys.append(keyframe)
-
- # END-FRAME: needs pos, rot and scl attributes
- # with animation length (required frame)
-
- elif frame == end_frame / frame_step:
-
- time = frame_length / fps
- keyframe = {
- constants.TIME: time,
- constants.POS: [pos_x, pos_y, pos_z],
- constants.ROT: [rot_x, rot_y, rot_z, rot_w],
- constants.SCL: [sca_x, sca_y, sca_z]
- }
- keys.append(keyframe)
-
- # MIDDLE-FRAME: needs only one of the attributes,
- # can be an empty frame (optional frame)
-
- elif pchange is True or rchange is True or schange is True:
-
- time = (frame * frame_step - start_frame) / fps
-
- if pchange is True and rchange is True:
- keyframe = {
- constants.TIME: time,
- constants.POS: [pos_x, pos_y, pos_z],
- constants.ROT: [rot_x, rot_y, rot_z, rot_w],
- constants.SCL: [sca_x, sca_y, sca_z]
- }
- elif pchange is True:
- keyframe = {
- constants.TIME: time,
- constants.POS: [pos_x, pos_y, pos_z]
- }
- elif rchange is True:
- keyframe = {
- constants.TIME: time,
- constants.ROT: [rot_x, rot_y, rot_z, rot_w]
- }
- elif schange is True:
- keyframe = {
- constants.TIME: time,
- constants.SCL: [sca_x, sca_y, sca_z]
- }
-
- keys.append(keyframe)
-
- hierarchy.append({
- constants.KEYS: keys,
- constants.PARENT: parent_index
- })
- parent_index += 1
-
- animation = {
- constants.HIERARCHY: hierarchy,
- constants.LENGTH: frame_length / fps,
- constants.FPS: fps,
- constants.NAME: action.name
- }
-
- return animation
-
-
-def _parse_pose_action(action, armature, options):
- """
-
- :param action:
- :param armature:
- :param options:
-
- """
- try:
- current_context = context.area.type
- except AttributeError:
- for window in context.window_manager.windows:
- screen = window.screen
- for area in screen.areas:
- if area.type != 'VIEW_3D':
- continue
-
- override = {
- 'window': window,
- 'screen': screen,
- 'area': area
- }
- ops.screen.screen_full_area(override)
- break
- current_context = context.area.type
-
- context.scene.objects.active = armature
- context.area.type = 'DOPESHEET_EDITOR'
- context.space_data.mode = 'ACTION'
- context.area.spaces.active.action = action
-
- armature_matrix = armature.matrix_world
- fps = context.scene.render.fps
-
- end_frame = action.frame_range[1]
- start_frame = action.frame_range[0]
- frame_length = end_frame - start_frame
-
- frame_step = options.get(constants.FRAME_STEP, 1)
- used_frames = int(frame_length / frame_step) + 1
-
- keys = []
- channels_location = []
- channels_rotation = []
- channels_scale = []
-
- for pose_bone in armature.pose.bones:
- logger.info("Processing channels for %s",
- pose_bone.bone.name)
- keys.append([])
- channels_location.append(
- _find_channels(action,
- pose_bone.bone,
- 'location'))
- channels_rotation.append(
- _find_channels(action,
- pose_bone.bone,
- 'rotation_quaternion'))
- channels_rotation.append(
- _find_channels(action,
- pose_bone.bone,
- 'rotation_euler'))
- channels_scale.append(
- _find_channels(action,
- pose_bone.bone,
- 'scale'))
-
- frame_step = options[constants.FRAME_STEP]
- frame_index_as_time = options[constants.FRAME_INDEX_AS_TIME]
- for frame_index in range(0, used_frames):
- if frame_index == used_frames - 1:
- frame = end_frame
- else:
- frame = start_frame + frame_index * frame_step
-
- logger.info("Processing frame %d", frame)
-
- time = frame - start_frame
- if frame_index_as_time is False:
- time = time / fps
-
- context.scene.frame_set(frame)
-
- bone_index = 0
-
- def has_keyframe_at(channels, frame):
- """
-
- :param channels:
- :param frame:
-
- """
- def find_keyframe_at(channel, frame):
- """
-
- :param channel:
- :param frame:
-
- """
- for keyframe in channel.keyframe_points:
- if keyframe.co[0] == frame:
- return keyframe
- return None
-
- for channel in channels:
- if not find_keyframe_at(channel, frame) is None:
- return True
- return False
-
- for pose_bone in armature.pose.bones:
-
- logger.info("Processing bone %s", pose_bone.bone.name)
- if pose_bone.parent is None:
- bone_matrix = armature_matrix * pose_bone.matrix
- else:
- parent_matrix = armature_matrix * pose_bone.parent.matrix
- bone_matrix = armature_matrix * pose_bone.matrix
- bone_matrix = parent_matrix.inverted() * bone_matrix
-
- pos, rot, scl = bone_matrix.decompose()
- rot = _normalize_quaternion(rot)
-
- pchange = True or has_keyframe_at(
- channels_location[bone_index], frame)
- rchange = True or has_keyframe_at(
- channels_rotation[bone_index], frame)
- schange = True or has_keyframe_at(
- channels_scale[bone_index], frame)
-
- pos = (pos.x, pos.z, -pos.y)
- rot = (rot.x, rot.z, -rot.y, rot.w)
- scl = (scl.x, scl.z, scl.y)
-
- keyframe = {constants.TIME: time}
- if frame == start_frame or frame == end_frame:
- keyframe.update({
- constants.POS: pos,
- constants.ROT: rot,
- constants.SCL: scl
- })
- elif any([pchange, rchange, schange]):
- if pchange is True:
- keyframe[constants.POS] = pos
- if rchange is True:
- keyframe[constants.ROT] = rot
- if schange is True:
- keyframe[constants.SCL] = scl
-
- if len(keyframe.keys()) > 1:
- logger.info("Recording keyframe data for %s %s",
- pose_bone.bone.name, str(keyframe))
- keys[bone_index].append(keyframe)
- else:
- logger.info("No anim data to record for %s",
- pose_bone.bone.name)
-
- bone_index += 1
-
- hierarchy = []
- bone_index = 0
- for pose_bone in armature.pose.bones:
- hierarchy.append({
- constants.PARENT: bone_index - 1,
- constants.KEYS: keys[bone_index]
- })
- bone_index += 1
-
- if frame_index_as_time is False:
- frame_length = frame_length / fps
-
- context.scene.frame_set(start_frame)
- context.area.type = current_context
-
- animation = {
- constants.HIERARCHY: hierarchy,
- constants.LENGTH: frame_length,
- constants.FPS: fps,
- constants.NAME: action.name
- }
-
- return animation
-
-
-def _find_channels(action, bone, channel_type):
- """
-
- :param action:
- :param bone:
- :param channel_type:
-
- """
- result = []
-
- if len(action.groups):
-
- group_index = -1
- for index, group in enumerate(action.groups):
- if group.name == bone.name:
- group_index = index
- # @TODO: break?
-
- if group_index > -1:
- for channel in action.groups[group_index].channels:
- if channel_type in channel.data_path:
- result.append(channel)
-
- else:
- bone_label = '"%s"' % bone.name
- for channel in action.fcurves:
- data_path = [bone_label in channel.data_path,
- channel_type in channel.data_path]
- if all(data_path):
- result.append(channel)
-
- return result
-
-
-def _position(bone, frame, action, armature_matrix):
- """
-
- :param bone:
- :param frame:
- :param action:
- :param armature_matrix:
-
- """
-
- position = mathutils.Vector((0, 0, 0))
- change = False
-
- ngroups = len(action.groups)
-
- if ngroups > 0:
-
- index = 0
-
- for i in range(ngroups):
- if action.groups[i].name == bone.name:
- index = i
-
- for channel in action.groups[index].channels:
- if "location" in channel.data_path:
- has_changed = _handle_position_channel(
- channel, frame, position)
- change = change or has_changed
-
- else:
-
- bone_label = '"%s"' % bone.name
-
- for channel in action.fcurves:
- data_path = channel.data_path
- if bone_label in data_path and "location" in data_path:
- has_changed = _handle_position_channel(
- channel, frame, position)
- change = change or has_changed
-
- position = position * bone.matrix_local.inverted()
-
- if bone.parent is None:
-
- position.x += bone.head.x
- position.y += bone.head.y
- position.z += bone.head.z
-
- else:
-
- parent = bone.parent
-
- parent_matrix = parent.matrix_local.inverted()
- diff = parent.tail_local - parent.head_local
-
- position.x += (bone.head * parent_matrix).x + diff.x
- position.y += (bone.head * parent_matrix).y + diff.y
- position.z += (bone.head * parent_matrix).z + diff.z
-
- return armature_matrix*position, change
-
-
-def _rotation(bone, frame, action, armature_matrix):
- """
-
- :param bone:
- :param frame:
- :param action:
- :param armature_matrix:
-
- """
-
- # TODO: calculate rotation also from rotation_euler channels
-
- rotation = mathutils.Vector((0, 0, 0, 1))
-
- change = False
-
- ngroups = len(action.groups)
-
- # animation grouped by bones
-
- if ngroups > 0:
-
- index = -1
-
- for i in range(ngroups):
- if action.groups[i].name == bone.name:
- index = i
-
- if index > -1:
- for channel in action.groups[index].channels:
- if "quaternion" in channel.data_path:
- has_changed = _handle_rotation_channel(
- channel, frame, rotation)
- change = change or has_changed
-
- # animation in raw fcurves
-
- else:
-
- bone_label = '"%s"' % bone.name
-
- for channel in action.fcurves:
- data_path = channel.data_path
- if bone_label in data_path and "quaternion" in data_path:
- has_changed = _handle_rotation_channel(
- channel, frame, rotation)
- change = change or has_changed
-
- rot3 = rotation.to_3d()
- rotation.xyz = rot3 * bone.matrix_local.inverted()
- rotation.xyz = armature_matrix * rotation.xyz
-
- return rotation, change
-
-def _scale(bone, frame, action, armature_matrix):
- """
-
- :param bone:
- :param frame:
- :param action:
- :param armature_matrix:
-
- """
- scale = mathutils.Vector((1.0, 1.0, 1.0))
-
- change = False
-
- ngroups = len(action.groups)
-
- # animation grouped by bones
-
- if ngroups > 0:
-
- index = -1
-
- for i in range(ngroups):
- if action.groups[i].name == bone.name:
-
- print(action.groups[i].name)
-
- index = i
-
- if index > -1:
- for channel in action.groups[index].channels:
-
- if "scale" in channel.data_path:
- has_changed = _handle_scale_channel(
- channel, frame, scale)
- change = change or has_changed
-
- # animation in raw fcurves
-
- else:
-
- bone_label = '"%s"' % bone.name
-
- for channel in action.fcurves:
- data_path = channel.data_path
- if bone_label in data_path and "scale" in data_path:
- has_changed = _handle_scale_channel(
- channel, frame, scale)
- change = change or has_changed
-
-
- #scale.xyz = armature_matrix * scale.xyz
-
- return scale, change
-
-
-def _handle_rotation_channel(channel, frame, rotation):
- """
-
- :param channel:
- :param frame:
- :param rotation:
-
- """
-
- change = False
-
- if channel.array_index in [0, 1, 2, 3]:
-
- for keyframe in channel.keyframe_points:
- if keyframe.co[0] == frame:
- change = True
-
- value = channel.evaluate(frame)
-
- if channel.array_index == 1:
- rotation.x = value
-
- elif channel.array_index == 2:
- rotation.y = value
-
- elif channel.array_index == 3:
- rotation.z = value
-
- elif channel.array_index == 0:
- rotation.w = value
-
- return change
-
-
-def _handle_position_channel(channel, frame, position):
- """
-
- :param channel:
- :param frame:
- :param position:
-
- """
-
- change = False
-
- if channel.array_index in [0, 1, 2]:
- for keyframe in channel.keyframe_points:
- if keyframe.co[0] == frame:
- change = True
-
- value = channel.evaluate(frame)
-
- if channel.array_index == 0:
- position.x = value
-
- if channel.array_index == 1:
- position.y = value
-
- if channel.array_index == 2:
- position.z = value
-
- return change
-
-def _handle_scale_channel(channel, frame, scale):
- """
-
- :param channel:
- :param frame:
- :param position:
-
- """
- change = False
-
- if channel.array_index in [0, 1, 2]:
- for keyframe in channel.keyframe_points:
- if keyframe.co[0] == frame:
- change = True
-
- value = channel.evaluate(frame)
-
- if channel.array_index == 0:
- scale.x = value
-
- if channel.array_index == 1:
- scale.y = value
-
- if channel.array_index == 2:
- scale.z = value
-
- return change
-
-
-def _quaternion_length(quat):
- """Calculate the length of a quaternion
-
- :param quat: Blender quaternion object
- :rtype: float
-
- """
- return math.sqrt(quat.x * quat.x + quat.y * quat.y +
- quat.z * quat.z + quat.w * quat.w)
-
-
-def _normalize_quaternion(quat):
- """Normalize a quaternion
-
- :param quat: Blender quaternion object
- :returns: generic quaternion enum object with normalized values
- :rtype: object
-
- """
- enum = type('Enum', (), {'x': 0, 'y': 0, 'z': 0, 'w': 1})
- length = _quaternion_length(quat)
- if length is not 0:
- length = 1 / length
- enum.x = quat.x * length
- enum.y = quat.y * length
- enum.z = quat.z * length
- enum.w = quat.w * length
- return enum
diff --git a/utils/exporters/blender/addons/io_three/exporter/api/camera.py b/utils/exporters/blender/addons/io_three/exporter/api/camera.py
deleted file mode 100644
index 06b12135a1e6270daafd03550081ed8fc3a1d5ef..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/exporter/api/camera.py
+++ /dev/null
@@ -1,130 +0,0 @@
-import math
-from bpy import data, types, context
-from .. import logger
-
-
-def _camera(func):
- """
-
- :param func:
-
- """
-
- def inner(name, *args, **kwargs):
- """
-
- :param name:
- :param *args:
- :param **kwargs:
-
- """
-
- if isinstance(name, types.Camera):
- camera = name
- else:
- camera = data.cameras[name]
-
- return func(camera, *args, **kwargs)
-
- return inner
-
-
-@_camera
-def aspect(camera):
- """
-
- :param camera:
- :rtype: float
-
- """
- logger.debug("camera.aspect(%s)", camera)
- render = context.scene.render
- return render.resolution_x/render.resolution_y
-
-
-@_camera
-def bottom(camera):
- """
-
- :param camera:
- :rtype: float
-
- """
- logger.debug("camera.bottom(%s)", camera)
- return -(camera.angle_y * camera.ortho_scale)
-
-
-@_camera
-def far(camera):
- """
-
- :param camera:
- :rtype: float
-
- """
- logger.debug("camera.far(%s)", camera)
- return camera.clip_end
-
-
-@_camera
-def fov(camera):
- """
-
- :param camera:
- :rtype: float
-
- """
- logger.debug("camera.fov(%s)", camera)
- fov_in_radians = camera.angle
- aspect_ratio = aspect(camera)
- if aspect_ratio > 1:
- fov_in_radians = 2 * math.atan(math.tan(fov_in_radians / 2) / aspect_ratio)
- return math.degrees(fov_in_radians)
-
-
-@_camera
-def left(camera):
- """
-
- :param camera:
- :rtype: float
-
- """
- logger.debug("camera.left(%s)", camera)
- return -(camera.angle_x * camera.ortho_scale)
-
-
-@_camera
-def near(camera):
- """
-
- :param camera:
- :rtype: float
-
- """
- logger.debug("camera.near(%s)", camera)
- return camera.clip_start
-
-
-@_camera
-def right(camera):
- """
-
- :param camera:
- :rtype: float
-
- """
- logger.debug("camera.right(%s)", camera)
- return camera.angle_x * camera.ortho_scale
-
-
-@_camera
-def top(camera):
- """
-
- :param camera:
- :rtype: float
-
- """
- logger.debug("camera.top(%s)", camera)
- return camera.angle_y * camera.ortho_scale
diff --git a/utils/exporters/blender/addons/io_three/exporter/api/constants.py b/utils/exporters/blender/addons/io_three/exporter/api/constants.py
deleted file mode 100644
index 76a4a46b2044c9062959888359051986b559ea80..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/exporter/api/constants.py
+++ /dev/null
@@ -1,29 +0,0 @@
-MESH = 'MESH'
-LAMP = 'LAMP'
-EMPTY = 'EMPTY'
-ARMATURE = 'ARMATURE'
-
-SPOT = 'SPOT'
-POINT = 'POINT'
-SUN = 'SUN'
-HEMI = 'HEMI'
-AREA = 'AREA'
-
-NO_SHADOW = 'NOSHADOW'
-
-CAMERA = 'CAMERA'
-PERSP = 'PERSP'
-ORTHO = 'ORTHO'
-
-RENDER = 'RENDER'
-
-ZYX = 'ZYX'
-
-MULTIPLY = 'MULTIPLY'
-
-WIRE = 'WIRE'
-IMAGE = 'IMAGE'
-
-MAG_FILTER = 'LinearFilter'
-MIN_FILTER = 'LinearMipMapLinearFilter'
-MAPPING = 'UVMapping'
diff --git a/utils/exporters/blender/addons/io_three/exporter/api/image.py b/utils/exporters/blender/addons/io_three/exporter/api/image.py
deleted file mode 100644
index c0581173fe7394a6d86c7d24bb7142950cd07e09..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/exporter/api/image.py
+++ /dev/null
@@ -1,52 +0,0 @@
-import os
-from bpy import data, types
-from .. import logger
-
-
-def _image(func):
- """
-
- :param func:
-
- """
-
- def inner(name, *args, **kwargs):
- """
-
- :param name:
- :param *args:
- :param **kwargs:
-
- """
-
- if isinstance(name, types.Image):
- mesh = name
- else:
- mesh = data.images[name]
-
- return func(mesh, *args, **kwargs)
-
- return inner
-
-
-def file_name(image):
- """
-
- :param image:
- :rtype: str
-
- """
- logger.debug("image.file_name(%s)", image)
- return os.path.basename(file_path(image))
-
-
-@_image
-def file_path(image):
- """
-
- :param image:
- :rtype: str
-
- """
- logger.debug("image.file_path(%s)", image)
- return os.path.normpath(image.filepath_from_user())
diff --git a/utils/exporters/blender/addons/io_three/exporter/api/light.py b/utils/exporters/blender/addons/io_three/exporter/api/light.py
deleted file mode 100644
index 25a8cc48da1aecd12425c40034030ba715ddd4b1..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/exporter/api/light.py
+++ /dev/null
@@ -1,97 +0,0 @@
-from bpy import data, types
-from .. import utilities, logger
-
-
-def _lamp(func):
- """
-
- :param func:
-
- """
-
- def inner(name, *args, **kwargs):
- """
-
- :param name:
- :param *args:
- :param **kwargs:
-
- """
-
- if isinstance(name, types.Lamp):
- lamp = name
- else:
- lamp = data.lamps[name]
-
- return func(lamp, *args, **kwargs)
-
- return inner
-
-
-@_lamp
-def angle(lamp):
- """
-
- :param lamp:
- :rtype: float
-
- """
- logger.debug("light.angle(%s)", lamp)
- return lamp.spot_size
-
-
-@_lamp
-def color(lamp):
- """
-
- :param lamp:
- :rtype: int
-
- """
- logger.debug("light.color(%s)", lamp)
- colour = (lamp.color.r, lamp.color.g, lamp.color.b)
- return utilities.rgb2int(colour)
-
-
-@_lamp
-def distance(lamp):
- """
-
- :param lamp:
- :rtype: float
-
- """
- logger.debug("light.distance(%s)", lamp)
- return lamp.distance
-
-
-@_lamp
-def intensity(lamp):
- """
-
- :param lamp:
- :rtype: float
-
- """
- logger.debug("light.intensity(%s)", lamp)
- return round(lamp.energy, 2)
-
-# mapping enum values to decay exponent
-__FALLOFF_TO_EXP = {
- 'CONSTANT': 0,
- 'INVERSE_LINEAR': 1,
- 'INVERSE_SQUARE': 2,
- 'CUSTOM_CURVE': 0,
- 'LINEAR_QUADRATIC_WEIGHTED': 2
-}
-
-@_lamp
-def falloff(lamp):
- """
-
- :param lamp:
- :rtype: float
-
- """
- logger.debug("light.falloff(%s)", lamp)
- return __FALLOFF_TO_EXP[lamp.falloff_type]
diff --git a/utils/exporters/blender/addons/io_three/exporter/api/material.py b/utils/exporters/blender/addons/io_three/exporter/api/material.py
deleted file mode 100644
index 609b14bb733f9ef3c687387e3daf8e56ee6c2d25..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/exporter/api/material.py
+++ /dev/null
@@ -1,405 +0,0 @@
-from bpy import data, types
-from .. import constants, logger
-from .constants import MULTIPLY, WIRE, IMAGE
-
-
-def _material(func):
- """
-
- :param func:
-
- """
-
- def inner(name, *args, **kwargs):
- """
-
- :param name:
- :param *args:
- :param **kwargs:
-
- """
-
- material = None
- if isinstance(name, types.Material):
- material = name
- elif name:
- material = data.materials[name]
-
- return func(material, *args, **kwargs) if material else None
-
- return inner
-
-
-@_material
-def blending(material):
- """
-
- :param material:
- :return: THREE_blending_type value
-
- """
- logger.debug("material.blending(%s)", material)
- try:
- blend = material.THREE_blending_type
- except AttributeError:
- logger.debug("No THREE_blending_type attribute found")
- blend = constants.NORMAL_BLENDING
-
- blend = getattr( constants.BLENDING_CONSTANTS , blend) #manthrax: Translate the blending type name, to the three.js constant value.
- return blend
-
-
-@_material
-def bump_map(material):
- """
-
- :param material:
- :return: texture node for bump
-
- """
- logger.debug("material.bump_map(%s)", material)
- for texture in _valid_textures(material):
- if texture.use_map_normal and not \
- texture.texture.use_normal_map:
- return texture.texture
-
-
-@_material
-def bump_scale(material):
- """
-
- :param material:
- :rtype: float
-
- """
- logger.debug("material.bump_scale(%s)", material)
- for texture in _valid_textures(material):
- if texture.use_map_normal:
- return texture.normal_factor
-
-
-@_material
-def depth_test(material):
- """
-
- :param material:
- :return: THREE_depth_test value
- :rtype: bool
-
- """
- logger.debug("material.depth_test(%s)", material)
- try:
- test = material.THREE_depth_test
- except AttributeError:
- logger.debug("No THREE_depth_test attribute found")
- test = True
- return test
-
-
-@_material
-def depth_write(material):
- """
-
- :param material:
- :return: THREE_depth_write value
- :rtype: bool
-
- """
- logger.debug("material.depth_write(%s)", material)
- try:
- write = material.THREE_depth_write
- except AttributeError:
- logger.debug("No THREE_depth_write attribute found")
- write = True
- return write
-
-
-@_material
-def double_sided(material):
- """
-
- :param material:
- :return: THREE_double_sided value
- :rtype: bool
-
- """
- logger.debug("material.double_sided(%s)", material)
- try:
- write = material.THREE_double_sided
- except AttributeError:
- logger.debug("No THREE_double_sided attribute found")
- write = False
- return write
-
-
-@_material
-def diffuse_color(material):
- """
-
- :param material:
- :return: rgb value
- :rtype: tuple
-
- """
- logger.debug("material.diffuse_color(%s)", material)
- return (material.diffuse_intensity * material.diffuse_color[0],
- material.diffuse_intensity * material.diffuse_color[1],
- material.diffuse_intensity * material.diffuse_color[2])
-
-
-@_material
-def diffuse_map(material):
- """
-
- :param material:
- :return: texture node for map
-
- """
- logger.debug("material.diffuse_map(%s)", material)
- for texture in _valid_textures(material):
- if texture.use_map_color_diffuse and not \
- texture.blend_type == MULTIPLY:
- return texture.texture
-
-
-@_material
-def emissive_color(material):
- """
-
- :param material:
- :return: rgb value
- :rtype: tuple
-
- """
- logger.debug("material.emissive_color(%s)", material)
- diffuse = diffuse_color(material)
- return (material.emit * diffuse[0],
- material.emit * diffuse[1],
- material.emit * diffuse[2])
-
-
-@_material
-def light_map(material):
- """
-
- :param material:
- :return: texture node for light maps
-
- """
- logger.debug("material.light_map(%s)", material)
- for texture in _valid_textures(material, strict_use=False):
- if texture.use_map_color_diffuse and \
- texture.blend_type == MULTIPLY:
- return texture.texture
-
-
-@_material
-def normal_scale(material):
- """
-
- :param material:
- :rtype: float
-
- """
- logger.debug("material.normal_scale(%s)", material)
- for texture in _valid_textures(material):
- if texture.use_map_normal:
- return (texture.normal_factor, texture.normal_factor)
-
-
-@_material
-def normal_map(material):
- """
-
- :param material:
- :return: texture node for normals
-
- """
- logger.debug("material.normal_map(%s)", material)
- for texture in _valid_textures(material):
- if texture.use_map_normal and \
- texture.texture.use_normal_map:
- return texture.texture
-
-
-@_material
-def opacity(material):
- """
-
- :param material:
- :rtype: float
-
- """
- logger.debug("material.opacity(%s)", material)
- return round(material.alpha, 2)
-
-
-@_material
-def shading(material):
- """
-
- :param material:
- :return: shading type (phong or lambert)
-
- """
- logger.debug("material.shading(%s)", material)
- dispatch = {
- True: constants.PHONG,
- False: constants.LAMBERT
- }
-
- if material.use_shadeless:
- return constants.BASIC
-
- return dispatch[material.specular_intensity > 0.0]
-
-
-@_material
-def specular_coef(material):
- """
-
- :param material:
- :rtype: float
-
- """
- logger.debug("material.specular_coef(%s)", material)
- return material.specular_hardness
-
-
-@_material
-def specular_color(material):
- """
-
- :param material:
- :return: rgb value
- :rtype: tuple
-
- """
- logger.debug("material.specular_color(%s)", material)
- return (material.specular_intensity * material.specular_color[0],
- material.specular_intensity * material.specular_color[1],
- material.specular_intensity * material.specular_color[2])
-
-
-@_material
-def specular_map(material):
- """
-
- :param material:
- :return: texture node for specular
-
- """
- logger.debug("material.specular_map(%s)", material)
- for texture in _valid_textures(material):
- if texture.use_map_specular:
- return texture.texture
-
-
-@_material
-def transparent(material):
- """
-
- :param material:
- :rtype: bool
-
- """
- logger.debug("material.transparent(%s)", material)
- return material.use_transparency
-
-
-@_material
-def type(material):
- """
-
- :param material:
- :return: THREE compatible shader type
-
- """
- logger.debug("material.type(%s)", material)
- if material.diffuse_shader != 'LAMBERT':
- material_type = constants.BASIC
- elif material.specular_intensity > 0:
- material_type = constants.PHONG
- else:
- material_type = constants.LAMBERT
-
- return material_type
-
-
-@_material
-def use_vertex_colors(material):
- """
-
- :param material:
- :rtype: bool
-
- """
- logger.debug("material.use_vertex_colors(%s)", material)
- return material.use_vertex_color_paint
-
-
-def used_materials():
- """
-
- :return: list of materials that are in use
- :rtype: generator
-
- """
- logger.debug("material.used_materials()")
- for material in data.materials:
- if material.users > 0:
- yield material.name
-
-
-@_material
-def visible(material):
- """
-
- :param material:
- :return: THREE_visible value
- :rtype: bool
-
- """
- logger.debug("material.visible(%s)", material)
- try:
- vis = material.THREE_visible
- except AttributeError:
- logger.debug("No THREE_visible attribute found")
- vis = True
-
- return vis
-
-
-@_material
-def wireframe(material):
- """
-
- :param material:
- :rtype: bool
-
- """
- logger.debug("material.wireframe(%s)", material)
- return material.type == WIRE
-
-
-def _valid_textures(material, strict_use=True):
- """
-
- :param material:
- :rtype: generator
-
- """
- for texture in material.texture_slots:
- if not texture:
- continue
- if strict_use:
- in_use = texture.use
- else:
- in_use = True
- if not in_use:
- continue
- if not texture.texture or texture.texture.type != IMAGE:
- logger.warning("Unable to export non-image texture %s", texture)
- continue
- logger.debug("Valid texture found %s", texture)
- yield texture
diff --git a/utils/exporters/blender/addons/io_three/exporter/api/mesh.py b/utils/exporters/blender/addons/io_three/exporter/api/mesh.py
deleted file mode 100644
index 3402a233fe048c2a3d2fbe8095fbd6a1581dcc21..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/exporter/api/mesh.py
+++ /dev/null
@@ -1,1390 +0,0 @@
-"""
-Blender API for querying mesh data. Animation data is also
-handled here since Three.js associates the animation (skeletal,
-morph targets) with the geometry nodes.
-"""
-
-import operator
-import re
-from bpy import data, types, context
-from . import material, texture, animation
-from . import object as object_
-from .. import constants, utilities, logger, exceptions
-
-
-# flips vectors
-
-XZ_Y = constants.XZ_Y
-X_ZY = constants.X_ZY
-XYZ = constants.XYZ
-_XY_Z = constants._XY_Z
-
-
-def flip_axes (a, dir=XYZ):
- """
-
- :function to swap vectors:
-
- """
-
- if dir == XZ_Y:
- a = (a[0], a[2], -a[1])
- elif dir == X_ZY:
- a = (a[0], -a[2], a[1])
- elif dir == _XY_Z:
- a = (-a[0], -a[1], a[2])
-
- return (a[0], a[1], a[2])
-
-
-def _mesh(func):
- """
-
- :param func:
-
- """
-
- def inner(name, *args, **kwargs):
- """
-
- :param name:
- :param *args:
- :param **kwargs:
-
- """
-
- if isinstance(name, types.Mesh):
- mesh = name
- else:
- mesh = data.meshes[name]
-
- return func(mesh, *args, **kwargs)
-
- return inner
-
-
-@_mesh
-def skeletal_animation(mesh, options):
- """
-
- :param mesh:
- :param options:
- :rtype: []
-
- """
- logger.debug("mesh.animation(%s, %s)", mesh, options)
- armature = _armature(mesh)
-
- if not armature:
- logger.warning("No armature found (%s)", mesh)
- return []
-
- anim_type = options.get(constants.ANIMATION)
-# pose_position = armature.data.pose_position
- dispatch = {
- constants.POSE: animation.pose_animation,
- constants.REST: animation.rest_animation
- }
-
- func = dispatch[anim_type]
-# armature.data.pose_position = anim_type.upper()
- animations = func(armature, options)
-# armature.data.pose_position = pose_position
-
- return animations
-
-@_mesh
-def bones(mesh, options):
- """
-
- :param mesh:
- :param options:
- :rtype: [], {}
-
- """
- logger.debug("mesh.bones(%s)", mesh)
- armature = _armature(mesh)
-
- if not armature:
- return [], {}
-
- anim_type = options.get(constants.ANIMATION)
-# pose_position = armature.data.pose_position
-
- if anim_type == constants.OFF:
- logger.info("Animation type not set, defaulting "
- "to using REST position for the armature.")
- func = _rest_bones
-# armature.data.pose_position = "REST"
- else:
- dispatch = {
- constants.REST: _rest_bones,
- constants.POSE: _pose_bones
- }
- logger.info("Using %s for the armature", anim_type)
- func = dispatch[anim_type]
-# armature.data.pose_position = anim_type.upper()
-
- bones_, bone_map = func(armature)
-# armature.data.pose_position = pose_position
-
- return (bones_, bone_map)
-
-
-@_mesh
-def buffer_color(mesh, options):
- """
-
- :param mesh:
- :rtype: []
-
- """
- colors_ = []
-
- try:
- vertex_colors_ = mesh.vertex_colors[0] # only supports one set
- except IndexError:
- return [] # no colors found
- for color_data in vertex_colors_.data:
- colors_.extend(tuple(color_data.color))
-
- return colors_
-
-
-@_mesh
-def buffer_normal(mesh, options):
- """
-
- :param mesh:
- :rtype: []
-
- """
- normals_ = []
-
- for face in mesh.tessfaces:
- vert_count = len(face.vertices)
- if vert_count is not 3:
- msg = "Non-triangulated face detected"
- raise exceptions.BufferGeometryError(msg)
-
- # using Object Loader with skinned mesh
- if options.get(constants.SCENE, True) and _armature(mesh):
-
- for vertex_index in face.vertices:
- normal = mesh.vertices[vertex_index].normal
- vector = flip_axes(normal, XZ_Y) if face.use_smooth else flip_axes(face.normal, XZ_Y)
- normals_.extend(vector)
-
- # using Object Loader with static mesh
- elif options.get(constants.SCENE, True) and not _armature(mesh):
-
- for vertex_index in face.vertices:
- normal = mesh.vertices[vertex_index].normal
- vector = flip_axes(normal, _XY_Z) if face.use_smooth else flip_axes(face.normal, _XY_Z)
- normals_.extend(vector)
-
- # using JSON Loader with skinned mesh
- elif not options.get(constants.SCENE, True) and _armature(mesh):
-
- for vertex_index in face.vertices:
- normal = mesh.vertices[vertex_index].normal
- vector = flip_axes(normal) if face.use_smooth else flip_axes(face.normal)
- normals_.extend(vector)
-
- # using JSON Loader with static mesh
- else:
-
- for vertex_index in face.vertices:
- normal = mesh.vertices[vertex_index].normal
- vector = flip_axes(normal) if face.use_smooth else flip_axes(face.normal)
- normals_.extend(vector)
-
- return normals_
-
-
-@_mesh
-def buffer_face_material(mesh, options):
- """
-
- :param mesh:
- :rtype: []
-
- """
- face_material = []
- logger.info("Retrieving face materials.")
-
- for face in mesh.tessfaces:
- #logger.info("face:%d,%d",face.index,face.material_index)
- face_material.append(face.material_index)
-
- return face_material
-
-
-@_mesh
-def buffer_position(mesh, options):
- """
-
- :param mesh:
- :rtype: []
-
- """
- position = []
-
- for face in mesh.tessfaces:
- vert_count = len(face.vertices)
- if vert_count is not 3:
- msg = "Non-triangulated face detected"
- raise exceptions.BufferGeometryError(msg)
-
- # using Object Loader with skinned mesh
- if options.get(constants.SCENE, True) and _armature(mesh):
-
- for vertex_index in face.vertices:
- vertex = mesh.vertices[vertex_index]
- vector = flip_axes(vertex.co, XZ_Y)
- position.extend(vector)
-
- # using Object Loader with static mesh
- elif options.get(constants.SCENE, True) and not _armature(mesh):
-
- for vertex_index in face.vertices:
- vertex = mesh.vertices[vertex_index]
- vector = flip_axes(vertex.co, _XY_Z)
- position.extend(vector)
-
- # using JSON Loader with skinned mesh
- elif not options.get(constants.SCENE, True) and _armature(mesh):
-
- for vertex_index in face.vertices:
- vertex = mesh.vertices[vertex_index]
- vector = flip_axes(vertex.co)
- position.extend(vector)
-
- # using JSON Loader with static mesh
- else:
-
- for vertex_index in face.vertices:
- vertex = mesh.vertices[vertex_index]
- vector = flip_axes(vertex.co)
- position.extend(vector)
-
- return position
-
-
-@_mesh
-def buffer_uv(mesh, layer=0):
- """
-
- :param mesh:
- :param layer: (Default value = 0)
- :rtype: []
-
- """
- uvs_ = []
- if len(mesh.uv_layers) <= layer:
- return uvs_
-
- for uv_data in mesh.uv_layers[layer].data:
- uv_tuple = (uv_data.uv[0], uv_data.uv[1])
- uvs_.extend(uv_tuple)
-
- return uvs_
-
-
-@_mesh
-def extra_vertex_groups(mesh, patterns_string):
- """
- Returns (name,index) tuples for the extra (non-skinning) vertex groups
- matching the given patterns.
- The patterns are comma-separated where the star character can be used
- as a wildcard character sequence.
-
- :param mesh:
- :param patterns_string:
- :rtype: []
-
- """
- logger.debug("mesh._extra_vertex_groups(%s)", mesh)
- pattern_re = None
- extra_vgroups = []
- if not patterns_string.strip():
- return extra_vgroups
- armature = _armature(mesh)
- obj = object_.objects_using_mesh(mesh)[0]
- for vgroup_index, vgroup in enumerate(obj.vertex_groups):
- # Skip bone weights:
- vgroup_name = vgroup.name
- if armature:
- is_bone_weight = False
- for bone in armature.pose.bones:
- if bone.name == vgroup_name:
- is_bone_weight = True
- break
- if is_bone_weight:
- continue
-
- if pattern_re is None:
- # Translate user-friendly patterns to a regular expression:
- # Join the whitespace-stripped, initially comma-separated
- # entries to alternatives. Escape all characters except
- # the star and replace that one with '.*?'.
- pattern_re = '^(?:' + '|'.join(
- map(lambda entry:
- '.*?'.join(map(re.escape, entry.strip().split('*'))),
- patterns_string.split(','))) + ')$'
-
- if not re.match(pattern_re, vgroup_name):
- continue
-
- extra_vgroups.append((vgroup_name, vgroup_index))
- return extra_vgroups
-
-
-@_mesh
-def vertex_group_data(mesh, index):
- """
- Return vertex group data for each vertex. Vertices not in the group
- get a zero value.
-
- :param mesh:
- :param index:
-
- """
- group_data = []
- for vertex in mesh.vertices:
- weight = None
- for group in vertex.groups:
- if group.group == index:
- weight = group.weight
- group_data.append(weight or 0.0)
- return group_data
-
-
-@_mesh
-def buffer_vertex_group_data(mesh, index):
- """
- Return vertex group data for each deindexed vertex. Vertices not in the
- group get a zero value.
-
- :param mesh:
- :param index:
-
- """
- group_data = []
- for face in mesh.tessfaces:
- for vertex_index in face.vertices:
- vertex = mesh.vertices[vertex_index]
- weight = None
- for group in vertex.groups:
- if group.group == index:
- weight = group.weight
- group_data.append(weight or 0.0)
- return group_data
-
-
-@_mesh
-def faces(mesh, options, material_list=None):
- """
-
- :param mesh:
- :param options:
- :param material_list: (Default value = None)
-
- """
- logger.debug("mesh.faces(%s, %s, materials=%s)",
- mesh, options, materials)
-
- material_list = material_list or []
- vertex_uv = len(mesh.uv_textures) > 0
- has_colors = len(mesh.vertex_colors) > 0
- logger.info("Has UVs = %s", vertex_uv)
- logger.info("Has vertex colours = %s", has_colors)
-
- opt_colours = options[constants.COLORS] and has_colors
- opt_uvs = options[constants.UVS] and vertex_uv
- opt_materials = options.get(constants.FACE_MATERIALS)
- opt_normals = options[constants.NORMALS]
- logger.debug("Vertex colours enabled = %s", opt_colours)
- logger.debug("UVS enabled = %s", opt_uvs)
- logger.debug("Materials enabled = %s", opt_materials)
- logger.debug("Normals enabled = %s", opt_normals)
-
- uv_indices = _uvs(mesh)[1] if opt_uvs else None
- vertex_normals = _normals(mesh, options) if opt_normals else None
- vertex_colours = vertex_colors(mesh) if opt_colours else None
-
- faces_data = []
-
- colour_indices = {}
- if vertex_colours:
- logger.debug("Indexing colours")
- for index, colour in enumerate(vertex_colours):
- colour_indices[str(colour)] = index
-
- normal_indices = {}
-
- if vertex_normals:
- logger.debug("Indexing normals")
-
- # using Object Loader with skinned mesh
- if options.get(constants.SCENE, True) and _armature(mesh):
-
- for index, normal in enumerate(vertex_normals):
- normal = flip_axes(normal, XYZ)
- normal_indices[str(normal)] = index
-
- # using Object Loader with static mesh
- elif options.get(constants.SCENE, True) and not _armature(mesh):
-
- for index, normal in enumerate(vertex_normals):
- normal = flip_axes(normal, XYZ)
- normal_indices[str(normal)] = index
-
- # using JSON Loader with skinned mesh
- elif not options.get(constants.SCENE, True) and _armature(mesh):
-
- for index, normal in enumerate(vertex_normals):
- normal = flip_axes(normal)
- normal_indices[str(normal)] = index
-
- # using JSON Loader with static mesh
- else:
-
- for index, normal in enumerate(vertex_normals):
- normal = flip_axes(normal)
- normal_indices[str(normal)] = index
-
- logger.info("Parsing %d faces", len(mesh.tessfaces))
- for face in mesh.tessfaces:
- vert_count = len(face.vertices)
-
- if vert_count not in (3, 4):
- logger.error("%d vertices for face %d detected",
- vert_count,
- face.index)
- raise exceptions.NGonError("ngons are not supported")
-
- mat_index = face.material_index is not None and opt_materials
- mask = {
- constants.QUAD: vert_count is 4,
- constants.MATERIALS: mat_index,
- constants.UVS: False,
- constants.NORMALS: False,
- constants.COLORS: False
- }
-
- face_data = []
-
- face_data.extend([v for v in face.vertices])
-
- if mask[constants.MATERIALS]:
- for mat_index, mat in enumerate(material_list):
- if mat[constants.DBG_INDEX] == face.material_index:
- face_data.append(mat_index)
- break
- else:
- logger.warning("Could not map the material index "
- "for face %d" % face.index)
- face_data.append(0) # default to index zero if there's a bad material
-
- if uv_indices:
- for index, uv_layer in enumerate(uv_indices):
- layer = mesh.tessface_uv_textures[index]
-
- for uv_data in layer.data[face.index].uv:
- uv_tuple = (uv_data[0], uv_data[1])
- uv_index = uv_layer[str(uv_tuple)]
- face_data.append(uv_index)
- mask[constants.UVS] = True
-
- if vertex_normals:
-
- # using Object Loader with skinned mesh
- if options.get(constants.SCENE, True) and _armature(mesh):
-
- for vertex in face.vertices:
- normal = mesh.vertices[vertex].normal
- normal = flip_axes(normal, XZ_Y) if face.use_smooth else flip_axes(face.normal, XZ_Y)
- face_data.append(normal_indices[str(normal)])
- mask[constants.NORMALS] = True
-
- # using Object Loader with static mesh
- elif options.get(constants.SCENE, True) and not _armature(mesh):
-
- for vertex in face.vertices:
- normal = mesh.vertices[vertex].normal
- normal = flip_axes(normal, _XY_Z) if face.use_smooth else flip_axes(face.normal, _XY_Z)
- face_data.append(normal_indices[str(normal)])
- mask[constants.NORMALS] = True
-
- # using JSON Loader with skinned mesh
- elif not options.get(constants.SCENE, True) and _armature(mesh):
-
- for vertex in face.vertices:
- normal = mesh.vertices[vertex].normal
- normal = flip_axes(normal) if face.use_smooth else flip_axes(face.normal)
- face_data.append(normal_indices[str(normal)])
- mask[constants.NORMALS] = True
-
- # using JSON Loader with static mesh
- else:
-
- for vertex in face.vertices:
- normal = mesh.vertices[vertex].normal
- normal = flip_axes(normal) if face.use_smooth else flip_axes(face.normal)
- face_data.append(normal_indices[str(normal)])
- mask[constants.NORMALS] = True
-
-
- if vertex_colours:
- colours = mesh.tessface_vertex_colors.active.data[face.index]
-
- for each in (colours.color1, colours.color2, colours.color3):
- each = utilities.rgb2int(each)
- face_data.append(colour_indices[str(each)])
- mask[constants.COLORS] = True
-
- if mask[constants.QUAD]:
- colour = utilities.rgb2int(colours.color4)
- face_data.append(colour_indices[str(colour)])
-
- face_data.insert(0, utilities.bit_mask(mask))
- faces_data.extend(face_data)
-
- return faces_data
-
-
-@_mesh
-def morph_targets(mesh, options):
- """
-
- :param mesh:
- :param options:
-
- """
- logger.debug("mesh.morph_targets(%s, %s)", mesh, options)
- obj = object_.objects_using_mesh(mesh)[0]
- original_frame = context.scene.frame_current
- frame_step = options.get(constants.FRAME_STEP, 1)
- scene_frames = range(context.scene.frame_start,
- context.scene.frame_end+1,
- frame_step)
-
- morphs = []
-
- for frame in scene_frames:
- logger.info("Processing data at frame %d", frame)
- context.scene.frame_set(frame, 0.0)
- morphs.append([])
- vertices_ = object_.extract_mesh(obj, options).vertices[:]
-
- # using Object Loader with skinned mesh
- if options.get(constants.SCENE, True) and _armature(mesh):
-
- for vertex in vertices_:
- morphs[-1].extend(flip_axes(vertex.co, XZ_Y))
-
- # using Object Loader with static mesh
- elif options.get(constants.SCENE, True) and not _armature(mesh):
-
- for vertex in vertices_:
- morphs[-1].extend(flip_axes(vertex.co, _XY_Z))
-
- # using JSON Loader with skinned mesh
- elif not options.get(constants.SCENE, True) and _armature(mesh):
-
- for vertex in vertices_:
- morphs[-1].extend(flip_axes(vertex.co))
-
- # using JSON Loader with static mesh
- else:
-
- for vertex in vertices_:
- morphs[-1].extend(flip_axes(vertex.co))
-
- context.scene.frame_set(original_frame, 0.0)
- morphs_detected = False
- for index, each in enumerate(morphs):
- if index is 0:
- continue
- morphs_detected = morphs[index-1] != each
- if morphs_detected:
- logger.info("Valid morph target data detected")
- break
- else:
- logger.info("No valid morph data detected")
- return []
-
- manifest = []
- for index, morph in enumerate(morphs):
- manifest.append({
- constants.NAME: 'animation_%06d' % index,
- constants.VERTICES: morph
- })
-
- return manifest
-
-@_mesh
-def blend_shapes(mesh, options):
- """
-
- :param mesh:
- :param options:
-
- """
- logger.debug("mesh.blend_shapes(%s, %s)", mesh, options)
- manifest = []
- if mesh.shape_keys:
- logger.info("mesh.blend_shapes -- there's shape keys")
- key_blocks = mesh.shape_keys.key_blocks
- for key in key_blocks.keys()[1:]: # skip "Basis"
- logger.info("mesh.blend_shapes -- key %s", key)
- morph = []
- for d in key_blocks[key].data:
- co = d.co
- morph.extend([co.x, co.y, co.z])
- manifest.append({
- constants.NAME: key,
- constants.VERTICES: morph
- })
- else:
- logger.debug("No valid blend_shapes detected")
- return manifest
-
-@_mesh
-def animated_blend_shapes(mesh, name, options):
- """
-
- :param mesh:
- :param options:
-
- """
-
- # let filter the name to only keep the node's name
- # the two cases are '%sGeometry' and '%sGeometry.%d', and we want %s
- name = re.search("^(.*)Geometry(\..*)?$", name).group(1)
-
- logger.debug("mesh.animated_blend_shapes(%s, %s)", mesh, options)
- tracks = []
- shp = mesh.shape_keys
- animCurves = shp.animation_data
- if animCurves:
- animCurves = animCurves.action.fcurves
-
- for key in shp.key_blocks.keys()[1:]: # skip "Basis"
- key_name = name+".morphTargetInfluences["+key+"]"
- found_animation = False
- data_path = 'key_blocks["'+key+'"].value'
- values = []
- if animCurves:
- for fcurve in animCurves:
- if fcurve.data_path == data_path:
- for xx in fcurve.keyframe_points:
- values.append({ "time": xx.co.x, "value": xx.co.y })
- found_animation = True
- break # no need to continue
-
- if found_animation:
- tracks.append({
- constants.NAME: key_name,
- constants.TYPE: "number",
- constants.KEYS: values
- });
-
- return tracks
-
-@_mesh
-def materials(mesh, options):
- """
-
- :param mesh:
- :param options:
-
- """
- logger.debug("mesh.materials(%s, %s)", mesh, options)
-
- # sanity check
- if not mesh.materials:
- return []
-
- indices = []
-
- #manthrax: Disable the following logic that attempts to find only the used materials on this mesh
- #for face in mesh.tessfaces:
- # if face.material_index not in indices:
- # indices.append(face.material_index)
- # instead, export all materials on this object... they are probably there for a good reason, even if they aren't referenced by the geometry at present...
- for index in range(len( mesh.materials )):
- indices.append(index)
-
-
- material_sets = [(mesh.materials[index], index) for index in indices]
- materials_ = []
-
- maps = options.get(constants.MAPS)
-
- mix = options.get(constants.MIX_COLORS)
- use_colors = options.get(constants.COLORS)
- logger.info("Colour mix is set to %s", mix)
- logger.info("Vertex colours set to %s", use_colors)
-
- for mat, index in material_sets:
- if mat == None: # undefined material for a specific index is skipped
- continue
-
- try:
- dbg_color = constants.DBG_COLORS[index]
- except IndexError:
- dbg_color = constants.DBG_COLORS[0]
-
- logger.info("Compiling attributes for %s", mat.name)
- attributes = {
- constants.COLOR_EMISSIVE: material.emissive_color(mat),
- constants.SHADING: material.shading(mat),
- constants.OPACITY: material.opacity(mat),
- constants.TRANSPARENT: material.transparent(mat),
- constants.VISIBLE: material.visible(mat),
- constants.WIREFRAME: material.wireframe(mat),
- constants.BLENDING: material.blending(mat),
- constants.DEPTH_TEST: material.depth_test(mat),
- constants.DEPTH_WRITE: material.depth_write(mat),
- constants.DOUBLE_SIDED: material.double_sided(mat),
- constants.DBG_NAME: mat.name,
- constants.DBG_COLOR: dbg_color,
- constants.DBG_INDEX: index
- }
-
- if use_colors:
- colors = material.use_vertex_colors(mat)
- attributes[constants.VERTEX_COLORS] = colors
-
- if (use_colors and mix) or (not use_colors):
- colors = material.diffuse_color(mat)
- attributes[constants.COLOR_DIFFUSE] = colors
-
- if attributes[constants.SHADING] == constants.PHONG:
- logger.info("Adding specular attributes")
- attributes.update({
- constants.SPECULAR_COEF: material.specular_coef(mat),
- constants.COLOR_SPECULAR: material.specular_color(mat)
- })
-
- if mesh.show_double_sided:
- logger.info("Double sided is on")
- attributes[constants.DOUBLE_SIDED] = True
-
- materials_.append(attributes)
-
- if not maps:
- continue
-
- diffuse = _diffuse_map(mat)
- if diffuse:
- logger.info("Diffuse map found")
- attributes.update(diffuse)
-
- light = _light_map(mat)
- if light:
- logger.info("Light map found")
- attributes.update(light)
-
- specular = _specular_map(mat)
- if specular:
- logger.info("Specular map found")
- attributes.update(specular)
-
- if attributes[constants.SHADING] == constants.PHONG:
- normal = _normal_map(mat)
- if normal:
- logger.info("Normal map found")
- attributes.update(normal)
-
- bump = _bump_map(mat)
- if bump:
- logger.info("Bump map found")
- attributes.update(bump)
-
- return materials_
-
-
-@_mesh
-def normals(mesh, options):
- """
-
- :param mesh:
- :rtype: []
-
- """
- logger.debug("mesh.normals(%s)", mesh)
- normal_vectors = []
-
- for vector in _normals(mesh, options):
- normal_vectors.extend(vector)
-
- return normal_vectors
-
-
-@_mesh
-def skin_weights(mesh, bone_map, influences, anim_type):
- """
-
- :param mesh:
- :param bone_map:
- :param influences:
- :param anim_type
-
- """
- logger.debug("mesh.skin_weights(%s)", mesh)
- return _skinning_data(mesh, bone_map, influences, anim_type, 1)
-
-
-@_mesh
-def skin_indices(mesh, bone_map, influences, anim_type):
- """
-
- :param mesh:
- :param bone_map:
- :param influences:
- :param anim_type
-
- """
- logger.debug("mesh.skin_indices(%s)", mesh)
- return _skinning_data(mesh, bone_map, influences, anim_type, 0)
-
-
-@_mesh
-def texture_registration(mesh):
- """
-
- :param mesh:
-
- """
- logger.debug("mesh.texture_registration(%s)", mesh)
- materials_ = mesh.materials or []
- registration = {}
-
- funcs = (
- (constants.MAP_DIFFUSE, material.diffuse_map),
- (constants.SPECULAR_MAP, material.specular_map),
- (constants.LIGHT_MAP, material.light_map),
- (constants.BUMP_MAP, material.bump_map),
- (constants.NORMAL_MAP, material.normal_map)
- )
-
- def _registration(file_path, file_name):
- """
-
- :param file_path:
- :param file_name:
-
- """
- return {
- 'file_path': file_path,
- 'file_name': file_name,
- 'maps': []
- }
-
- logger.info("found %d materials", len(materials_))
- for mat in materials_:
- for (key, func) in funcs:
- tex = func(mat)
- if tex is None:
- continue
-
- logger.info("%s has texture %s", key, tex.name)
- file_path = texture.file_path(tex)
- file_name = texture.file_name(tex)
-
- reg = registration.setdefault(
- utilities.hash(file_path),
- _registration(file_path, file_name))
-
- reg["maps"].append(key)
-
- return registration
-
-
-@_mesh
-def uvs(mesh):
- """
-
- :param mesh:
- :rtype: []
-
- """
- logger.debug("mesh.uvs(%s)", mesh)
- uvs_ = []
- for layer in _uvs(mesh)[0]:
- uvs_.append([])
- logger.info("Parsing UV layer %d", len(uvs_))
- for pair in layer:
- uvs_[-1].extend(pair)
- return uvs_
-
-
-@_mesh
-def vertex_colors(mesh):
- """
-
- :param mesh:
-
- """
- logger.debug("mesh.vertex_colors(%s)", mesh)
- vertex_colours = []
-
- try:
- vertex_colour = mesh.tessface_vertex_colors.active.data
- except AttributeError:
- logger.info("No vertex colours found")
- return
-
- for face in mesh.tessfaces:
-
- colours = (vertex_colour[face.index].color1,
- vertex_colour[face.index].color2,
- vertex_colour[face.index].color3,
- vertex_colour[face.index].color4)
-
- for colour in colours:
- colour = utilities.rgb2int((colour.r, colour.g, colour.b))
-
- if colour not in vertex_colours:
- vertex_colours.append(colour)
-
- return vertex_colours
-
-
-@_mesh
-def vertices(mesh, options):
- """
-
- :param mesh:
- :rtype: []
-
- """
- logger.debug("mesh.vertices(%s)", mesh)
- vertices_ = []
-
- # using Object Loader with skinned mesh
- if options.get(constants.SCENE, True) and _armature(mesh):
-
- for vertex in mesh.vertices:
- vertices_.extend(flip_axes(vertex.co, XZ_Y))
-
- # using Object Loader with static mesh
- elif options.get(constants.SCENE, True) and not _armature(mesh):
-
- for vertex in mesh.vertices:
- vertices_.extend(flip_axes(vertex.co, _XY_Z))
-
- # using JSON Loader with skinned mesh
- elif not options.get(constants.SCENE, True) and _armature(mesh):
-
- for vertex in mesh.vertices:
- vertices_.extend(flip_axes(vertex.co))
-
- # using JSON Loader with static mesh
- else:
-
- for vertex in mesh.vertices:
- vertices_.extend(flip_axes(vertex.co))
-
- return vertices_
-
-
-def _normal_map(mat):
- """
-
- :param mat:
-
- """
- tex = material.normal_map(mat)
- if tex is None:
- return
-
- logger.info("Found normal texture map %s", tex.name)
-
- normal = {
- constants.MAP_NORMAL:
- texture.file_name(tex),
- constants.MAP_NORMAL_FACTOR:
- material.normal_scale(mat),
- constants.MAP_NORMAL_ANISOTROPY:
- texture.anisotropy(tex),
- constants.MAP_NORMAL_WRAP: texture.wrap(tex),
- constants.MAP_NORMAL_REPEAT: texture.repeat(tex)
- }
-
- return normal
-
-
-def _bump_map(mat):
- """
-
- :param mat:
-
- """
- tex = material.bump_map(mat)
- if tex is None:
- return
-
- logger.info("Found bump texture map %s", tex.name)
-
- bump = {
- constants.MAP_BUMP:
- texture.file_name(tex),
- constants.MAP_BUMP_ANISOTROPY:
- texture.anisotropy(tex),
- constants.MAP_BUMP_WRAP: texture.wrap(tex),
- constants.MAP_BUMP_REPEAT: texture.repeat(tex),
- constants.MAP_BUMP_SCALE:
- material.bump_scale(mat),
- }
-
- return bump
-
-
-def _specular_map(mat):
- """
-
- :param mat:
-
- """
- tex = material.specular_map(mat)
- if tex is None:
- return
-
- logger.info("Found specular texture map %s", tex.name)
-
- specular = {
- constants.MAP_SPECULAR:
- texture.file_name(tex),
- constants.MAP_SPECULAR_ANISOTROPY:
- texture.anisotropy(tex),
- constants.MAP_SPECULAR_WRAP: texture.wrap(tex),
- constants.MAP_SPECULAR_REPEAT: texture.repeat(tex)
- }
-
- return specular
-
-
-def _light_map(mat):
- """
-
- :param mat:
-
- """
- tex = material.light_map(mat)
- if tex is None:
- return
-
- logger.info("Found light texture map %s", tex.name)
-
- light = {
- constants.MAP_LIGHT:
- texture.file_name(tex),
- constants.MAP_LIGHT_ANISOTROPY:
- texture.anisotropy(tex),
- constants.MAP_LIGHT_WRAP: texture.wrap(tex),
- constants.MAP_LIGHT_REPEAT: texture.repeat(tex)
- }
-
- return light
-
-
-def _diffuse_map(mat):
- """
-
- :param mat:
-
- """
- tex = material.diffuse_map(mat)
- if tex is None:
- return
-
- logger.info("Found diffuse texture map %s", tex.name)
-
- diffuse = {
- constants.MAP_DIFFUSE:
- texture.file_name(tex),
- constants.MAP_DIFFUSE_ANISOTROPY:
- texture.anisotropy(tex),
- constants.MAP_DIFFUSE_WRAP: texture.wrap(tex),
- constants.MAP_DIFFUSE_REPEAT: texture.repeat(tex)
- }
-
- return diffuse
-
-
-def _normals(mesh, options):
- """
-
- :param mesh:
- :rtype: []
-
- """
- vectors = []
-
- vectors_ = {}
- for face in mesh.tessfaces:
-
- if options.get(constants.SCENE, True) and _armature(mesh):
-
- for vertex_index in face.vertices:
- normal = mesh.vertices[vertex_index].normal
- vector = flip_axes(normal, XZ_Y) if face.use_smooth else flip_axes(face.normal, XZ_Y)
-
- str_vec = str(vector)
- try:
- vectors_[str_vec]
- except KeyError:
- vectors.append(vector)
- vectors_[str_vec] = True
-
- elif options.get(constants.SCENE, True) and not _armature(mesh):
-
- for vertex_index in face.vertices:
- normal = mesh.vertices[vertex_index].normal
- vector = flip_axes(normal,_XY_Z) if face.use_smooth else flip_axes(face.normal,_XY_Z)
-
- str_vec = str(vector)
- try:
- vectors_[str_vec]
- except KeyError:
- vectors.append(vector)
- vectors_[str_vec] = True
-
- elif not options.get(constants.SCENE, True) and _armature(mesh):
-
- for vertex_index in face.vertices:
- normal = mesh.vertices[vertex_index].normal
- vector = flip_axes(normal) if face.use_smooth else flip_axes(face.normal)
-
- str_vec = str(vector)
- try:
- vectors_[str_vec]
- except KeyError:
- vectors.append(vector)
- vectors_[str_vec] = True
-
- else:
-
- for vertex_index in face.vertices:
- normal = mesh.vertices[vertex_index].normal
- vector = flip_axes(normal) if face.use_smooth else flip_axes(face.normal)
-
- str_vec = str(vector)
- try:
- vectors_[str_vec]
- except KeyError:
- vectors.append(vector)
- vectors_[str_vec] = True
-
- return vectors
-
-
-def _uvs(mesh):
- """
-
- :param mesh:
- :rtype: [[], ...], [{}, ...]
-
- """
- uv_layers = []
- uv_indices = []
-
- for layer in mesh.uv_layers:
- uv_layers.append([])
- uv_indices.append({})
- index = 0
-
- for uv_data in layer.data:
- uv_tuple = (uv_data.uv[0], uv_data.uv[1])
- uv_key = str(uv_tuple)
-
- try:
- uv_indices[-1][uv_key]
- except KeyError:
- uv_indices[-1][uv_key] = index
- uv_layers[-1].append(uv_tuple)
- index += 1
-
- return uv_layers, uv_indices
-
-
-def _armature(mesh):
- """
-
- :param mesh:
-
- """
- obj = object_.objects_using_mesh(mesh)[0]
- armature = obj.find_armature()
-
- #manthrax: Remove logging spam. This was spamming on every vertex...
- #if armature:
- # logger.info("Found armature %s for %s", armature.name, obj.name)
- #else:
- # logger.info("Found no armature for %s", obj.name)
- return armature
-
-
-def _skinning_data(mesh, bone_map, influences, anim_type, array_index):
- """
-
- :param mesh:
- :param bone_map:
- :param influences:
- :param array_index:
- :param anim_type
-
- """
- armature = _armature(mesh)
- manifest = []
- if not armature:
- return manifest
-
- # armature bones here based on type
- if anim_type == constants.OFF or anim_type == constants.REST:
- armature_bones = armature.data.bones
- else:
- # POSE mode
- armature_bones = armature.pose.bones
-
- obj = object_.objects_using_mesh(mesh)[0]
- logger.debug("Skinned object found %s", obj.name)
-
- for vertex in mesh.vertices:
- bone_array = []
- for group in vertex.groups:
- bone_array.append((group.group, group.weight))
-
- bone_array.sort(key=operator.itemgetter(1), reverse=True)
-
- for index in range(influences):
- if index >= len(bone_array):
- manifest.append(0)
- continue
- name = obj.vertex_groups[bone_array[index][0]].name
- for bone_index, bone in enumerate(armature_bones):
- if bone.name != name:
- continue
- if array_index is 0:
- entry = bone_map.get(bone_index, -1)
- else:
- entry = bone_array[index][1]
-
- manifest.append(entry)
- break
- else:
- manifest.append(0)
-
- return manifest
-
-
-def _pose_bones(armature):
- """
-
- :param armature:
- :rtype: [], {}
-
- """
- bones_ = []
- bone_map = {}
- bone_count = 0
-
- armature_matrix = armature.matrix_world
- for bone_count, pose_bone in enumerate(armature.pose.bones):
- armature_bone = pose_bone.bone
- bone_index = None
-
- if armature_bone.parent is None:
- bone_matrix = armature_matrix * armature_bone.matrix_local
- bone_index = -1
- else:
- parent_bone = armature_bone.parent
- parent_matrix = armature_matrix * parent_bone.matrix_local
- bone_matrix = armature_matrix * armature_bone.matrix_local
- bone_matrix = parent_matrix.inverted() * bone_matrix
- bone_index = index = 0
-
- for pose_parent in armature.pose.bones:
- armature_parent = pose_parent.bone.name
- if armature_parent == parent_bone.name:
- bone_index = index
- index += 1
-
- bone_map[bone_count] = bone_count
-
- pos, rot, scl = bone_matrix.decompose()
- bones_.append({
- constants.PARENT: bone_index,
- constants.NAME: armature_bone.name,
-
- constants.POS: (pos.x, pos.z, -pos.y),
- constants.ROTQ: (rot.x, rot.z, -rot.y, rot.w),
- constants.SCL: (scl.x, scl.z, scl.y)
- })
-
- return bones_, bone_map
-
-
-def _rest_bones(armature):
- """
-
- :param armature:
- :rtype: [], {}
-
- """
- bones_ = []
- bone_map = {}
- bone_count = 0
- bone_index_rel = 0
-
- for bone in armature.data.bones:
- logger.info("Parsing bone %s", bone.name)
-
- if not bone.use_deform:
- logger.debug("Ignoring bone %s at: %d",
- bone.name, bone_index_rel)
- continue
-
- if bone.parent is None:
- bone_pos = bone.head_local
- logger.debug("Root bone:%s",str(bone_pos))
- bone_index = -1
- else:
- bone_pos = bone.head_local - bone.parent.head_local
- logger.debug("Child bone:%s",str(bone_pos))
-
- bone_index = 0
- index = 0
- for parent in armature.data.bones:
- if parent.name == bone.parent.name:
- bone_index = bone_map.get(index)
- index += 1
-
- bone_world_pos = armature.matrix_world * bone_pos
-
- x_axis = bone_world_pos.x
- y_axis = bone_world_pos.z
- z_axis = -bone_world_pos.y
-
- logger.debug("Bone pos:%s",str(bone_world_pos))
-
- logger.debug("Adding bone %s at: %s, %s",
- bone.name, bone_index, bone_index_rel)
- bone_map[bone_count] = bone_index_rel
- bone_index_rel += 1
- # @TODO: the rotq probably should not have these
- # hard coded values
- bones_.append({
- constants.PARENT: bone_index,
- constants.NAME: bone.name,
- constants.POS: (x_axis, y_axis, z_axis),
- constants.ROTQ: (0, 0, 0, 1)
- })
-
- bone_count += 1
-
- return (bones_, bone_map)
diff --git a/utils/exporters/blender/addons/io_three/exporter/api/object.py b/utils/exporters/blender/addons/io_three/exporter/api/object.py
deleted file mode 100644
index 23b84dfef0a02c9abe2fb1be8a41be0bc8d69124..0000000000000000000000000000000000000000
--- a/utils/exporters/blender/addons/io_three/exporter/api/object.py
+++ /dev/null
@@ -1,747 +0,0 @@
-import math
-import mathutils
-import bpy
-from bpy import data, context, types
-from bpy_extras.io_utils import axis_conversion
-from .. import constants, logger, utilities, exceptions
-from .constants import (
- MESH,
- EMPTY,
- ARMATURE,
- LAMP,
- AREA,
- SPOT,
- SUN,
- POINT,
- HEMI,
- CAMERA,
- PERSP,
- ORTHO,
- RENDER,
- NO_SHADOW,
- ZYX
-)
-# TODO: RectAreaLight support
-
-
-# Blender doesn't seem to have a good way to link a mesh back to the
-# objects that are instancing it, or it is bloody obvious and I haven't
-# discovered yet. This manifest serves as a way for me to map a mesh
-# node to the object nodes that are using it.
-_MESH_MAP = {}
-
-
-def _object(func):
- """
-
- :param func:
-
- """
-
- def inner(arg, *args, **kwargs):
- """
-
- :param arg:
- :param *args:
- :param **kwargs:
-
- """
-
- if isinstance(arg, types.Object):
- obj = arg
- else:
- obj = data.objects[arg]
-
- return func(obj, *args, **kwargs)
-
- return inner
-
-
-def clear_mesh_map():
- """Clears the mesh map, required on initialization"""
- _MESH_MAP.clear()
-
-
-def assemblies(valid_types, options):
- """
-
- :param valid_types:
- :param options:
-
- """
- logger.debug('object.assemblies(%s)', valid_types)
- for obj in data.objects:
-
- # rigged assets are parented under armature nodes
- if obj.parent and obj.parent.type != ARMATURE:
- continue
- if obj.parent and obj.parent.type == ARMATURE:
- logger.info('Has armature parent %s', obj.name)
- if _valid_node(obj, valid_types, options):
- yield obj.name
-
-
-@_object
-def cast_shadow(obj):
- """
-
- :param obj:
-
- """
- logger.debug('object.cast_shadow(%s)', obj)
- if obj.type == LAMP:
- if obj.data.type in (SPOT, SUN):
- ret = obj.data.shadow_method != NO_SHADOW
- else:
- logger.info('%s is a lamp but this lamp type does not '\
- 'have supported shadows in ThreeJS', obj.name)
- ret = None
- return ret
- elif obj.type == MESH:
- mats = material(obj)
- if mats:
- for m in mats:
- if data.materials[m].use_cast_shadows:
- return True
- return False
-
-
-@_object
-def children(obj, valid_types):
- """
-
- :param obj:
- :param valid_types:
-
- """
- logger.debug('object.children(%s, %s)', obj, valid_types)
- for child in obj.children:
- if child.type in valid_types and child.THREE_export:
- yield child.name
-
-
-@_object
-def material(obj):
- """
-
- :param obj:
-
- """
- logger.debug('object.material(%s)', obj)
-
- try:
- matName = obj.material_slots[0].name # manthrax: Make this throw an error on an empty material array, resulting in non-material
- return [o.name for o in obj.material_slots]
- except IndexError:
- pass
-
-def extract_time(fcurves, start_index):
- time = []
- for xx in fcurves[start_index].keyframe_points:
- time.append(xx.co.x)
- return time
-
-def merge_sorted_lists(l1, l2):
- sorted_list = []
- l1 = l1[:]
- l2 = l2[:]
- while (l1 and l2):
- h1 = l1[0]
- h2 = l2[0]
- if h1 == h2:
- sorted_list.append(h1)
- l1.pop(0)
- l2.pop(0)
- elif h1 < h2:
- l1.pop(0)
- sorted_list.append(h1)
- else:
- l2.pop(0)
- sorted_list.append(h2)
- # Add the remaining of the lists
- sorted_list.extend(l1 if l1 else l2)
- return sorted_list
-
-def appendVec3(track, time, vec3):
- track.append({ "time": time, "value": [ vec3.x, vec3.y, vec3.z ] })
-
-def appendQuat(track, time, quat):
- track.append({ "time": time, "value": [ quat.x, quat.y, quat.z, quat.w ] })
-
-# trackable transform fields (