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

Fix transforms #83

Merged
merged 3 commits into from
Oct 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 20 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
0.1.0 (2018-10-15)
Changes:
#Changelog

## 0.1.0 (2018-10-15)
**Fixed Bugs:**
- Fixed an issue where generating `usdz` wrote out absolute paths instead of relative paths

**Changes:**
- Reorganized repo by moving files to the `_gltf2usd` module
- Renames unicode filenames to ascii to avoid name conflicts (https://github.com/kcoley/gltf2usd/issues/71)
- Added versioning to the `gltf2usd` (https://github.com/kcoley/gltf2usd/issues/81)
- Fixed an issue where generating `usdz` wrote out absolute paths instead of relative paths (https://github.com/kcoley/gltf2usd/issues/68)
- Added changelog
(https://github.com/kcoley/gltf2usd/issues/68)
- Added changelog


## 0.1.1 (2018-10-21)
**Fixed Bugs:**
- Fixed issue with node transforms and node animations, where the glTF node transform would get applied on top of its animation, causing incorrect positions.

**Changes:**
- Convert usd file path to absolute path on load
- Reformatted changelog
- Switched some methods to properties
- Increment version
6 changes: 4 additions & 2 deletions Source/_gltf2usd/gltf2/Animation.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,15 @@ def __init__(self, channel_entry, animation):
self._target = AnimationChannelTarget(channel_entry['target'])
self._animation = animation

def get_target(self):
@property
def target(self):
return self._target

def get_sampler_index(self):
return self._sampler_index

def get_sampler(self):
@property
def sampler(self):
return self._animation._samplers[self._sampler_index]


Expand Down
6 changes: 4 additions & 2 deletions Source/_gltf2usd/gltf2/Material.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,17 @@ def __init__(self, normal_texture_entry, gltf_loader):
super(NormalTexture, self).__init__(normal_texture_entry, gltf_loader)
self._scale = normal_texture_entry['scale'] if ('scale' in normal_texture_entry) else 1.0

def get_scale(self):
@property
def scale(self):
return self._scale

class OcclusionTexture(Texture):
def __init__(self, occlusion_texture_entry, gltf_loader):
super(OcclusionTexture, self).__init__(occlusion_texture_entry, gltf_loader)
self._strength = occlusion_texture_entry['strength'] if ('strength' in occlusion_texture_entry) else 1.0

def get_strength(self):
@property
def strength(self):
return self._strength

class PbrMetallicRoughness:
Expand Down
12 changes: 8 additions & 4 deletions Source/_gltf2usd/gltf2/Node.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@ def __init__(self, node_dict, node_index, gltf_loader):
def get_name(self):
return self._name

def get_translation(self):
@property
def translation(self):
return self._translation

def get_rotation(self):
@property
def rotation(self):
return self._rotation

def get_scale(self):
@property
def scale(self):
return self._scale

def get_children(self):
Expand All @@ -43,7 +46,8 @@ def get_children(self):
def get_parent(self):
return self._parent

def get_matrix(self):
@property
def matrix(self):
return self._matrix

def get_index(self):
Expand Down
8 changes: 4 additions & 4 deletions Source/_gltf2usd/gltf2usdUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def compute_usd_transform_matrix_from_gltf_node(node):
Matrix-- USD matrix
"""

matrix = node.get_matrix()
matrix = node.matrix
if (matrix != None):
return Gf.Matrix4d(
matrix[0], matrix[1], matrix[2], matrix[3],
Expand All @@ -43,13 +43,13 @@ def compute_usd_transform_matrix_from_gltf_node(node):
matrix[12], matrix[13], matrix[14], matrix[15]
)
else:
translation = node.get_translation()
translation = node.translation
usd_translation = Gf.Vec3f(translation[0], translation[1], translation[2])

rotation = node.get_rotation()
rotation = node.rotation
usd_rotation = Gf.Quatf(rotation[3], rotation[0], rotation[1], rotation[2])

scale = node.get_scale()
scale = node.scale
usd_scale = Gf.Vec3h(scale[0], scale[1], scale[2])

return UsdSkel.MakeTransform(usd_translation, usd_rotation, usd_scale)
Expand Down
2 changes: 1 addition & 1 deletion Source/_gltf2usd/usd_material.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def _set_normal_texture(self, gltf_material):
self._normal.Set((0,0,1))
else:
destination = normal_texture.write_to_directory(self._output_directory, GLTFImage.ImageColorChannels.RGB)
normal_scale = normal_texture.get_scale()
normal_scale = normal_texture.scale
scale_factor = (normal_scale, normal_scale, normal_scale, 1.0)
usd_uv_texture = USDUVTexture("normalTexture", self._stage, self._usd_material._usd_material, normal_texture, [self._st0, self._st1])
usd_uv_texture._file_asset.Set(destination)
Expand Down
2 changes: 1 addition & 1 deletion Source/_gltf2usd/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class Version(object):
"""
_major = 0
_minor = 1
_patch = 0
_patch = 1
@staticmethod
def get_major_version_number():
"""Returns the major version
Expand Down
107 changes: 86 additions & 21 deletions Source/gltf2usd.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,17 @@ def _convert_node_to_xform(self, node, usd_xform):
xform_name {str} -- USD xform name
"""
xformPrim = UsdGeom.Xform.Define(self.stage, '{0}/{1}'.format(usd_xform.GetPath(), GLTF2USDUtils.convert_to_usd_friendly_node_name(node.get_name())))
xformPrim.AddTransformOp().Set(self._compute_rest_matrix(node))

if self._node_has_animations(node):
self._convert_animation_to_usd(node, xformPrim)
else:
xformPrim.AddTransformOp().Set(self._compute_rest_matrix(node))


mesh = node.get_mesh()
if mesh != None:
usd_mesh = self._convert_mesh_to_xform(mesh, xformPrim, node)

self._convert_animation_to_usd(node, xformPrim)


children = node.get_children()

for child in children:
Expand Down Expand Up @@ -211,20 +215,20 @@ def _get_anim_data_for_joint_and_path(self, gltf_animation, gltf_joint, path, ti
anim_channel = gltf_animation.get_animation_channel_for_node_and_path(gltf_joint, path)
if not anim_channel:
if path == 'translation':
return gltf_joint.get_translation()
return gltf_joint.translation
elif path == 'rotation':
gltf_rotation = gltf_joint.get_rotation()
gltf_rotation = gltf_joint.rotation
usd_rotation = Gf.Quatf(gltf_rotation[3], gltf_rotation[0], gltf_rotation[1], gltf_rotation[2])
return usd_rotation
elif path == 'scale':
return gltf_joint.get_scale()
return gltf_joint.scale

else:
if path == 'rotation':
rotation = anim_channel.get_sampler().get_interpolated_output_data(time_sample)
rotation = anim_channel.sampler.get_interpolated_output_data(time_sample)
return rotation
elif path == 'scale' or path =='translation':
return anim_channel.get_sampler().get_interpolated_output_data(time_sample)
return anim_channel.sampler.get_interpolated_output_data(time_sample)
else:
raise Exception('unsupported animation type: {}'.format(path))

Expand Down Expand Up @@ -436,6 +440,16 @@ def _convert_materials_to_preview_surface_new(self):
usd_material.convert_material_to_usd_preview_surface(material, self.output_dir)
self.usd_materials.append(usd_material)

def _node_has_animations(self, gltf_node):
animations = self.gltf_loader.get_animations()
for animation in animations:
animation_channels = animation.get_animation_channels_for_node(gltf_node)
if len(animation_channels) > 0:
return True


return False


def _convert_animation_to_usd(self, gltf_node, usd_node):
animations = self.gltf_loader.get_animations()
Expand All @@ -446,15 +460,38 @@ def _convert_animation_to_usd(self, gltf_node, usd_node):
if len(animation_channels) > 0:
total_max_time = -999
total_min_time = 999
for channel in animation_channels:
min_max_time = self._create_usd_animation(usd_node, channel)
total_max_time = max(total_max_time, min_max_time.max)
total_min_time = min(total_min_time, min_max_time.min)

min_max_time = self._create_usd_animation2(usd_node, gltf_node, animation_channels)

total_max_time = max(total_max_time, min_max_time.max)
total_min_time = min(total_min_time, min_max_time.min)

self.stage.SetStartTimeCode(total_min_time * self.fps)
self.stage.SetEndTimeCode(total_max_time * self.fps)
self.stage.SetTimeCodesPerSecond(self.fps)

def _create_keyframe_transform_node(self, gltf_node, animation_channels, input_sample):
matrix = gltf_node.matrix
if matrix:
translation = Gf.Vec3f()
rotation = Gf.Quatf()
scale = Gf.Vec3h()
usd_matrix = self._convert_to_usd_matrix(matrix)
UsdSkel.DecomposeTransform(usd_matrix, translation, rotation, scale)
else:
translation = Gf.Vec3f(gltf_node.translation)
rotation = Gf.Quatf(gltf_node.rotation[3], gltf_node.rotation[0], gltf_node.rotation[1], gltf_node.rotation[2])
scale = Gf.Vec3h(gltf_node.scale)

for animation_channel in animation_channels:
if animation_channel.target == 'translation':
translation = animation_channel.sampler.get_interpolated_output_data(input_sample)
elif animation_channel.target == 'rotation':
rotation = animation_channel.sampler.get_interpolated_output_data(input_sample)
elif animation_channel.target == 'scale':
scale = animation_channel.sampler.get_interpolated_output_data(input_sample)

return UsdSkel.MakeTransform(translation, rotation, scale)

def _convert_skin_to_usd(self, gltf_node, gltf_primitive, usd_node, usd_mesh):
"""Converts a glTF skin to a UsdSkel
Expand Down Expand Up @@ -551,7 +588,7 @@ def _compute_rest_matrix(self, gltf_node):
"""

xform_matrix = None
matrix = gltf_node.get_matrix()
matrix = gltf_node.matrix
if matrix != None:
xform_matrix = self._convert_to_usd_matrix(matrix)
return xform_matrix
Expand All @@ -560,13 +597,13 @@ def _compute_rest_matrix(self, gltf_node):
usd_rotation = Gf.Quatf().GetIdentity()
usd_translation = Gf.Vec3f(0,0,0)

scale = gltf_node.get_scale()
scale = gltf_node.scale
usd_scale = Gf.Vec3h(scale[0], scale[1], scale[2])

rotation = gltf_node.get_rotation()
rotation = gltf_node.rotation
usd_rotation = Gf.Quatf(rotation[3], rotation[0], rotation[1], rotation[2])

translation = gltf_node.get_translation()
translation = gltf_node.translation
usd_translation = Gf.Vec3f(translation[0], translation[1], translation[2])

return UsdSkel.MakeTransform(usd_translation, usd_rotation, usd_scale)
Expand All @@ -583,7 +620,7 @@ def _create_usd_animation(self, usd_node, animation_channel):
[type] -- [description]
"""

sampler = animation_channel.get_sampler()
sampler = animation_channel.sampler


max_time = int(round(sampler.get_input_max()[0] ))
Expand All @@ -600,6 +637,34 @@ def _create_usd_animation(self, usd_node, animation_channel):
MinMaxTime = collections.namedtuple('MinMaxTime', ('max', 'min'))
return MinMaxTime(max=max_time, min=min_time)

def _create_usd_animation2(self, usd_node, gltf_node, animation_channels):
"""Converts a glTF animation to a USD animation

Arguments:
usd_node {[type]} -- usd node
gltf_node {[type]} -- glTF node
animation_channel {AnimationMap} -- map of animation target path and animation sampler indices

Returns:
[type] -- [description]
"""

max_time = -999
min_time = 999
for channel in animation_channels:
max_time = max(max_time, int(round(channel.sampler.get_input_max()[0])))
min_time = min(min_time, int(round(channel.sampler.get_input_min()[0])))


transform = usd_node.AddTransformOp(opSuffix='transform')

for i, keyframe in enumerate(numpy.arange(min_time, max_time, 1./self.fps)):
transform_node = self._create_keyframe_transform_node(gltf_node, animation_channels, keyframe)
transform.Set(transform_node, Usd.TimeCode(i))

MinMaxTime = collections.namedtuple('MinMaxTime', ('max', 'min'))
return MinMaxTime(max=max_time, min=min_time)

def _get_keyframe_conversion_func(self, usd_node, animation_channel):
"""Convert glTF key frames to USD animation key frames

Expand All @@ -614,8 +679,8 @@ def _get_keyframe_conversion_func(self, usd_node, animation_channel):
[func] -- USD animation conversion function
"""

path = animation_channel.get_target().get_path()
animation_sampler = animation_channel.get_sampler()
path = animation_channel.target.get_path()
animation_sampler = animation_channel.sampler

def convert_translation(transform, time, output, i, _):
value = animation_sampler.get_interpolated_output_data(time)
Expand Down Expand Up @@ -739,4 +804,4 @@ def convert_to_usd(gltf_file, usd_file, fps, scale, arkit=False, verbose=False,
args = parser.parse_args()

if args.gltf_file:
convert_to_usd(os.path.expanduser(args.gltf_file), os.path.expanduser(args.usd_file), args.fps, args.scale, args.arkit, args.verbose, args.use_euler_rotation)
convert_to_usd(os.path.expanduser(args.gltf_file), os.path.abspath(os.path.expanduser(args.usd_file)), args.fps, args.scale, args.arkit, args.verbose, args.use_euler_rotation)
6 changes: 3 additions & 3 deletions Source/tests/testInitializeGLTFLoader.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ def test_get_animation_channels_for_node_index(self):
node = self.loader.get_nodes()[2]
animation_channels = animation.get_animation_channels_for_node(node)
print('\n\n\n\n\n\n\n')
print([animation_channel.get_target().get_path() for animation_channel in animation_channels])
print([animation_channel.target.get_path() for animation_channel in animation_channels])

def test_get_animation_sampler_input_data(self):
animation = self.loader.get_animations()[0]
node = self.loader.get_nodes()[2]
animation_channel = animation.get_animation_channel_for_node_and_path(node, 'rotation')
input_data = animation_channel.get_sampler().get_input_data()
input_data = animation_channel.sampler.get_input_data()

print('input:\n\n\n\n\n\n\n')
print(input_data)
Expand All @@ -97,7 +97,7 @@ def test_get_animation_sampler_output_data(self):
animation = self.loader.get_animations()[0]
node = self.loader.get_nodes()[2]
animation_channel = animation.get_animation_channel_for_node_and_path(node, 'rotation')
output_data = animation_channel.get_sampler().get_output_data()
output_data = animation_channel.sampler.get_output_data()
print('output:\n\n\n\n\n\n\n')
print(output_data)

Expand Down