# ##### 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 #####
"""
Blender exporter for Three.js (ASCII JSON format).
TODO
- binary format
"""
import bpy
import mathutils
import shutil
import os
import os.path
import math
import operator
import random
# #####################################################
# Configuration
# #####################################################
DEFAULTS = {
"bgcolor" : [0, 0, 0],
"bgalpha" : 1.0,
"position" : [0, 0, 0],
"rotation" : [0, 0, 0],
"scale" : [1, 1, 1],
"camera" :
{
"name" : "default_camera",
"type" : "PerspectiveCamera",
"near" : 1,
"far" : 10000,
"fov" : 60,
"aspect": 1.333,
"position" : [0, 0, 10],
"target" : [0, 0, 0]
},
"light" :
{
"name" : "default_light",
"type" : "DirectionalLight",
"direction" : [0, 1, 1],
"color" : [1, 1, 1],
"intensity" : 0.8
}
}
ROTATE_X_PI2 = mathutils.Quaternion((1.0, 0.0, 0.0), math.radians(-90.0)).to_matrix().to_4x4()
# default colors for debugging (each material gets one distinct color):
# white, red, green, blue, yellow, cyan, magenta
COLORS = [0xeeeeee, 0xee0000, 0x00ee00, 0x0000ee, 0xeeee00, 0x00eeee, 0xee00ee]
# skinning
MAX_INFLUENCES = 2
# #####################################################
# Templates - scene
# #####################################################
TEMPLATE_SCENE_ASCII = """\
{
"metadata" :
{
"formatVersion" : 3.2,
"type" : "scene",
"sourceFile" : "%(fname)s",
"generatedBy" : "Blender 2.7 Exporter",
"objects" : %(nobjects)s,
"geometries" : %(ngeometries)s,
"materials" : %(nmaterials)s,
"textures" : %(ntextures)s
},
"urlBaseType" : %(basetype)s,
%(sections)s
"transform" :
{
"position" : %(position)s,
"rotation" : %(rotation)s,
"scale" : %(scale)s
},
"defaults" :
{
"bgcolor" : %(bgcolor)s,
"bgalpha" : %(bgalpha)f,
"camera" : %(defcamera)s
}
}
"""
TEMPLATE_SECTION = """
"%s" :
{
%s
},
"""
TEMPLATE_OBJECT = """\
%(object_id)s : {
"geometry" : %(geometry_id)s,
"groups" : [ %(group_id)s ],
"material" : %(material_id)s,
"position" : %(position)s,
"rotation" : %(rotation)s,
"quaternion": %(quaternion)s,
"scale" : %(scale)s,
"visible" : %(visible)s,
"castShadow" : %(castShadow)s,
"receiveShadow" : %(receiveShadow)s,
"doubleSided" : %(doubleSided)s
}"""
TEMPLATE_EMPTY = """\
%(object_id)s : {
"groups" : [ %(group_id)s ],
"position" : %(position)s,
"rotation" : %(rotation)s,
"quaternion": %(quaternion)s,
"scale" : %(scale)s
}"""
TEMPLATE_GEOMETRY_LINK = """\
%(geometry_id)s : {
"type" : "ascii",
"url" : %(model_file)s
}"""
TEMPLATE_GEOMETRY_EMBED = """\
%(geometry_id)s : {
"type" : "embedded",
"id" : %(embed_id)s
}"""
TEMPLATE_TEXTURE = """\
%(texture_id)s : {
"url": %(texture_file)s%(extras)s
}"""
TEMPLATE_MATERIAL_SCENE = """\
%(material_id)s : {
"type": %(type)s,
"parameters": { %(parameters)s }
}"""
TEMPLATE_CAMERA_PERSPECTIVE = """\
%(camera_id)s : {
"type" : "PerspectiveCamera",
"fov" : %(fov)f,
"aspect": %(aspect)f,
"near" : %(near)f,
"far" : %(far)f,
"position": %(position)s,
"target" : %(target)s
}"""
TEMPLATE_CAMERA_ORTHO = """\
%(camera_id)s : {
"type" : "OrthographicCamera",
"left" : %(left)f,
"right" : %(right)f,
"top" : %(top)f,
"bottom": %(bottom)f,
"near" : %(near)f,
"far" : %(far)f,
"position": %(position)s,
"target" : %(target)s
}"""
TEMPLATE_LIGHT_POINT = """\
%(light_id)s : {
"type" : "PointLight",
"position" : %(position)s,
"rotation" : %(rotation)s,
"color" : %(color)d,
"distance" : %(distance).3f,
"intensity" : %(intensity).3f
}"""
TEMPLATE_LIGHT_SUN = """\
%(light_id)s : {
"type" : "AmbientLight",
"position" : %(position)s,
"rotation" : %(rotation)s,
"color" : %(color)d,
"distance" : %(distance).3f,
"intensity" : %(intensity).3f
}"""
TEMPLATE_LIGHT_SPOT = """\
%(light_id)s : {
"type" : "SpotLight",
"position" : %(position)s,
"rotation" : %(rotation)s,
"color" : %(color)d,
"distance" : %(distance).3f,
"intensity" : %(intensity).3f,
"use_shadow" : %(use_shadow)d,
"angle" : %(angle).3f
}"""
TEMPLATE_LIGHT_HEMI = """\
%(light_id)s : {
"type" : "HemisphereLight",
"position" : %(position)s,
"rotation" : %(rotation)s,
"color" : %(color)d,
"distance" : %(distance).3f,
"intensity" : %(intensity).3f
}"""
TEMPLATE_LIGHT_AREA = """\
%(light_id)s : {
"type" : "AreaLight",
"position" : %(position)s,
"rotation" : %(rotation)s,
"color" : %(color)d,
"distance" : %(distance).3f,
"intensity" : %(intensity).3f,
"gamma" : %(gamma).3f,
"shape" : "%(shape)s",
"size" : %(size).3f,
"size_y" : %(size_y).3f
}"""
TEMPLATE_VEC4 = '[ %g, %g, %g, %g ]'
TEMPLATE_VEC3 = '[ %g, %g, %g ]'
TEMPLATE_VEC2 = '[ %g, %g ]'
TEMPLATE_STRING = '"%s"'
TEMPLATE_HEX = "0x%06x"
# #####################################################
# Templates - model
# #####################################################
TEMPLATE_FILE_ASCII = """\
{
"metadata" :
{
"formatVersion" : 3.1,
"generatedBy" : "Blender 2.7 Exporter",
"vertices" : %(nvertex)d,
"faces" : %(nface)d,
"normals" : %(nnormal)d,
"colors" : %(ncolor)d,
"uvs" : [%(nuvs)s],
"materials" : %(nmaterial)d,
"morphTargets" : %(nmorphTarget)d,
"bones" : %(nbone)d
},
%(model)s
}
"""
TEMPLATE_MODEL_ASCII = """\
"scale" : %(scale)f,
"materials" : [%(materials)s],
"vertices" : [%(vertices)s],
"morphTargets" : [%(morphTargets)s],
"normals" : [%(normals)s],
"colors" : [%(colors)s],
"uvs" : [%(uvs)s],
"faces" : [%(faces)s],
"bones" : [%(bones)s],
"skinIndices" : [%(indices)s],
"skinWeights" : [%(weights)s],
"animations" : [%(animations)s]
"""
TEMPLATE_VERTEX = "%g,%g,%g"
TEMPLATE_VERTEX_TRUNCATE = "%d,%d,%d"
TEMPLATE_N = "%g,%g,%g"
TEMPLATE_UV = "%g,%g"
TEMPLATE_C = "%d"
# #####################################################
# Utils
# #####################################################
def veckey3(x,y,z):
return round(x, 6), round(y, 6), round(z, 6)
def veckey3d(v):
return veckey3(v.x, v.y, v.z)
def veckey2d(v):
return round(v[0], 6), round(v[1], 6)
def get_faces(obj):
if hasattr(obj, "tessfaces"):
return obj.tessfaces
else:
return obj.faces
def get_normal_indices(v, normals, mesh):
n = []
mv = mesh.vertices
for i in v:
normal = mv[i].normal
key = veckey3d(normal)
n.append( normals[key] )
return n
def get_uv_indices(face_index, uvs, mesh, layer_index):
uv = []
uv_layer = mesh.tessface_uv_textures[layer_index].data
for i in uv_layer[face_index].uv:
uv.append( uvs[veckey2d(i)] )
return uv
def get_color_indices(face_index, colors, mesh):
c = []
color_layer = mesh.tessface_vertex_colors.active.data
face_colors = color_layer[face_index]
face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
for i in face_colors: