def _convert_skin_to_usd(self, gltf_node, gltf_primitive, usd_node, usd_mesh): """Converts a glTF skin to a UsdSkel Arguments: gltf_node {dict} -- glTF node node_index {int} -- index of the glTF node usd_parent_node {UsdPrim} -- parent node of the usd node usd_mesh {[type]} -- [description] """ skel_binding_api = UsdSkel.BindingAPI(usd_mesh) gltf_skin = gltf_node.get_skin() if not gltf_skin: self.logger.warning('The glTF node has joints, but no skin associated with them') else: gltf_joint_names = [GLTF2USDUtils.convert_to_usd_friendly_node_name(joint.name) for joint in gltf_skin.get_joints()] usd_joint_names = [Sdf.Path(self._get_usd_joint_hierarchy_name(joint, gltf_skin.root_joints)) for joint in gltf_skin.get_joints()] skeleton = self._create_usd_skeleton(gltf_skin, usd_node, usd_joint_names) skeleton_animation = self._create_usd_skeleton_animation(gltf_skin, skeleton, usd_joint_names) parent_path = usd_node.GetPath() bind_matrices = [] rest_matrices = [] skeleton_root = self.stage.GetPrimAtPath(parent_path) skel_binding_api = UsdSkel.BindingAPI(usd_mesh) skel_binding_api.CreateGeomBindTransformAttr(Gf.Matrix4d(((1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1)))) skel_binding_api.CreateSkeletonRel().AddTarget(skeleton.GetPath()) if skeleton_animation: skel_binding_api.CreateAnimationSourceRel().AddTarget(skeleton_animation.GetPath()) skeleton_skel_binding_api = UsdSkel.BindingAPI(skeleton) skeleton_skel_binding_api.CreateAnimationSourceRel().AddTarget(skeleton_animation.GetPath()) bind_matrices = self._compute_bind_transforms(gltf_skin) primitive_attributes = gltf_primitive.get_attributes() if 'WEIGHTS_0' in primitive_attributes and 'JOINTS_0' in primitive_attributes: total_vertex_weights = primitive_attributes['WEIGHTS_0'].get_data() total_vertex_joints = primitive_attributes['JOINTS_0'].get_data() total_joint_indices = [] total_joint_weights = [] for joint_indices, weights in zip(total_vertex_joints, total_vertex_weights): for joint_index, weight in zip(joint_indices, weights): total_joint_indices.append(joint_index) total_joint_weights.append(weight) joint_indices_attr = skel_binding_api.CreateJointIndicesPrimvar(False, 4).Set(total_joint_indices) total_joint_weights = Vt.FloatArray(total_joint_weights) UsdSkel.NormalizeWeights(total_joint_weights, 4) joint_weights_attr = skel_binding_api.CreateJointWeightsPrimvar(False, 4).Set(total_joint_weights)
def testSkelWithoutBindPose(self): """ Tests export of a Skeleton when a bindPose is not fully setup. """ mayaFile = os.path.join(self.inputPath, "UsdExportSkeletonTest", "UsdExportSkeletonWithoutBindPose.ma") cmds.file(mayaFile, force=True, open=True) frameRange = [1, 5] usdFile = os.path.abspath('UsdExportSkeletonWithoutBindPose.usda') cmds.usdExport(mergeTransformAndShape=True, file=usdFile, shadingMode='none', frameRange=frameRange, exportSkels='auto') stage = Usd.Stage.Open(usdFile) skeleton = UsdSkel.Skeleton.Get(stage, '/cubeRig/skel/joint1') self.assertEqual(skeleton.GetBindTransformsAttr().Get(), Vt.Matrix4dArray([Gf.Matrix4d(1.0)])) self.assertEqual(skeleton.GetJointsAttr().Get(), Vt.TokenArray(['joint1'])) self.assertEqual(skeleton.GetRestTransformsAttr().Get(), Vt.Matrix4dArray([Gf.Matrix4d(1.0)])) self.assertTrue(skeleton.GetPrim().HasAPI(UsdSkel.BindingAPI)) skelBindingAPI = UsdSkel.BindingAPI(skeleton) self.assertTrue(skelBindingAPI) animSourcePrim = skelBindingAPI.GetAnimationSource() self.assertEqual(animSourcePrim.GetPath(), '/cubeRig/skel/joint1/Animation') animSource = UsdSkel.Animation(animSourcePrim) self.assertTrue(animSource) self.assertEqual(skeleton.GetJointsAttr().Get(), Vt.TokenArray(['joint1'])) self.assertEqual(animSource.GetRotationsAttr().Get(), Vt.QuatfArray([Gf.Quatf(1.0, Gf.Vec3f(0.0))])) self.assertEqual(animSource.GetScalesAttr().Get(), Vt.Vec3hArray([Gf.Vec3h(1.0)])) self.assertEqual( animSource.GetTranslationsAttr().Get(Usd.TimeCode.Default()), Vt.Vec3fArray([Gf.Vec3f(5.0, 5.0, 0.0)])) self.assertEqual( animSource.GetTranslationsAttr().Get(1.0), Vt.Vec3fArray([Gf.Vec3f(0.0, 0.0, 0.0)])) self.assertEqual( animSource.GetTranslationsAttr().Get(2.0), Vt.Vec3fArray([Gf.Vec3f(1.25, 1.25, 0.0)])) self.assertEqual( animSource.GetTranslationsAttr().Get(3.0), Vt.Vec3fArray([Gf.Vec3f(2.5, 2.5, 0.0)])) self.assertEqual( animSource.GetTranslationsAttr().Get(4.0), Vt.Vec3fArray([Gf.Vec3f(3.75, 3.75, 0.0)])) self.assertEqual( animSource.GetTranslationsAttr().Get(5.0), Vt.Vec3fArray([Gf.Vec3f(5.0, 5.0, 0.0)]))
def test_JointInfluences(self): """Tests for helpers for getting/setting joint influences.""" stage = Usd.Stage.CreateInMemory() gprim = stage.DefinePrim('/Model/Gprim') binding = UsdSkel.BindingAPI(gprim) indices = binding.CreateJointIndicesPrimvar(constant=False, elementSize=3) assert indices assert indices.GetInterpolation() == UsdGeom.Tokens.vertex assert indices.GetElementSize() == 3 weights = binding.CreateJointWeightsPrimvar(constant=True) assert weights assert weights.GetInterpolation() == UsdGeom.Tokens.constant # Should be able to re-create bindings with an alternate # interpolation and/or element size. weights = binding.CreateJointWeightsPrimvar(constant=False, elementSize=3) assert weights assert weights.GetInterpolation() == UsdGeom.Tokens.vertex assert weights.GetElementSize() == 3 assert binding.SetRigidJointInfluence(10, 0.5) indices = binding.GetJointIndicesPrimvar() weights = binding.GetJointWeightsPrimvar() assert indices.Get() == Vt.IntArray([10]) assert weights.Get() == Vt.FloatArray([0.5])
def test_InstancedBlendShape(self): """Tests for correctness in the interpretation of instanced blend shapes.""" testFile = "populate.usda" stage = Usd.Stage.Open(testFile) cache = UsdSkel.Cache() skelRoot = UsdSkel.Root(stage.GetPrimAtPath("/SkelBinding")) self.assertTrue(cache.Populate(skelRoot, Usd.TraverseInstanceProxies())) # instance proxy mesh mesh = stage.GetPrimAtPath("/SkelBinding/Instance/Override") skelBinding = UsdSkel.BindingAPI(mesh) self.assertEqual(list(skelBinding.GetBlendShapesAttr().Get()), ["override"]) skel = skelBinding.GetSkeleton() skelq = cache.GetSkelQuery(skel) animq = skelq.GetAnimQuery() self.assertEqual(list(animq.GetBlendShapeOrder()), ["override", "shape"]) skinq = cache.GetSkinningQuery(mesh) self.assertTrue(skinq.HasBlendShapes()) self.assertEqual(skelBinding.GetInheritedAnimationSource(), stage.GetPrimAtPath("/Anim1")) # bug PRES-77530 # because skelBinding.GetBlendShapesAttr().Get() and # animq.GetBlendShapeOrder() have different order, # the mapper should not be null. mapper = skinq.GetBlendShapeMapper() self.assertFalse(mapper.IsNull())
def _convert_primitive_to_mesh(self, gltf_primitive, usd_node, gltf_node, gltf_mesh): """ Converts a glTF mesh primitive to a USD mesh Arguments: name {str} -- name of the primitive primitive {dict} -- glTF primitive usd_parent_node {str} -- USD parent xform node_index {int} -- glTF node index double_sided {bool} -- specifies if the primitive is double sided """ parent_node = usd_node parent_path = parent_node.GetPath() attributes = gltf_primitive.get_attributes() skel_root = None targets = gltf_primitive.get_morph_targets() if 'JOINTS_0' in attributes or len(targets) > 0: skeleton_path = '{0}/{1}'.format(usd_node.GetPath(), 'skeleton_root') skel_root = UsdSkel.Root.Define(self.stage, skeleton_path) parent_node = skel_root parent_path = parent_node.GetPath() mesh = UsdGeom.Mesh.Define( self.stage, '{0}/{1}'.format( parent_node.GetPath(), GLTF2USDUtils.convert_to_usd_friendly_node_name( gltf_primitive.get_name()))) mesh.CreateSubdivisionSchemeAttr().Set('none') material = gltf_primitive.get_material() if material != None: if material.is_double_sided(): mesh.CreateDoubleSidedAttr().Set(True) usd_material = self.usd_materials[material.get_index()] UsdShade.MaterialBindingAPI(mesh).Bind( usd_material.get_usd_material()) for attribute_name in attributes: attribute = attributes[attribute_name] if attribute_name == 'POSITION': override_prim = self.stage.OverridePrim(mesh.GetPath()) override_prim.CreateAttribute( 'extent', Sdf.ValueTypeNames.Float3Array).Set( [attribute.get_min_value(), attribute.get_max_value()]) mesh.CreatePointsAttr(attribute.get_data()) if attribute_name == 'NORMAL': mesh.CreateNormalsAttr(attribute.get_data()) if attribute_name == 'COLOR_0': prim_var = UsdGeom.PrimvarsAPI(mesh) data = attribute.get_data() if attribute.accessor_type == 'VEC4': print( 'Vertex color alpha currently not supported. Defaulting to vertex color without alpha.' ) data = [ Gf.Vec3f(entry[0:3]) for entry in attribute.get_data() ] colors = prim_var.CreatePrimvar('displayColor', Sdf.ValueTypeNames.Color3f, 'vertex').Set(data) if attribute_name == 'TEXCOORD_0': data = attribute.get_data() invert_uvs = [] for uv in data: new_uv = (uv[0], 1 - uv[1]) invert_uvs.append(new_uv) prim_var = UsdGeom.PrimvarsAPI(mesh) uv = prim_var.CreatePrimvar('primvars:st0', Sdf.ValueTypeNames.TexCoord2fArray, 'vertex') uv.Set(invert_uvs) if attribute_name == 'TEXCOORD_1': data = attribute.get_data() invert_uvs = [] for uv in data: new_uv = (uv[0], 1 - uv[1]) invert_uvs.append(new_uv) prim_var = UsdGeom.PrimvarsAPI(mesh) uv = prim_var.CreatePrimvar('primvars:st1', Sdf.ValueTypeNames.TexCoord2fArray, 'vertex') uv.Set(invert_uvs) if attribute_name == 'JOINTS_0': self._convert_skin_to_usd(gltf_node, gltf_primitive, parent_node, mesh) weights = gltf_mesh.get_weights() if targets: skinBinding = UsdSkel.BindingAPI.Apply(mesh.GetPrim()) skeleton = UsdSkel.Skeleton.Define(self.stage, '{0}/skel'.format(parent_path)) # Create an animation for this mesh to hold the blendshapes skelAnim = UsdSkel.Animation.Define( self.stage, '{0}/skel/anim'.format(parent_path)) # link the skeleton animation to skelAnim skinBinding.CreateAnimationSourceRel().AddTarget( skelAnim.GetPath()) skeleton_skel_binding = UsdSkel.BindingAPI(skeleton) skeleton_skel_binding.CreateAnimationSourceRel().AddTarget( skelAnim.GetPath()) # link the skeleton to skeleton skinBinding.CreateSkeletonRel().AddTarget(skeleton.GetPath()) # Set blendshape names on the animation names = [] for i, _ in enumerate(gltf_mesh.get_weights()): targets[i].get_name() blend_shape_name = GLTF2USDUtils.convert_to_usd_friendly_node_name( targets[i].get_name()) names.append(blend_shape_name) skelAnim.CreateBlendShapesAttr().Set(names) self._set_blendshape_weights(skelAnim, usd_node, gltf_node) skinBinding.CreateBlendShapesAttr(names) # Set the starting weights of each blendshape to the weights defined in the glTF primitive blend_shape_targets = skinBinding.CreateBlendShapeTargetsRel() # Define offsets for each blendshape, and add them as skel:blendShapes and skel:blendShapeTargets for i, name in enumerate(names): offsets = targets[i].get_attributes()['POSITION'] blend_shape_name = '{0}/{1}'.format(mesh.GetPath(), name) # define blendshapes in the mesh blend_shape = UsdSkel.BlendShape.Define( self.stage, blend_shape_name) blend_shape.CreateOffsetsAttr(offsets) blend_shape_targets.AddTarget(name) indices = gltf_primitive.get_indices() num_faces = int(len(indices) / 3) face_count = [3] * num_faces mesh.CreateFaceVertexCountsAttr(face_count) mesh.CreateFaceVertexIndicesAttr(indices)