glTF exporter: Options tweaks, image merging fixes

This commit is contained in:
Julien Duroure 2018-12-05 21:41:39 +01:00
parent 0c494907cf
commit 3087c4e458
6 changed files with 59 additions and 24 deletions

View File

@ -74,11 +74,18 @@ class ExportGLTF2_Base:
export_format: EnumProperty(
name='Format',
items=(('GLB', 'glb', 'Exports a single file, with all data packed in binary form. Most efficient and portable, but more difficult to edit later'),
('GLTF_EMBEDDED', 'glTF embedded)', 'Exports a single file, with all data packed in JSON. Less efficient than binary, but easier to edit later'),
('GLTF', 'glTF', 'Exports multiple files, with separate JSON (.gltf), binary (.bin), and texture data. Easiest to edit later')),
description='Output format and embedding options. Binary is most efficient, but JSON (embedded or separate) may be easier to edit later',
default='GLTF'
items=(('GLB', 'glTF Binary (.glb)',
'Exports a single file, with all data packed in binary form. '
'Most efficient and portable, but more difficult to edit later'),
('GLTF_EMBEDDED', 'glTF Embedded (.gltf)',
'Exports a single file, with all data packed in JSON. '
'Less efficient than binary, but easier to edit later'),
('GLTF_SEPARATE', 'glTF Separate (.gltf + .bin + textures)',
'Exports multiple files, with separate JSON, binary and texture data. '
'Easiest to edit later')),
description='Output format and embedding options. Binary is most efficient, '
'but JSON (embedded or separate) may be easier to edit later.',
default='GLB'
)
export_copyright: StringProperty(

View File

@ -18,6 +18,8 @@ from io_scene_gltf2.io.com import gltf2_io
from io_scene_gltf2.blender.exp import gltf2_blender_gather_nodes
from io_scene_gltf2.blender.exp import gltf2_blender_gather_animations
from io_scene_gltf2.blender.exp.gltf2_blender_gather_cache import cached
from io_scene_gltf2.blender.exp import gltf2_blender_generate_extras
from io_scene_gltf2.blender.exp import gltf2_blender_export_keys
def gather_gltf2(export_settings):
@ -39,7 +41,7 @@ def gather_gltf2(export_settings):
def __gather_scene(blender_scene, export_settings):
scene = gltf2_io.Scene(
extensions=None,
extras=None,
extras=__gather_extras(blender_scene, export_settings),
name=blender_scene.name,
nodes=[]
)
@ -59,3 +61,9 @@ def __gather_animations(blender_scene, export_settings):
animations += gltf2_blender_gather_animations.gather_animations(blender_object, export_settings)
return animations
def __gather_extras(blender_object, export_settings):
if export_settings[gltf2_blender_export_keys.EXTRAS]:
return gltf2_blender_generate_extras.generate_extras(blender_object)
return None

View File

@ -48,7 +48,7 @@ def __filter_image(sockets_or_slots, export_settings):
def __gather_buffer_view(sockets_or_slots, export_settings):
if export_settings[gltf2_blender_export_keys.FORMAT] != 'GLTF':
if export_settings[gltf2_blender_export_keys.FORMAT] != 'GLTF_SEPARATE':
image = __get_image_data(sockets_or_slots)
return gltf2_io_binary_data.BinaryData(
data=image.to_image_data(__gather_mime_type(sockets_or_slots, export_settings)))
@ -79,7 +79,7 @@ def __gather_name(sockets_or_slots, export_settings):
def __gather_uri(sockets_or_slots, export_settings):
if export_settings[gltf2_blender_export_keys.FORMAT] == 'GLTF':
if export_settings[gltf2_blender_export_keys.FORMAT] == 'GLTF_SEPARATE':
# as usual we just store the data in place instead of already resolving the references
return __get_image_data(sockets_or_slots)
return None
@ -121,6 +121,7 @@ def __get_image_data(sockets_or_slots):
pixels = [split_pixels_by_channels(result.shader_node.image)[channel]]
else:
pixels = split_pixels_by_channels(result.shader_node.image)
channel = 0
file_name = os.path.splitext(result.shader_node.image.name)[0]
@ -128,12 +129,13 @@ def __get_image_data(sockets_or_slots):
file_name,
result.shader_node.image.size[0],
result.shader_node.image.size[1],
channel,
pixels)
if image is None:
image = image_data
else:
image.add_to_image(image_data)
image.add_to_image(channel, image_data)
return image
elif __is_slot(sockets_or_slots):
@ -144,6 +146,7 @@ def __get_image_data(sockets_or_slots):
texture.name,
texture.image.size[0],
texture.image.size[1],
0,
pixels)
return image_data
else:

