Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for importing Hubs components from glTF files #63

Merged
merged 133 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
74c7171
test support for importing some hubs components
Exairnous Nov 28, 2021
109fef0
More support for Hubs components. Everything works on object compone…
Exairnous Nov 29, 2021
cbeda4b
Fix enum menus, simplify property assignment and make it consistent. …
Exairnous Dec 2, 2021
c317084
Add support for material components and start on reworking how compon…
Exairnous Dec 3, 2021
d5ad399
Finished reworking how components are loaded. kit-alt-materials full…
Exairnous Jan 24, 2022
2ed37b8
Add support for importing scene properties.
Exairnous Jan 24, 2022
2cbcaa0
Merge branch 'master' into import
Exairnous Jan 25, 2022
4fccd71
Merge branch 'master' into import
Exairnous Mar 9, 2022
df211d2
Separate import functions out into their own file. Refactor how spec…
Exairnous Apr 6, 2022
889181f
Fix setting colors from Hex, handle more special cases, reduce code d…
Exairnous May 13, 2022
a35f433
Cleanup unused imports.
Exairnous May 13, 2022
a594064
Merge branch 'master' into import
Exairnous Jul 6, 2022
fb29aee
Update importer for changes in the new architecture.
Exairnous Jul 6, 2022
ba9d049
Clear the stored components after the import is finished so they don'…
Exairnous Jul 7, 2022
c1d1734
Handle properties that link to objects in a more reliable and future …
Exairnous Jul 7, 2022
af86b32
Update handle_spawner to the new architecture.
Exairnous Jul 7, 2022
6f4a80f
Add support for newer import API and refactor some code
keianhzo Jul 28, 2022
7141691
Simplify compat import
keianhzo Jul 28, 2022
1dc2129
Consolidate into one GLTF importer
keianhzo Jul 28, 2022
f8cbf4a
Fix media-frame yup issues and expose a global import property for yup
keianhzo Jul 28, 2022
2013a46
Remove debug print
keianhzo Jul 28, 2022
1a3a50d
Lightmap support
keianhzo Jul 29, 2022
a79ce27
Support for importing components in bones
keianhzo Jul 29, 2022
0480312
Remove duplicated comment
keianhzo Aug 22, 2022
b7c95a8
Remove unnecessary gather_imports
keianhzo Aug 22, 2022
b88f0dc
Update addons/io_hubs_addon/components/definitions/media_frame.py
keianhzo Aug 22, 2022
abdfc63
Update io add_hubs_components function name
keianhzo Aug 22, 2022
29f57db
Update addons/io_hubs_addon/io/gltf_importer.py
keianhzo Aug 22, 2022
07c9bc3
Update addons/io_hubs_addon/io/gltf_importer.py
keianhzo Aug 22, 2022
ee38a92
Update addons/io_hubs_addon/io/gltf_importer.py
keianhzo Aug 22, 2022
bb12ef3
Fix glTF string
keianhzo Aug 22, 2022
eab3282
Remove import_hubs_components method
keianhzo Aug 22, 2022
4cf0b7f
Catch and log component import exceptions
keianhzo Aug 22, 2022
87d1bc9
Move import
keianhzo Aug 22, 2022
64e1202
Update addons/io_hubs_addon/components/definitions/background.py
keianhzo Aug 22, 2022
3f66db0
Update addons/io_hubs_addon/components/definitions/background.py
keianhzo Aug 22, 2022
0342790
Update addons/io_hubs_addon/io/gltf_importer.py
keianhzo Aug 22, 2022
c3b84a3
Merge remote-tracking branch 'keianhzo/import-v1' into import-v1
keianhzo Aug 22, 2022
19c8b08
Fix merge issues
keianhzo Aug 22, 2022
35610fd
Fix merge issues
keianhzo Aug 22, 2022
091fd12
Fix lightmap import
keianhzo Aug 25, 2022
021299d
Show importer exception call stack
keianhzo Aug 25, 2022
f3a5f81
Support for Spoke GLB import
keianhzo Aug 25, 2022
bc971ef
Merge pull request #1 from keianhzo/import-v1
Exairnous Aug 26, 2022
c2089b5
Cleanup.
Exairnous Aug 26, 2022
5ce7a90
Merge branch 'master' into import
keianhzo Sep 6, 2022
ff2bc72
Fix merge conflict
keianhzo Sep 6, 2022
0161238
Use import extensions starting in Blender 3.1 because they aren't pre…
Exairnous Sep 11, 2022
0fb5c34
Fix #123
Exairnous Sep 19, 2022
28eaf83
Separate import functions out into their own file. Refactor how spec…
Exairnous Apr 6, 2022
126109f
Fix setting colors from Hex, handle more special cases, reduce code d…
Exairnous May 13, 2022
21ada56
Update importer for changes in the new architecture.
Exairnous Jul 6, 2022
3aaf0eb
Clear the stored components after the import is finished so they don'…
Exairnous Jul 7, 2022
02e990b
Handle properties that link to objects in a more reliable and future …
Exairnous Jul 7, 2022
9b0d4ac
Update handle_spawner to the new architecture.
Exairnous Jul 7, 2022
9bd5eab
Add support for newer import API and refactor some code
keianhzo Jul 28, 2022
e0e8f9c
Simplify compat import
keianhzo Jul 28, 2022
a3e92b1
Consolidate into one GLTF importer
keianhzo Jul 28, 2022
0dfd575
Fix media-frame yup issues and expose a global import property for yup
keianhzo Jul 28, 2022
051f24b
Remove debug print
keianhzo Jul 28, 2022
25ec5fb
Lightmap support
keianhzo Jul 29, 2022
74743ce
Support for importing components in bones
keianhzo Jul 29, 2022
9e6ed2e
Remove duplicated comment
keianhzo Aug 22, 2022
3794fcd
Remove unnecessary gather_imports
keianhzo Aug 22, 2022
a963def
Update io add_hubs_components function name
keianhzo Aug 22, 2022
0890280
Fix glTF string
keianhzo Aug 22, 2022
37e6a03
Remove import_hubs_components method
keianhzo Aug 22, 2022
815906d
Catch and log component import exceptions
keianhzo Aug 22, 2022
7994552
Move import
keianhzo Aug 22, 2022
8fd9910
Update addons/io_hubs_addon/components/definitions/media_frame.py
keianhzo Aug 22, 2022
7d9711d
Update addons/io_hubs_addon/io/gltf_importer.py
keianhzo Aug 22, 2022
8a5d30f
Update addons/io_hubs_addon/io/gltf_importer.py
keianhzo Aug 22, 2022
9be706e
Update addons/io_hubs_addon/io/gltf_importer.py
keianhzo Aug 22, 2022
5120f66
Update addons/io_hubs_addon/components/definitions/background.py
keianhzo Aug 22, 2022
92080da
Update addons/io_hubs_addon/components/definitions/background.py
keianhzo Aug 22, 2022
5979823
Update addons/io_hubs_addon/io/gltf_importer.py
keianhzo Aug 22, 2022
efcc735
Fix merge issues
keianhzo Aug 22, 2022
544b1a1
Fix lightmap import
keianhzo Aug 25, 2022
4620a56
Show importer exception call stack
keianhzo Aug 25, 2022
b05f7d4
Support for Spoke GLB import
keianhzo Aug 25, 2022
34abb76
Cleanup.
Exairnous Aug 26, 2022
6880d57
Fix merge conflict
keianhzo Sep 6, 2022
30c9920
Use import extensions starting in Blender 3.1 because they aren't pre…
Exairnous Sep 11, 2022
b2fe084
Fix #123
Exairnous Sep 19, 2022
d4ac897
Update importer parameters import_settings -> gltf
keianhzo Nov 2, 2022
c81cf53
Fix HDR images glTF import
keianhzo Nov 2, 2022
2988e81
Rebase fixes
keianhzo Nov 3, 2022
d11521b
Import tests
keianhzo Nov 4, 2022
44c6c20
Add delayed gathered to import and update tests
keianhzo Nov 4, 2022
5384bca
Remove debug print
keianhzo Nov 5, 2022
bd94d63
Enable all tests
keianhzo Nov 5, 2022
895d9c8
Detach relfection probes from the reflection probe object for correct…
keianhzo Nov 7, 2022
11715e4
Fix import issues with the text component in Spoke
keianhzo Nov 7, 2022
2c99c33
Support for importing Spoke's spawn points
keianhzo Nov 7, 2022
d6325b5
Support Spoke's box collider import
keianhzo Nov 7, 2022
fcfc8db
Merge branch 'master' into import-v2
keianhzo Jan 5, 2023
cf3ebb2
Merge fixes
keianhzo Jan 6, 2023
9d24341
Linter fixes
keianhzo Jan 6, 2023
54af4b4
Add reflection probe import support
keianhzo Jan 6, 2023
cf0a6e0
Disable undo stack in background mode
keianhzo Jan 9, 2023
8998792
Fix reflection probe host reference in migration
keianhzo Jan 17, 2023
4f2f74a
Make importer v1.1.0
keianhzo Jan 18, 2023
e3b048c
Merge branch 'import' into import-v2
Exairnous Mar 24, 2024
ed6df81
Merge pull request #4 from keianhzo/import-v2
Exairnous Mar 24, 2024
8f4972a
Fix importer/exporter panel registration.
Exairnous Mar 26, 2024
8ee41f3
Import properties for the audio-params component.
Exairnous Mar 26, 2024
288315d
Fix importing the tracks of the loop-animation component when the com…
Exairnous Mar 26, 2024
2e25110
Fix property value type check when importing text.
Exairnous Mar 26, 2024
c51833c
Remove unneeded add_component call from box collider and spawn point …
Exairnous Mar 26, 2024
db4dee4
Simplify delayed gathers in gltf_importer.py, make them consistent, a…
Exairnous Mar 26, 2024
7ca5909
Fix incorrect import of the cone angle properties for the audio param…
Exairnous Mar 26, 2024
36c28cf
Merge branch 'master' into import
Exairnous Mar 30, 2024
d36407c
Particle Emitter: Swap z/y values on import for startVelocity and end…
Exairnous Mar 31, 2024
9a95eb0
Media Frame: Add support for importing the align property.
Exairnous Mar 31, 2024
c76b9a6
Combine the image imports into a single utility function.
Exairnous Mar 31, 2024
d4b46f1
Support importing HDR images in Blender 4.0+
Exairnous Mar 31, 2024
f3da850
Simplify loop-animation import.
Exairnous Apr 2, 2024
dad1dec
Prevent a blank track from being added to the loop-animation componen…
Exairnous Apr 2, 2024
980e3df
Prevent any chance of a color space mismatch on import.
Exairnous Apr 2, 2024
47c917e
Consolidate Spoke components in the definitions/spoke folder and prin…
Exairnous Apr 2, 2024
f002386
Improve error reporting on import and show errors to the general user…
Exairnous Apr 2, 2024
ecadcc3
Consolidate image importing into one spot, fix background color impor…
Exairnous Apr 2, 2024
fa775ca
Fix gizmo update check error on import when importing armatures (e.g.…
Exairnous Apr 2, 2024
9cc9669
Add support for importing video texture/audio targets that point to b…
Exairnous Apr 2, 2024
bd638df
Remove reflection probe changes.
Exairnous Apr 4, 2024
83f7c9c
Set box-collider type to manual and convert its world scale/location …
Exairnous Apr 5, 2024
9095610
Add warning on media frame import if it or one of its parents is scal…
Exairnous Apr 5, 2024
5e79a58
Fix importing the bloom properties for the environment-settings compo…
Exairnous Apr 5, 2024
79f20bd
Switch to getting the node by the id rather than looking it up by nam…
Exairnous Apr 5, 2024
5991ed6
Remove unused import and run format.py.
Exairnous Apr 5, 2024
67268c4
Fix linter error.
Exairnous Apr 5, 2024
f58cbff
Added in support for both importing and exporting the Clip Rect prope…
Exairnous Apr 8, 2024
e7e1c96
Update the tests for the new text component property clip rect.
Exairnous Apr 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion addons/io_hubs_addon/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .io import gltf_exporter
from .io import gltf_exporter, gltf_importer
from . import (nodes, components)
bl_info = {
"name": "Hubs Blender Addon",
Expand All @@ -17,13 +17,15 @@

def register():
gltf_exporter.register()
gltf_importer.register()
nodes.register()
components.register()


def unregister():
components.unregister()
nodes.unregister()
gltf_importer.unregister()
gltf_exporter.unregister()


Expand Down
342 changes: 342 additions & 0 deletions addons/io_hubs_addon/io/gltf_importer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
import bpy
import traceback
import re
from io_scene_gltf2.blender.imp.gltf2_blender_node import BlenderNode
from io_scene_gltf2.blender.imp.gltf2_blender_material import BlenderMaterial
from io_scene_gltf2.blender.imp.gltf2_blender_scene import BlenderScene
from io_scene_gltf2.blender.imp.gltf2_blender_image import BlenderImage

from ..components.utils import has_component, add_component
from ..components.definitions.loop_animation import has_track

# import hooks were only recently added to the glTF exporter, so make a custom hook for now
orig_BlenderNode_create_object = BlenderNode.create_object
orig_BlenderMaterial_create = BlenderMaterial.create
orig_BlenderScene_create = BlenderScene.create

stored_components = {'object': {}, 'material': {}}

@staticmethod
def patched_BlenderNode_create_object(gltf, vnode_id):
obj = orig_BlenderNode_create_object(gltf, vnode_id)

vnode = gltf.vnodes[vnode_id]
node = None

if vnode.camera_node_idx is not None:
parent_vnode = gltf.vnodes[vnode.parent]
if parent_vnode.name:
node = [n for n in gltf.data.nodes if n.name == parent_vnode.name][0]

else:
if vnode.name:
node = [n for n in gltf.data.nodes if n.name == vnode.name][0]


if node is not None:
extensions = node.extensions
if extensions:
MOZ_hubs_components = extensions.get('MOZ_hubs_components')
if MOZ_hubs_components:
stored_components['object'][node.name] = (vnode, node)

return obj

@staticmethod
def patched_BlenderMaterial_create(gltf, material_idx, vertex_color):
orig_BlenderMaterial_create(gltf, material_idx, vertex_color)

glb_material = gltf.data.materials[material_idx]

if glb_material is not None:
extensions = glb_material.extensions
if extensions:
MOZ_hubs_components = extensions.get('MOZ_hubs_components')
if MOZ_hubs_components:
stored_components['material'][glb_material.name] = glb_material

@staticmethod
def patched_BlenderScene_create(gltf):
global stored_components
orig_BlenderScene_create(gltf)

create_object_hubs_components(gltf)
create_material_hubs_components(gltf)
create_scene_hubs_components(gltf)

# clear stored components so as not to conflict with the next import
for key in stored_components.keys():
stored_components[key].clear()


def create_object_hubs_components(gltf):
special_cases = {
'networked': handle_networked,
#'audio-target': handle_audio_target,
'spawn-point': handle_spawn_point,
'heightfield': handle_heightfield,
'box-collider': handle_box_collider,
'scene-preview-camera': handle_scene_preview_camera,
'trimesh': handle_trimesh,
'spawner': handle_spawner,
'loop-animation': handle_loop_animation,
}

for vnode, node in stored_components['object'].values():
MOZ_hubs_components = node.extensions['MOZ_hubs_components']
for glb_component_name, glb_component_value in MOZ_hubs_components.items():
try:
if glb_component_name in special_cases.keys():
special_cases[glb_component_name](gltf, vnode, node, glb_component_name, glb_component_value)
continue

else:
blender_component = add_hubs_component("object", glb_component_name, glb_component_value, vnode=vnode, node=node)

for property_name, property_value in glb_component_value.items():
assign_property(gltf, blender_component, property_name, property_value)

except Exception:
print("Error encountered while adding Hubs components:")
traceback.print_exc()
print("Continuing on....\n")

def create_material_hubs_components(gltf):
special_cases = {
#'video-texture-target': handle_video_texture_target,
}

for glb_material in stored_components['material'].values():
MOZ_hubs_components = glb_material.extensions['MOZ_hubs_components']

for glb_component_name, glb_component_value in MOZ_hubs_components.items():
try:
if glb_component_name in special_cases.keys():
special_cases[glb_component_name](gltf, glb_material, glb_component_name, glb_component_value)
continue

else:
blender_component = add_hubs_component("material", glb_component_name, glb_component_value, glb_material=glb_material)

for property_name, property_value in glb_component_value.items():
assign_property(gltf, blender_component, property_name, property_value)


except Exception:
print("Error encountered while adding Hubs components:")
traceback.print_exc()
print("Continuing on....\n")

def create_scene_hubs_components(gltf):
if gltf.data.scene is None:
return

special_cases = {
'environment-settings': handle_environment_settings,
'background': handle_background,
}

gltf_scene = gltf.data.scenes[gltf.data.scene]
extensions = gltf_scene.extensions
if extensions:
MOZ_hubs_components = extensions.get('MOZ_hubs_components')
if MOZ_hubs_components:
for glb_component_name, glb_component_value in MOZ_hubs_components.items():
try:
if glb_component_name in special_cases.keys():
special_cases[glb_component_name](gltf, glb_component_name, glb_component_value)
continue

blender_component = add_hubs_component("scene", glb_component_name, glb_component_value, gltf=gltf)

for property_name, property_value in glb_component_value.items():
assign_property(gltf, blender_component, property_name, property_value)

except Exception:
print("Error encountered while adding Hubs components:")
traceback.print_exc()
print("Continuing on....\n")


# OBJECT SPECIAL CASES
def handle_networked(gltf, vnode, node, glb_component_name, glb_component_value):
return

def handle_audio_target(gltf, vnode, node, glb_component_name, glb_component_value):
blender_component = add_hubs_component("object", glb_component_name, glb_component_value, vnode=vnode, node=node)

for property_name, property_value in glb_component_value.items():
if property_name == 'srcNode':
setattr(blender_component, property_name, gltf.vnodes[property_value['index']].blender_object)

else:
print(f"{property_name} = {property_value}")
setattr(blender_component, property_name, property_value)

def handle_spawn_point(gltf, vnode, node, glb_component_name, glb_component_value):
blender_component = add_hubs_component("object", "waypoint", glb_component_value, vnode=vnode, node=node)

blender_component.canBeSpawnPoint = True

def handle_heightfield(gltf, vnode, node, glb_component_name, glb_component_value):
return

def handle_box_collider(gltf, vnode, node, glb_component_name, glb_component_value):
blender_component = add_hubs_component("object", "ammo-shape", glb_component_value, vnode=vnode, node=node)

blender_component.type = "box"

def handle_scene_preview_camera(gltf, vnode, node, glb_component_name, glb_component_value):
return

def handle_trimesh(gltf, vnode, node, glb_component_name, glb_component_value):
return

def handle_spawner(gltf, vnode, node, glb_component_name, glb_component_value):
blender_component = add_hubs_component("object", glb_component_name, glb_component_value, vnode=vnode, node=node)

for property_name, property_value in glb_component_value.items():
if property_name == 'mediaOptions':
setattr(blender_component, "applyGravity", property_value["applyGravity"])

else:
assign_property(gltf, blender_component, property_name, property_value)

def handle_loop_animation(gltf, vnode, node, glb_component_name, glb_component_value):
blender_component = add_hubs_component("object", glb_component_name, glb_component_value, vnode=vnode, node=node)

for property_name, property_value in glb_component_value.items():
if property_name == 'clip':
tracks = property_value.split(",")
for track_name in tracks:
if not has_track(blender_component.tracks_list, track_name):
track = blender_component.tracks_list.add()
track.name = track_name.strip()

else:
assign_property(gltf, blender_component, property_name, property_value)


# MATERIAL SPECIAL CASES
def handle_video_texture_target(gltf, glb_material, glb_component_name, glb_component_value):
blender_component = add_hubs_component("material", glb_component_name, glb_component_value, glb_material=glb_material)

for property_name, property_value in glb_component_value.items():
if property_name == 'srcNode':
setattr(blender_component, property_name, gltf.vnodes[property_value['index']].blender_object)

else:
print(f"{property_name} = {property_value}")
setattr(blender_component, property_name, property_value)


# SCENE SPECIAL CASES
def handle_environment_settings(gltf, glb_component_name, glb_component_value):
blender_component = add_hubs_component("scene", glb_component_name, glb_component_value, gltf=gltf)

# load environment maps
enviro_imgs = {}
for gltf_texture in gltf.data.textures:
extensions = gltf_texture.extensions
if extensions:
MOZ_texture_rgbe = extensions.get('MOZ_texture_rgbe')
if MOZ_texture_rgbe:
BlenderImage.create(gltf, MOZ_texture_rgbe['source'])
pyimg = gltf.data.images[MOZ_texture_rgbe['source']]
blender_image_name = pyimg.blender_image_name
enviro_imgs[MOZ_texture_rgbe['source']] = blender_image_name


for property_name, property_value in glb_component_value.items():
if isinstance(property_value, dict) and property_value['__mhc_link_type'] == "texture":
blender_image_name = enviro_imgs[property_value['index']]
blender_image = bpy.data.images[blender_image_name]

setattr(blender_component, property_name, blender_image)

else:
assign_property(gltf, blender_component, property_name, property_value)

def handle_background(gltf, glb_component_name, glb_component_value):
blender_component = add_hubs_component("scene", "environment-settings", glb_component_value, gltf=gltf)

blender_component.toneMapping = "LinearToneMapping"

set_color_from_hex(blender_component, "backgroundColor", glb_component_value['color'])


# UTILITIES
def add_hubs_component(element_type, glb_component_name, glb_component_value, vnode=None, node=None, glb_material=None, gltf=None):
# get element
if element_type == "object":
element = vnode.blender_object

elif element_type == "material":
element = bpy.data.materials[glb_material.blender_material[None]]

elif element_type == "scene":
element = bpy.data.scenes[gltf.blender_scene]

else:
element = None

# print debug info
if element_type == "object":
print(f"Node Name: {node.name}")
print(f"Object: {element}")

print(f"Hubs Component Name: {glb_component_name}")
print(f"Hubs Component Value: {glb_component_value}")

# create component
if not has_component(element, glb_component_name):
add_component(element, glb_component_name)

return getattr(element, f"hubs_component_{glb_component_name.replace('-', '_')}")

def set_color_from_hex(blender_component, property_name, hexcolor):
hexcolor = hexcolor.lstrip('#')
rgb_int = [int(hexcolor[i:i+2], 16) for i in (0, 2, 4)]

for x, value in enumerate(rgb_int):
rgb_float = value/255 if value > 0 else 0

# convert sRGB values to linear
if rgb_float < 0.04045:
rgb_float_linear = rgb_float * (1.0 / 12.92)

else:
rgb_float_linear = ((rgb_float + 0.055) * (1.0 / 1.055)) ** 2.4

print(f"{property_name}[{x}] = {rgb_float_linear}")
getattr(blender_component, property_name)[x] = rgb_float_linear

def assign_property(gltf, blender_component, property_name, property_value):
if isinstance(property_value, dict):
if property_value.get('__mhc_link_type'):
if len(property_value) == 2:
setattr(blender_component, property_name, gltf.vnodes[property_value['index']].blender_object)

else:
blender_subcomponent = getattr(blender_component, property_name)
for x, subproperty_value in enumerate(property_value.values()):
print(f"{property_name}[{x}] = {subproperty_value}")
blender_subcomponent[x] = subproperty_value

elif re.fullmatch("#[0-9a-fA-F]*", str(property_value)):
set_color_from_hex(blender_component, property_name, property_value)

else:
print(f"{property_name} = {property_value}")
setattr(blender_component, property_name, property_value)


def register():
BlenderNode.create_object = patched_BlenderNode_create_object
BlenderMaterial.create = patched_BlenderMaterial_create
BlenderScene.create = patched_BlenderScene_create

def unregister():
BlenderNode.create_object = orig_BlenderNode_create_object
BlenderMaterial.create = orig_BlenderMaterial_create
BlenderScene.create = orig_BlenderScene_create