提交 9df3f9b1 编写于 作者: T tschw

Blender export of indexed BufferGeometry objects.

上级 7b2c3e07
......@@ -38,7 +38,7 @@ logging.basicConfig(
bl_info = {
'name': "Three.js Format",
'author': "repsac, mrdoob, yomotsu, mpk, jpweeks, rkusa",
'author': "repsac, mrdoob, yomotsu, mpk, jpweeks, rkusa, tschw",
'version': (1, 4, 0),
'blender': (2, 7, 3),
'location': "File > Export",
......@@ -308,6 +308,10 @@ def restore_export_settings(properties, settings):
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 {
......@@ -430,6 +434,7 @@ def set_settings(properties):
constants.BONES: properties.option_bones,
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,
......@@ -566,6 +571,17 @@ class ExportThree(bpy.types.Operator, ExportHelper):
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",
......@@ -768,6 +784,8 @@ class ExportThree(bpy.types.Operator, ExportHelper):
row = layout.row()
row.prop(self.properties, 'option_geometry_type')
row = layout.row()
row.prop(self.properties, 'option_index_type')
## }
layout.separator()
......
......@@ -47,6 +47,11 @@ UVS = 'uvs'
APPLY_MODIFIERS = 'applyModifiers'
COLORS = 'colors'
MIX_COLORS = 'mixColors'
INDEX = 'index'
DRAW_CALLS = 'offsets'
DC_START = 'start'
DC_COUNT = 'count'
DC_INDEX = 'index'
SCALE = 'scale'
COMPRESSION = 'compression'
MAPS = 'maps'
......@@ -77,6 +82,7 @@ GLOBAL = 'global'
BUFFER_GEOMETRY = 'BufferGeometry'
GEOMETRY = 'geometry'
GEOMETRY_TYPE = 'geometryType'
INDEX_TYPE = 'indexType'
CRITICAL = 'critical'
ERROR = 'error'
......@@ -89,6 +95,10 @@ MSGPACK = 'msgpack'
PACK = 'pack'
FLOAT_32 = 'Float32Array'
UINT_16 = 'Uint16Array'
UINT_32 = 'Uint32Array'
INFLUENCES_PER_VERTEX = 'influencesPerVertex'
EXPORT_OPTIONS = {
......@@ -98,6 +108,7 @@ EXPORT_OPTIONS = {
UVS: True,
APPLY_MODIFIERS: True,
COLORS: False,
INDEX_TYPE: UINT_16,
MATERIALS: False,
FACE_MATERIALS: False,
SCALE: 1,
......@@ -187,8 +198,6 @@ NORMAL = 'normal'
ITEM_SIZE = 'itemSize'
ARRAY = 'array'
FLOAT_32 = 'Float32Array'
VISIBLE = 'visible'
CAST_SHADOW = 'castShadow'
RECEIVE_SHADOW = 'receiveShadow'
......
......@@ -241,7 +241,8 @@ class Geometry(base_classes.BaseNode):
constants.NORMALS, constants.BONES,
constants.SKIN_WEIGHTS,
constants.SKIN_INDICES, constants.NAME,
constants.INFLUENCES_PER_VERTEX]
constants.INFLUENCES_PER_VERTEX,
constants.INDEX]
data = {}
anim_components = [constants.MORPH_TARGETS, constants.ANIMATION]
......@@ -285,6 +286,10 @@ class Geometry(base_classes.BaseNode):
data[constants.METADATA].update(self.metadata)
draw_calls = self.get(constants.DRAW_CALLS)
if draw_calls is not None:
data[constants.DRAW_CALLS] = draw_calls
return data
def _buffer_geometry_metadata(self, metadata):
......@@ -345,12 +350,15 @@ class Geometry(base_classes.BaseNode):
constants.METADATA: self.metadata
})
else:
geometry_data = data
if self.options.get(constants.EMBED_GEOMETRY, True):
data[constants.DATA] = {
constants.ATTRIBUTES: component_data
}
else:
data[constants.ATTRIBUTES] = component_data
data[constants.DATA] = geometry_data = {}
geometry_data[constants.ATTRIBUTES] = component_data
draw_calls = self.get(constants.DRAW_CALLS)
if draw_calls is not None:
geometry_data[constants.DRAW_CALLS] = draw_calls
data[constants.METADATA] = self.metadata
data[constants.NAME] = self[constants.NAME]
......@@ -363,6 +371,7 @@ class Geometry(base_classes.BaseNode):
options_vertices = self.options.get(constants.VERTICES)
option_normals = self.options.get(constants.NORMALS)
option_uvs = self.options.get(constants.UVS)
option_index_type = self.options.get(constants.INDEX_TYPE)
pos_tuple = (constants.POSITION, options_vertices,
api.mesh.buffer_position, 3)
......@@ -388,6 +397,88 @@ class Geometry(base_classes.BaseNode):
constants.ARRAY: array
}
if option_index_type != constants.NONE:
assert(not (self.get(constants.INDEX) or
self.get(constants.DRAW_CALLS)))
indices_per_face = 3
index_threshold = 0xffff - indices_per_face
if option_index_type == constants.UINT_32:
index_threshold = 0x7fffffff - indices_per_face
attrib_data_in, attrib_data_out, attrib_keys = [], [], []
i = 0
for key, entry in self[constants.ATTRIBUTES].items():
item_size = entry[constants.ITEM_SIZE]
attrib_keys.append(key)
attrib_data_in.append( (entry[constants.ARRAY], item_size) )
attrib_data_out.append( ([], i, i + item_size) )
i += item_size
index_data, draw_calls = [], []
indexed, flush_req, base_vertex = {}, False, 0
assert(len(attrib_data_in) > 0)
array, item_size = attrib_data_in[0]
i, n = 0, len(array) / item_size
while i < n:
vertex_data = ()
for array, item_size in attrib_data_in:
vertex_data += tuple(
array[i * item_size : (i + 1) * item_size])
vertex_index = indexed.get(vertex_data)
if vertex_index is None:
vertex_index = len(indexed)
flush_req = vertex_index >= index_threshold
indexed[vertex_data] = vertex_index
for array, i_from, i_to in attrib_data_out:
array.extend(vertex_data[i_from : i_to])
index_data.append(vertex_index)
i += 1
if i == n:
flush_req = len(draw_calls) > 0
assert(i % indices_per_face == 0)
if flush_req and i % indices_per_face == 0:
start, count = 0, len(index_data)
if draw_calls:
prev = draw_calls[-1]
start = prev[constants.DC_START] + prev[constants.DC_COUNT]
count -= start
draw_calls.append({
constants.DC_START: start,
constants.DC_COUNT: count,
constants.DC_INDEX: base_vertex
})
base_vertex += len(indexed)
indexed.clear()
flush_req = False
for i, key in enumerate(attrib_keys):
array = attrib_data_out[i][0]
self[constants.ATTRIBUTES][key][constants.ARRAY] = array
self[constants.ATTRIBUTES][constants.INDEX] = {
constants.ITEM_SIZE: 3,
constants.TYPE: option_index_type,
constants.ARRAY: index_data
}
if (draw_calls):
logger.info("draw_calls = %s", repr(draw_calls))
self[constants.DRAW_CALLS] = draw_calls
def _parse_geometry(self):
"""Parse the geometry to Three.Geometry specs"""
if self.options.get(constants.VERTICES):
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册