View File

@ -96,7 +96,7 @@ def __gather_double_sided(blender_material, export_settings):
def __gather_emmissive_factor(blender_material, export_settings):
emissive_socket = gltf2_blender_get.get_socket_or_texture_slot(blender_material, "Emissive")
if isinstance(emissive_socket, bpy.types.NodeSocket):
if isinstance(emissive_socket, bpy.types.NodeSocket) and not emissive_socket.is_linked:
return list(emissive_socket.default_value)[0:3]
return None

View File

@ -46,7 +46,7 @@ def __gather_base_color_factor(blender_material, export_settings):
base_color_socket = gltf2_blender_get.get_socket_or_texture_slot(blender_material, "Base Color")
if base_color_socket is None:
base_color_socket = gltf2_blender_get.get_socket_or_texture_slot(blender_material, "BaseColor")
if isinstance(base_color_socket, bpy.types.NodeSocket):
if isinstance(base_color_socket, bpy.types.NodeSocket) and not base_color_socket.is_linked:
return list(base_color_socket.default_value)
return None
@ -67,7 +67,7 @@ def __gather_extras(blender_material, export_settings):
def __gather_metallic_factor(blender_material, export_settings):
metallic_socket = gltf2_blender_get.get_socket_or_texture_slot(blender_material, "Metallic")
if isinstance(metallic_socket, bpy.types.NodeSocket):
if isinstance(metallic_socket, bpy.types.NodeSocket) and not metallic_socket.is_linked:
return metallic_socket.default_value
return None
@ -87,7 +87,7 @@ def __gather_metallic_roughness_texture(blender_material, export_settings):
def __gather_roughness_factor(blender_material, export_settings):
roughness_socket = gltf2_blender_get.get_socket_or_texture_slot(blender_material, "Roughness")
if isinstance(roughness_socket, bpy.types.NodeSocket):
if isinstance(roughness_socket, bpy.types.NodeSocket) and not roughness_socket.is_linked:
return roughness_socket.default_value
return None

View File

@ -23,21 +23,38 @@ class ImageData:
# FUTURE_WORK: as a method to allow the node graph to be better supported, we could model some of
# the node graph elements with numpy functions
def __init__(self, name: str, width: int, height: int, channels: typing.Optional[typing.List[np.ndarray]] = []):
def __init__(self, name: str, width: int, height: int, offset: int, channels: typing.Optional[typing.List[np.ndarray]] = []):
if width <= 0 or height <= 0:
raise ValueError("Image data can not have zero width or height")
if offset + len(channels) > 4:
raise ValueError("Image data can not have more than 4 channels")
self.channels = []
for fill in range(offset):
# Fill before.
self.channels.append(np.ones_like(channels[0]))
self.channels += channels
total_channels = len(self.channels)
for fill in range(total_channels, 4):
# Fill after.
self.channels.append(np.ones_like(channels[0]))
self.name = name
self.channels = channels
self.width = width
self.height = height
def add_to_image(self, image_data):
def add_to_image(self, channel, image_data):
if self.width != image_data.width or self.height != image_data.height:
raise ValueError("Image dimensions do not match")
if len(self.channels) + len(image_data.channels) > 4:
raise ValueError("Can't append image: channels full")
if channel < 0 or channel > 3:
raise ValueError("Can't append image: channels out of bounds")
if len(image_data.channels) != 4:
raise ValueError("Can't append image: incomplete image")
self.name += image_data.name
self.channels += image_data.channels
# Replace channel.
self.channels[channel] = image_data.channels[channel]
@property
def r(self):
@ -73,13 +90,13 @@ class ImageData:
# if there is no data, create a single pixel image
if not channels:
channels = np.zeros((1, 1))
channels = np.ones((1, 1))
# fill all channels of the png
for _ in range(4 - len(channels)):
channels.append(np.ones_like(channels[0]))
# fill all channels of the png
for _ in range(4 - len(channels)):
channels.append(np.ones_like(channels[0]))
image = np.concatenate(self.channels, axis=1)
image = np.concatenate(channels, axis=1)
image = image.flatten()
image = (image * 255.0).astype(np.uint8)
buf = image.tobytes()