glTF addon: updates from upstream
* invalidate cache for multiple exports * exporter: support KHR_lights_punctual * fixed lights * disable export all layers * fixed texture slot images stalling export * option to enable exporting more than 4 influences from upsteam commit 26699c476211add92d13df0a284b8df2f08acb3e to upstream commit 7a8f733fc446cfb3880a8c1658bccf94bcfd456c
This commit is contained in:
parent
a12a93cbdf
commit
74dbec774e
|
@ -18,6 +18,7 @@
|
|||
|
||||
import os
|
||||
import bpy
|
||||
import datetime
|
||||
from bpy_extras.io_utils import ImportHelper, ExportHelper
|
||||
from bpy.types import Operator, AddonPreferences
|
||||
|
||||
|
@ -158,11 +159,11 @@ class ExportGLTF2_Base:
|
|||
default=False
|
||||
)
|
||||
|
||||
export_layers: BoolProperty(
|
||||
name='Export all layers',
|
||||
description='',
|
||||
default=True
|
||||
)
|
||||
# export_layers: BoolProperty(
|
||||
# name='Export all layers',
|
||||
# description='',
|
||||
# default=True
|
||||
# )
|
||||
|
||||
export_extras: BoolProperty(
|
||||
name='Export extras',
|
||||
|
@ -232,6 +233,12 @@ class ExportGLTF2_Base:
|
|||
default=False
|
||||
)
|
||||
|
||||
export_all_influences: BoolProperty(
|
||||
name='Export all bone influences',
|
||||
description='Export more than four joint vertex influences',
|
||||
default=False
|
||||
)
|
||||
|
||||
export_morph: BoolProperty(
|
||||
name='Export morphing',
|
||||
description='',
|
||||
|
@ -307,6 +314,8 @@ class ExportGLTF2_Base:
|
|||
# All custom export settings are stored in this container.
|
||||
export_settings = {}
|
||||
|
||||
export_settings['timestamp'] = datetime.datetime.now()
|
||||
|
||||
export_settings['gltf_filepath'] = bpy.path.ensure_ext(self.filepath, self.filename_ext)
|
||||
export_settings['gltf_filedirectory'] = os.path.dirname(export_settings['gltf_filepath']) + '/'
|
||||
|
||||
|
@ -328,7 +337,7 @@ class ExportGLTF2_Base:
|
|||
else:
|
||||
export_settings['gltf_camera_infinite'] = False
|
||||
export_settings['gltf_selected'] = self.export_selected
|
||||
export_settings['gltf_layers'] = self.export_layers
|
||||
export_settings['gltf_layers'] = True #self.export_layers
|
||||
export_settings['gltf_extras'] = self.export_extras
|
||||
export_settings['gltf_yup'] = self.export_yup
|
||||
export_settings['gltf_apply'] = self.export_apply
|
||||
|
@ -346,8 +355,10 @@ class ExportGLTF2_Base:
|
|||
export_settings['gltf_skins'] = self.export_skins
|
||||
if self.export_skins:
|
||||
export_settings['gltf_bake_skins'] = self.export_bake_skins
|
||||
export_settings['gltf_all_vertex_influences'] = self.export_all_influences
|
||||
else:
|
||||
export_settings['gltf_bake_skins'] = False
|
||||
export_settings['gltf_all_vertex_influences'] = False
|
||||
export_settings['gltf_frame_step'] = self.export_frame_step
|
||||
export_settings['gltf_morph'] = self.export_morph
|
||||
if self.export_morph:
|
||||
|
@ -384,7 +395,7 @@ class ExportGLTF2_Base:
|
|||
col = layout.box().column()
|
||||
col.label(text='Nodes:') # , icon='OOPS')
|
||||
col.prop(self, 'export_selected')
|
||||
col.prop(self, 'export_layers')
|
||||
#col.prop(self, 'export_layers')
|
||||
col.prop(self, 'export_extras')
|
||||
col.prop(self, 'export_yup')
|
||||
|
||||
|
@ -413,6 +424,10 @@ class ExportGLTF2_Base:
|
|||
col.prop(self, 'export_materials')
|
||||
col.prop(self, 'export_texture_transform')
|
||||
|
||||
col = layout.box().column()
|
||||
col.label(text='Lights:') # , icon='LIGHT_DATA')
|
||||
col.prop(self, 'export_lights')
|
||||
|
||||
col = layout.box().column()
|
||||
col.label(text='Animation:') # , icon='OUTLINER_DATA_POSE')
|
||||
col.prop(self, 'export_animations')
|
||||
|
@ -426,19 +441,13 @@ class ExportGLTF2_Base:
|
|||
col.prop(self, 'export_skins')
|
||||
if self.export_skins:
|
||||
col.prop(self, 'export_bake_skins')
|
||||
col.prop(self, 'export_all_influences')
|
||||
col.prop(self, 'export_morph')
|
||||
if self.export_morph:
|
||||
col.prop(self, 'export_morph_normal')
|
||||
if self.export_morph_normal:
|
||||
col.prop(self, 'export_morph_tangent')
|
||||
|
||||
addon_prefs = context.user_preferences.addons[__name__].preferences
|
||||
if addon_prefs.experimental:
|
||||
col = layout.box().column()
|
||||
col.label(text='Experimental:') # , icon='RADIO')
|
||||
col.prop(self, 'export_lights')
|
||||
col.prop(self, 'export_displacement')
|
||||
|
||||
row = layout.row()
|
||||
row.operator(
|
||||
GLTF2ExportSettings.bl_idname,
|
||||
|
@ -474,16 +483,6 @@ def menu_func_export(self, context):
|
|||
self.layout.operator(ExportGLTF2_GLB.bl_idname, text='Binary glTF 2.0 (.glb)')
|
||||
|
||||
|
||||
class ExportGLTF2_AddonPreferences(AddonPreferences):
|
||||
bl_idname = __name__
|
||||
|
||||
experimental: BoolProperty(name='Enable experimental glTF export settings', default=False)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "experimental")
|
||||
|
||||
|
||||
class ImportglTF2(Operator, ImportHelper):
|
||||
bl_idname = 'import_scene.gltf'
|
||||
bl_label = "glTF 2.0 (.gltf/.glb)"
|
||||
|
@ -549,7 +548,6 @@ classes = (
|
|||
GLTF2ExportSettings,
|
||||
ExportGLTF2_GLTF,
|
||||
ExportGLTF2_GLB,
|
||||
ExportGLTF2_AddonPreferences,
|
||||
ImportglTF2
|
||||
)
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ def __get_image_data(sockets_or_slots):
|
|||
# For shared ressources, such as images, we just store the portion of data that is needed in the glTF property
|
||||
# in a helper class. During generation of the glTF in the exporter these will then be combined to actual binary
|
||||
# ressources.
|
||||
def split_pixels_by_channels(image: bpy.types.Image) -> typing.Iterable[typing.Iterable[float]]:
|
||||
def split_pixels_by_channels(image: bpy.types.Image) -> typing.List[typing.List[float]]:
|
||||
pixels = np.array(image.pixels)
|
||||
pixels = pixels.reshape((pixels.shape[0] // image.channels, image.channels))
|
||||
channels = np.split(pixels, pixels.shape[1], axis=1)
|
||||
|
@ -139,7 +139,7 @@ def __get_image_data(sockets_or_slots):
|
|||
return image
|
||||
elif __is_slot(sockets_or_slots):
|
||||
texture = __get_tex_from_slot(sockets_or_slots[0])
|
||||
pixels = texture.image.pixels
|
||||
pixels = split_pixels_by_channels(texture.image)
|
||||
|
||||
image_data = gltf2_io_image_data.ImageData(
|
||||
texture.name,
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
# Copyright 2018 The glTF-Blender-IO authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import bpy
|
||||
from typing import Optional, List, Any
|
||||
|
||||
from io_scene_gltf2.blender.exp.gltf2_blender_gather_cache import cached
|
||||
|
||||
from io_scene_gltf2.io.com import gltf2_io_lights_punctual
|
||||
from io_scene_gltf2.io.com import gltf2_io_debug
|
||||
|
||||
|
||||
def gather_light_spot(blender_lamp, export_settings) -> Optional[gltf2_io_lights_punctual.LightSpot]:
|
||||
|
||||
if not __filter_light_spot(blender_lamp, export_settings):
|
||||
return None
|
||||
|
||||
spot = gltf2_io_lights_punctual.LightSpot(
|
||||
inner_cone_angle=__gather_inner_cone_angle(blender_lamp, export_settings),
|
||||
outer_cone_angle=__gather_outer_cone_angle(blender_lamp, export_settings)
|
||||
)
|
||||
return spot
|
||||
|
||||
|
||||
def __filter_light_spot(blender_lamp, _) -> bool:
|
||||
if blender_lamp.type != "SPOT":
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def __gather_inner_cone_angle(blender_lamp, _) -> Optional[float]:
|
||||
angle = blender_lamp.spot_size * 0.5
|
||||
return angle - angle * blender_lamp.spot_blend
|
||||
|
||||
|
||||
def __gather_outer_cone_angle(blender_lamp, _) -> Optional[float]:
|
||||
return blender_lamp.spot_size * 0.5
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
# Copyright 2018 The glTF-Blender-IO authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import bpy
|
||||
import math
|
||||
from typing import Optional, List, Dict, Any
|
||||
|
||||
from io_scene_gltf2.blender.exp.gltf2_blender_gather_cache import cached
|
||||
|
||||
from io_scene_gltf2.io.com import gltf2_io_lights_punctual
|
||||
from io_scene_gltf2.io.com import gltf2_io_debug
|
||||
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_gather_light_spots
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_search_node_tree
|
||||
|
||||
@cached
|
||||
def gather_lights_punctual(blender_lamp, export_settings) -> Optional[Dict[str, Any]]:
|
||||
if not __filter_lights_punctual(blender_lamp, export_settings):
|
||||
return None
|
||||
|
||||
light = gltf2_io_lights_punctual.Light(
|
||||
color=__gather_color(blender_lamp, export_settings),
|
||||
intensity=__gather_intensity(blender_lamp, export_settings),
|
||||
spot=__gather_spot(blender_lamp, export_settings),
|
||||
type=__gather_type(blender_lamp, export_settings),
|
||||
range=__gather_range(blender_lamp, export_settings),
|
||||
name=__gather_name(blender_lamp, export_settings),
|
||||
extensions=__gather_extensions(blender_lamp, export_settings),
|
||||
extras=__gather_extras(blender_lamp, export_settings)
|
||||
)
|
||||
|
||||
return light.to_dict()
|
||||
|
||||
|
||||
def __filter_lights_punctual(blender_lamp, export_settings) -> bool:
|
||||
if blender_lamp.type in ["HEMI", "AREA"]:
|
||||
gltf2_io_debug.print_console("WARNING", "Unsupported light source {}".format(blender_lamp.type))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def __gather_color(blender_lamp, export_settings) -> Optional[List[float]]:
|
||||
emission_node = __get_cycles_emission_node(blender_lamp)
|
||||
if emission_node is not None:
|
||||
return emission_node.inputs["Color"].default_value
|
||||
|
||||
return list(blender_lamp.color)
|
||||
|
||||
|
||||
def __gather_intensity(blender_lamp, _) -> Optional[float]:
|
||||
emission_node = __get_cycles_emission_node(blender_lamp)
|
||||
if emission_node is not None:
|
||||
if blender_lamp.type != 'SUN':
|
||||
# When using cycles, the strength should be influenced by a LightFalloff node
|
||||
result = gltf2_blender_search_node_tree.from_socket(
|
||||
emission_node.get("Strength"),
|
||||
gltf2_blender_search_node_tree.FilterByType(bpy.types.ShaderNodeLightFalloff)
|
||||
)
|
||||
if result:
|
||||
quadratic_falloff_node = result[0].shader_node
|
||||
emission_strength = quadratic_falloff_node.inputs["Strength"].default_value / (math.pi * 4.0)
|
||||
else:
|
||||
gltf2_io_debug.print_console('WARNING',
|
||||
'No quadratic light falloff node attached to emission strength property')
|
||||
emission_strength = blender_lamp.energy
|
||||
else:
|
||||
emission_strength = emission_node.inputs["Strength"].default_value
|
||||
return emission_strength
|
||||
|
||||
return blender_lamp.energy
|
||||
|
||||
|
||||
def __gather_spot(blender_lamp, export_settings) -> Optional[gltf2_io_lights_punctual.LightSpot]:
|
||||
if blender_lamp.type == "SPOT":
|
||||
return gltf2_blender_gather_light_spots.gather_light_spot(blender_lamp, export_settings)
|
||||
return None
|
||||
|
||||
|
||||
def __gather_type(blender_lamp, _) -> str:
|
||||
return {
|
||||
"POINT": "point",
|
||||
"SUN": "directional",
|
||||
"SPOT": "spot"
|
||||
}[blender_lamp.type]
|
||||
|
||||
|
||||
def __gather_range(blender_lamp, export_settings) -> Optional[float]:
|
||||
# TODO: calculate range from
|
||||
# https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual#range-property
|
||||
return None
|
||||
|
||||
|
||||
def __gather_name(blender_lamp, export_settings) -> Optional[str]:
|
||||
return blender_lamp.name
|
||||
|
||||
|
||||
def __gather_extensions(blender_lamp, export_settings) -> Optional[dict]:
|
||||
return None
|
||||
|
||||
|
||||
def __gather_extras(blender_lamp, export_settings) -> Optional[Any]:
|
||||
return None
|
||||
|
||||
|
||||
def __get_cycles_emission_node(blender_lamp) -> Optional[bpy.types.ShaderNodeEmission]:
|
||||
if blender_lamp.use_nodes and blender_lamp.node_tree:
|
||||
for currentNode in blender_lamp.node_tree.nodes:
|
||||
if isinstance(currentNode, bpy.types.ShaderNodeOutputLamp):
|
||||
if not currentNode.is_active_output:
|
||||
continue
|
||||
result = gltf2_blender_search_node_tree.from_socket(
|
||||
currentNode.inputs.get("Surface"),
|
||||
gltf2_blender_search_node_tree.FilterByType(bpy.types.ShaderNodeEmission)
|
||||
)
|
||||
if not result:
|
||||
continue
|
||||
return result[0].shader_node
|
||||
return None
|
||||
|
|
@ -12,6 +12,8 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import bpy
|
||||
|
||||
from . import gltf2_blender_export_keys
|
||||
from io_scene_gltf2.blender.exp.gltf2_blender_gather_cache import cached
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_gather_skins
|
||||
|
@ -19,7 +21,9 @@ from io_scene_gltf2.blender.exp import gltf2_blender_gather_cameras
|
|||
from io_scene_gltf2.blender.exp import gltf2_blender_gather_mesh
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_gather_joints
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_extract
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_gather_lights
|
||||
from io_scene_gltf2.io.com import gltf2_io
|
||||
from io_scene_gltf2.io.com import gltf2_io_extensions
|
||||
|
||||
|
||||
@cached
|
||||
|
@ -87,7 +91,28 @@ def __gather_children(blender_object, export_settings):
|
|||
|
||||
|
||||
def __gather_extensions(blender_object, export_settings):
|
||||
return None
|
||||
extensions = {}
|
||||
|
||||
if export_settings["gltf_lights"] and (blender_object.type == "LAMP" or blender_object.type == "LIGHT"):
|
||||
blender_lamp = blender_object.data
|
||||
light = gltf2_blender_gather_lights.gather_lights_punctual(
|
||||
blender_lamp,
|
||||
export_settings
|
||||
)
|
||||
if light is not None:
|
||||
light_extension = gltf2_io_extensions.ChildOfRootExtension(
|
||||
name="KHR_lights_punctual",
|
||||
path=["lights"],
|
||||
extension=light
|
||||
)
|
||||
extensions["KHR_lights_punctual"] = gltf2_io_extensions.Extension(
|
||||
name="KHR_lights_punctual",
|
||||
extension={
|
||||
"light": light_extension
|
||||
}
|
||||
)
|
||||
|
||||
return extensions if extensions else None
|
||||
|
||||
|
||||
def __gather_extras(blender_object, export_settings):
|
||||
|
|
|
@ -168,8 +168,8 @@ def __gather_skins(blender_primitive, export_settings):
|
|||
if bone_index >= 4:
|
||||
gltf2_io_debug.print_console("WARNING", "There are more than 4 joint vertex influences."
|
||||
"Consider to apply blenders Limit Total function.")
|
||||
# TODO: add option to stop after 4
|
||||
# break
|
||||
if not export_settings['gltf_all_vertex_influences']:
|
||||
break
|
||||
|
||||
# joints
|
||||
internal_joint = blender_primitive["attributes"][joint_id]
|
||||
|
|
|
@ -12,7 +12,10 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from typing import Optional, List, Dict
|
||||
|
||||
from io_scene_gltf2.io.com import gltf2_io
|
||||
from io_scene_gltf2.io.com import gltf2_io_extensions
|
||||
from io_scene_gltf2.io.exp import gltf2_io_binary_data
|
||||
from io_scene_gltf2.io.exp import gltf2_io_image_data
|
||||
from io_scene_gltf2.io.exp import gltf2_io_buffer
|
||||
|
@ -208,6 +211,20 @@ class GlTF2Exporter:
|
|||
# TODO: allow embedding of images (base64)
|
||||
return image.name + ".png"
|
||||
|
||||
@classmethod
|
||||
def __get_key_path(cls, d: dict, keypath: List[str], default=[]):
|
||||
"""Create if necessary and get the element at key path from a dict"""
|
||||
key = keypath.pop(0)
|
||||
|
||||
if len(keypath) == 0:
|
||||
v = d.get(key, default)
|
||||
d[key] = v
|
||||
return v
|
||||
|
||||
d_key = d.get(key, {})
|
||||
d[key] = d_key
|
||||
return cls.__get_key_path(d[key], keypath, default)
|
||||
|
||||
def __traverse(self, node):
|
||||
"""
|
||||
Recursively traverse a scene graph consisting of gltf compatible elements.
|
||||
|
@ -215,21 +232,21 @@ class GlTF2Exporter:
|
|||
The tree is traversed downwards until a primitive is reached. Then any ChildOfRoot property
|
||||
is stored in the according list in the glTF and replaced with a index reference in the upper level.
|
||||
"""
|
||||
def traverse_all_members(node):
|
||||
def __traverse_property(node):
|
||||
for member_name in [a for a in dir(node) if not a.startswith('__') and not callable(getattr(node, a))]:
|
||||
new_value = self.__traverse(getattr(node, member_name))
|
||||
setattr(node, member_name, new_value) # usually this is the same as before
|
||||
|
||||
# TODO: maybe with extensions hooks we can find a more elegant solution
|
||||
if member_name == "extensions" and new_value is not None:
|
||||
for extension_name in new_value.keys():
|
||||
self.__append_unique_and_get_index(self.__gltf.extensions_used, extension_name)
|
||||
self.__append_unique_and_get_index(self.__gltf.extensions_required, extension_name)
|
||||
# # TODO: maybe with extensions hooks we can find a more elegant solution
|
||||
# if member_name == "extensions" and new_value is not None:
|
||||
# for extension_name in new_value.keys():
|
||||
# self.__append_unique_and_get_index(self.__gltf.extensions_used, extension_name)
|
||||
# self.__append_unique_and_get_index(self.__gltf.extensions_required, extension_name)
|
||||
return node
|
||||
|
||||
# traverse nodes of a child of root property type and add them to the glTF root
|
||||
if type(node) in self.__childOfRootPropertyTypeLookup:
|
||||
node = traverse_all_members(node)
|
||||
node = __traverse_property(node)
|
||||
idx = self.__to_reference(node)
|
||||
# child of root properties are only present at root level --> replace with index in upper level
|
||||
return idx
|
||||
|
@ -247,7 +264,7 @@ class GlTF2Exporter:
|
|||
|
||||
# traverse into any other property
|
||||
if type(node) in self.__propertyTypeLookup:
|
||||
return traverse_all_members(node)
|
||||
return __traverse_property(node)
|
||||
|
||||
# binary data needs to be moved to a buffer and referenced with a buffer view
|
||||
if isinstance(node, gltf2_io_binary_data.BinaryData):
|
||||
|
@ -258,6 +275,21 @@ class GlTF2Exporter:
|
|||
if isinstance(node, gltf2_io_image_data.ImageData):
|
||||
return self.__add_image(node)
|
||||
|
||||
# extensions
|
||||
if isinstance(node, gltf2_io_extensions.Extension):
|
||||
extension = self.__traverse(node.extension)
|
||||
self.__append_unique_and_get_index(self.__gltf.extensions_used, node.name)
|
||||
self.__append_unique_and_get_index(self.__gltf.extensions_required, node.name)
|
||||
|
||||
# extensions that lie in the root of the glTF.
|
||||
# They need to be converted to a reference at place of occurrence
|
||||
if isinstance(node, gltf2_io_extensions.ChildOfRootExtension):
|
||||
root_extension_list = self.__get_key_path(self.__gltf.extensions, [node.name] + node.path)
|
||||
idx = self.__append_unique_and_get_index(root_extension_list, extension)
|
||||
return idx
|
||||
|
||||
return extension
|
||||
|
||||
# do nothing for any type that does not match a glTF schema (primitives)
|
||||
return node
|
||||
|
||||
|
|
|
@ -95,3 +95,4 @@ def from_socket(start_socket: bpy.types.NodeSocket,
|
|||
|
||||
return __search_from_socket(start_socket, shader_node_filter, [])
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# Copyright 2018 The glTF-Blender-IO authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from typing import List, Dict, Any
|
||||
|
||||
|
||||
class Extension:
|
||||
"""Container for extensions. Allows to specify requiredness"""
|
||||
def __init__(self, name: str, extension: Dict[str, Any], required: bool = True):
|
||||
self.name = name
|
||||
self.extension = extension
|
||||
self.required = required
|
||||
|
||||
|
||||
class ChildOfRootExtension(Extension):
|
||||
"""Container object for extensions that should be appended to the root extensions"""
|
||||
def __init__(self, path: List[str], name: str, extension: Dict[str, Any], required: bool = True):
|
||||
"""
|
||||
Wrap a local extension entity into an object that will later be inserted into a root extension and converted
|
||||
to a reference.
|
||||
:param path: The path of the extension object in the root extension. E.g. ['lights'] for
|
||||
KHR_lights_punctual. Must be a path to a list in the extensions dict.
|
||||
:param extension: The data that should be placed into the extension list
|
||||
"""
|
||||
self.path = path
|
||||
super().__init__(name, extension, required)
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
# Copyright 2018 The glTF-Blender-IO authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from io_scene_gltf2.io.com.gltf2_io import *
|
||||
|
||||
|
||||
class LightSpot:
|
||||
"""light/spot"""
|
||||
def __init__(self, inner_cone_angle, outer_cone_angle):
|
||||
self.inner_cone_angle = inner_cone_angle
|
||||
self.outer_cone_angle = outer_cone_angle
|
||||
|
||||
@staticmethod
|
||||
def from_dict(obj):
|
||||
assert isinstance(obj, dict)
|
||||
inner_cone_angle = from_union([from_float, from_none], obj.get("innerConeAngle"))
|
||||
outer_cone_angle = from_union([from_float, from_none], obj.get("outerConeAngle"))
|
||||
return LightSpot(inner_cone_angle, outer_cone_angle)
|
||||
|
||||
def to_dict(self):
|
||||
result = {}
|
||||
result["innerConeAngle"] = from_union([from_float, from_none], self.inner_cone_angle)
|
||||
result["outerConeAngle"] = from_union([from_float, from_none], self.outer_cone_angle)
|
||||
return result
|
||||
|
||||
|
||||
class Light:
|
||||
"""defines a set of lights for use with glTF 2.0. Lights define light sources within a scene"""
|
||||
def __init__(self, color, intensity, spot, type, range, name, extensions, extras):
|
||||
self.color = color
|
||||
self.intensity = intensity
|
||||
self.spot = spot
|
||||
self.type = type
|
||||
self.range = range
|
||||
self.name = name
|
||||
self.extensions = extensions
|
||||
self.extras = extras
|
||||
|
||||
@staticmethod
|
||||
def from_dict(obj):
|
||||
assert isinstance(obj, dict)
|
||||
color = from_union([lambda x: from_list(from_float, x), from_none], obj.get("color"))
|
||||
intensity = from_union([from_float, from_none], obj.get("intensity"))
|
||||
spot = LightSpot.from_dict(obj.get("spot"))
|
||||
type = from_str(obj.get("type"))
|
||||
range = from_union([from_float, from_none], obj.get("range"))
|
||||
name = from_union([from_str, from_none], obj.get("name"))
|
||||
extensions = from_union([lambda x: from_dict(lambda x: from_dict(lambda x: x, x), x), from_none],
|
||||
obj.get("extensions"))
|
||||
extras = obj.get("extras")
|
||||
return Light(color, intensity, spot, type, range, name, extensions, extras)
|
||||
|
||||
def to_dict(self):
|
||||
result = {}
|
||||
result["color"] = from_union([lambda x: from_list(to_float, x), from_none], self.color)
|
||||
result["intensity"] = from_union([from_float, from_none], self.intensity)
|
||||
result["spot"] = from_union([lambda x: to_class(LightSpot, x), from_none], self.spot)
|
||||
result["type"] = from_str(self.type)
|
||||
result["range"] = from_union([from_float, from_none], self.range)
|
||||
result["name"] = from_union([from_str, from_none], self.name)
|
||||
result["extensions"] = from_union([lambda x: from_dict(lambda x: from_dict(lambda x: x, x), x), from_none],
|
||||
self.extensions)
|
||||
result["extras"] = self.extras
|
||||
return result
|
||||
|
Loading…
Reference in New Issue