Пример #1
0
		//! duplicate this rig (deep copy)
		public Rig Duplicate() {
		
			Rig rig = new Rig ();
			for (int i = 0; i < NumShapes(); i++) rig.AddShape(ShapeName(i));
			for (int i = 0; i < NumBones() ; i++) rig.AddBone(BoneName(i));
			return rig;
		}
Пример #2
0
	    /**
	     * @brief Reads an fsb file and returns a clip constructed from the the content of the fsb file.
	     * @param[in] data  The binary data from the fsb file.
	     * @return A clip with the track data imported from the fsb file, null if there was some error during loading.
	     */
	    public static Clip Read(byte[] data) {
	
	        DataParser parser = new DataParser();
	        parser.ExtractData(data, false, 0.0);
	
	        if (parser.Valid()) {
	
	            Rig rig = new Rig();
	
	            // add hardcoded bone names of fsb file
	            rig.AddBone("Neck");
	            rig.AddBone("EyeLeft");
	            rig.AddBone("EyeRight");
	
	            for (int i = 0; i < parser.fsBlendShapeNames.Length; i++) {
	                rig.AddShape(parser.fsBlendShapeNames[i]);
	            }
	
	            Clip clip = new Clip(rig);
	
	            while (parser.CountAvailableTracks() > 0) {
	                TrackData track_data = parser.Dequeue();
	
	                if (!track_data.TrackSuccess) {
	                    // do not save the state if the tracking data is not valid
	                    Debug.LogWarning("this frame doesn't contain valid tracking data");
	                    continue;
	                }
	
	                RigState state = clip.NewState(track_data.TimeStamp);
	                
					state.SetTrackingSuccessful(track_data.TrackSuccess);
	
	                if (rig.NumShapes() != track_data.n_coefficients()) {
	                    Debug.LogError("num blendshapes do not agree in file with " + rig.NumShapes() +
	                                   " in rig and " + track_data.n_coefficients() + " in state");
	                    return null;
	                }
	
	                // Assume the head translation to be joint 0 (Neck)
	                state.SetBoneTranslation(0, track_data.HeadTranslation());
	
	                // bone indices same as the order when added to the rig
	                state.SetBoneRotation(0, track_data.HeadRotation());
	                state.SetBoneRotation(1, track_data.LeftEyeRotation());
	                state.SetBoneRotation(2, track_data.RightEyeRotation());
	
	                for (int i = 0; i < track_data.n_coefficients(); i++) {
	                    state.SetBlendshapeCoefficient(i, track_data.Coefficient[i]);
	                }
	            }
	
	            return clip;
	        } else {
	            Debug.LogError("cannot parse fsb file");
	        }
	
	        return null;
	    }
Пример #3
0
		//! @returns a rig build from a set of blendshape names
		static public Rig GetRigFromBlendShapeNames(string [] blendshape_names) {
			Rig rig = new Rig();
			rig.AddBone("Neck");
			rig.AddBone("EyeLeft");
			rig.AddBone("EyeRight");
			for (int i = 0; i < blendshape_names.Length; i++) {
				rig.AddShape(blendshape_names[i]);
			}
			return rig;
		}
Пример #4
0
		void Update () {
		
			bool new_data = false;
			m_mutex.WaitOne();
			// check if there are new blendshape names, and if so update
			if (NewBlendShapeNamesArrived()) {
				m_rig = Rig.GetRigFromBlendShapeNames(GetBlendShapeNames());
			}
	
			// get most recent tracking data
			while (m_data_parser.CountAvailableTracks() > 0) {
				m_current_track = m_data_parser.Dequeue();
				new_data = true;
			}
	
			// check that we have a rig (set up from blendshape names) with the same number of blendshapes as what we receive
			if (m_rig != null && m_current_track != null) {
				int n_track_coefficients = m_current_track.n_coefficients();
				int n_rig_coefficients = m_rig.NumShapes();
				if (n_track_coefficients != n_rig_coefficients) {
					Debug.LogWarning("number of coefficients of rig and tracking state have changed: " + n_track_coefficients + " vs " + n_rig_coefficients);
					// clear the current rig as it is not usable with the data coming from faceshift
					m_rig = null;
					m_current_track = null;
					// get again the blendshapes from fs studio
					AskForBlendshapeNames();
				}
			}
			m_mutex.ReleaseMutex();
	
			if (m_rig != null && m_current_track != null && m_Retargeting != null) {
				if (new_data && m_current_track.TrackSuccess) {
					// create a rig state
					RigState state = new RigState(m_rig);
					state.SetTimestamp(m_current_track.TimeStamp);
					state.SetBoneTranslation(0, m_current_track.HeadTranslation());
					state.SetBoneRotation(0, m_current_track.HeadRotation());
					state.SetBoneRotation(1, m_current_track.LeftEyeRotation());
					state.SetBoneRotation(2, m_current_track.RightEyeRotation());
					for (int i = 0; i < m_rig.NumShapes(); i++) {
						state.SetBlendshapeCoefficient(i, m_current_track.Coefficient[i]);
					}
					
					base.UpdateAnimation(m_rig, state);
				}
			}
		}
Пример #5
0
        //! @brief Loads a faceshift clip
        public void LoadFSB(string path)
        {
            if (!File.Exists(path))
            {
                                #if UNITY_EDITOR
                EditorUtility.DisplayDialog("Clip loading failed", "File " + path + " does exist", "Ok");
                                #endif
                return;
            }

            Clip new_clip = FsbReader.Read(path);
            if (new_clip == null)
            {
                Debug.LogError("could not read clip from file " + path);
                                #if UNITY_EDITOR
                EditorUtility.DisplayDialog("Load failed", "File " + path + " does not contain a clip", "Ok");
                                #endif
                return;
            }

            Rig clip_rig = new_clip.Rig();

            if (IsSourceRigDifferent(clip_rig))
            {
                if ((cachedRigLoaded) && (!SourceRigChangedAskToContinue()))
                {
                    // The user wants to cancel
                    return;
                }
            }

            // always save new rig from the fsb file to have the same order

            // Apply new rig
            m_fs_Rig = clip_rig;

            // Cache new rig
            SaveSourceRig();

            m_clip      = new_clip;
            m_clip_path = path;
        }
Пример #6
0
        /**
         *	Evaluates the target blendshape values based on the state of a rig and a retargeting configuration.
         *  If a blendshape is not affected by the retargeting then the value of this blendshape is null.
         */
        public static BlendshapeValue [] evaluate_target_blendshapes(ClipRetargeting retargeting,
                                                                     Rig rig,
                                                                     RigState state,
                                                                     ArrayList target_blendshapes)
        {
            int n_target_blendshapes = target_blendshapes.Count;

            BlendshapeValue [] values = new BlendshapeValue[n_target_blendshapes];
            // We iterate over the targets and accumulate all sources to them
            for (int index = 0; index < n_target_blendshapes; index++)
            {
                double value       = 0.0;
                int    value_count = 0;
                for (int mapping_nr = 0; mapping_nr < retargeting.get_number_of_blendshape_mappings(); mapping_nr++)
                {
                    string mapping_target = retargeting.get_blendshape_mapping_destination(mapping_nr);
                    if (!mapping_target.Equals(((BlendshapeInfo)target_blendshapes[index]).m_name))
                    {
                        continue;
                    }
                    string mapping_src = retargeting.get_blendshape_mapping_source(mapping_nr);
                    int    src_index   = rig.shape_index(mapping_src);
                    if (src_index >= 0)
                    {
                        double mapping_weight = retargeting.get_blendshape_mapping_weight(mapping_nr);
                        value += state.blendshape_coefficient(src_index) * mapping_weight;
                        value_count++;
                    }
                    else
                    {
                        Debug.Log("Could not find source blend shape '" + mapping_src);
                    }
                }
                // Apply the value for this target
                if (value_count > 0)
                {
                    values[index] = new BlendshapeValue(value);
                }
            }
            return(values);
        }
Пример #7
0
        //! @brief Loads a faceshift clip
        public void LoadFSB(string path)
        {
            if (!File.Exists(path))
            {
                        #if UNITY_EDITOR
                EditorUtility.DisplayDialog("Clip loading failed", "File " + path + " does exist", "Ok");
                        #endif
                return;
            }
            Clip new_clip = FsbReader.read(path);
            if (new_clip == null)
            {
                Debug.LogError("could not read clip from file " + path);
                        #if UNITY_EDITOR
                EditorUtility.DisplayDialog("Load failed", "File " + path + " does not contain a clip", "Ok");
                        #endif
                return;
            }

            Rig clip_rig = new_clip.rig();

            if (!clip_rig.Equals(m_fs_Rig))
            {
                if ((cachedRigLoaded) && (!source_rig_changed_ask_to_continue()))
                {
                    // The user wants to cancel
                    return;
                }

                // Apply new rig
                m_fs_Rig = clip_rig;

                // Cache new rig
                SaveSourceRig();
            }

            m_clip      = new_clip;
            m_clip_path = path;
        }
        /// <summary>
        /// Performs faceshift live tracking animation given a rig and a state.
        /// </summary>
        public void UpdateAnimation(Rig rig, RigState state)
        {
            if (rig == null || state == null)
            {
                return;
            }

            // evaluate joint transformations
            TransformationValue [] transformationsTracking = null;
            if (m_TPose != null && m_TPose.m_joints.Count == m_GameObjectTransformations.Count)
            {
                // evaluate using tpose
                transformationsTracking = Utils.EvaluateTargetTransformations(m_Retargeting, rig, state, m_TPose.m_joints);
            }
            else
            {
                // evaluate using state from start of application
                transformationsTracking = Utils.EvaluateTargetTransformations(m_Retargeting, rig, state, m_GameObjectTransformations);
            }

            if (transformationsTracking != null)
            {
                if (!ApplyTransformations(transformationsTracking, 1.0f))
                {
                    Debug.LogError("Cannot apply tracking transformations as evaluated shape size is incorrect");
                }
            }

            if (state != null)
            {
                BlendshapeValue [] blendshapesTracking = Utils.EvaluateTargetBlendshapes(m_Retargeting, rig, state, m_GameObjectBlendshapes);
                if (!ApplyBlendshapes(blendshapesTracking, 1.0f))
                {
                    Debug.LogError("Cannot apply tracking blendshapes as the number of blendshapes is not the same");
                }
            }
        }
Пример #9
0
        /**
         * @brief Loads an FST retargeting file from faceshift which contains the retargeting information
         * @param[in] path The path to the file
         * @param onlyRig Should only the rig be loaded (true) or also the mapping (false)
         */
        public bool LoadRetargetingFromAsset(TextAsset asset)
        {
            Rig new_rig = new Rig();

            if (!new_rig.load_from_fst(asset.bytes))
            {
                return(false);
            }

            if (!new_rig.Equals(m_fs_Rig))
            {
                if ((cachedRigLoaded) && (!source_rig_changed_ask_to_continue()))
                {
                    // The user wants to cancel
                    return(false);
                }

                // Apply new rig
                m_fs_Rig = new_rig;

                // Cache new rig
                SaveSourceRig();
            }

            ClipRetargeting retargeting = ClipRetargeting.load(asset.bytes);

            if (retargeting != null && !retargeting.isEmpty())
            {
                m_retargeting       = retargeting;
                m_retargeting_asset = asset;
                return(true);
            }
            else
            {
                return(false);
            }
        }
Пример #10
0
        /**
         * @brief Loads an FST file from faceshift which contains the retargeting information
         * @param[in] path The path to the file
         * @param onlyRig Should only the rig be loaded (true) or also the mapping (false)
         */
        public bool LoadRetargetingFromFile(string path)
        {
            Rig new_rig = new Rig();

            if (!new_rig.LoadFromFST(path))
            {
                return(false);
            }

            if (IsSourceRigDifferent(new_rig))
            {
                if (cachedRigLoaded && !SourceRigChangedAskToContinue())
                {
                    // The user wants to cancel
                    return(false);
                }

                // Apply new rig
                m_fs_Rig = new_rig;

                // Cache new rig
                SaveSourceRig();
            }

            ClipRetargeting retargeting = ClipRetargeting.Load(path);

            if (retargeting != null && !retargeting.IsEmpty())
            {
                m_Retargeting      = retargeting;
                m_RetargetingAsset = null;                 // clear asset as we use a file
                return(true);
            }
            else
            {
                return(false);
            }
        }
Пример #11
0
        /**
         * @brief Loads an FST file from faceshift which contains the retargeting information
         * @param[in] path The path to the file
         * @param onlyRig Should only the rig be loaded (true) or also the mapping (false)
         */
        public bool LoadRetargetingFromFile(string path)
        {
            Rig new_rig = new Rig();

            if (!new_rig.load_from_fst(path))
            {
                return(false);
            }

            if (!new_rig.Equals(m_fs_Rig))
            {
                if ((cachedRigLoaded) && (!source_rig_changed_ask_to_continue()))
                {
                    // The user wants to cancel
                    return(false);
                }

                // Apply new rig
                m_fs_Rig = new_rig;

                // Cache new rig
                SaveSourceRig();
            }

            ClipRetargeting retargeting = ClipRetargeting.load(path);

            if (retargeting != null && !retargeting.isEmpty())
            {
                m_retargeting       = retargeting;
                m_retargeting_asset = null;         // clear asset as we use a file
                return(true);
            }
            else
            {
                return(false);
            }
        }
Пример #12
0
		/**
		 *	Evaluates the target transformation based on the state of a rig and a retargeting configuration.
		 *  If a transform is not affected by the retargeting then the value of the transform is null.
		 */
		public static TransformationValue [] EvaluateTargetTransformations(ClipRetargeting retargeting,
		                                                       Rig rig,
		                                                       RigState state,
		                                                       ArrayList target_transformations) {
		                                                       
			if (retargeting == null || rig == null || state == null || target_transformations == null) {
				Debug.LogError("cannot evaluat target transformations as one or more object is null");
				return null;
			}
			
			int n_target_transformations = target_transformations.Count;
			TransformationValue [] values = new TransformationValue[n_target_transformations];
			// We iterate over the target transformations and accumulate all sources to them
			for (int target_nr = 0; target_nr < target_transformations.Count; target_nr++) {
				
				// get original rotation and translation from tpose
				TransformationInformation tpose_joint = target_transformations[target_nr] as TransformationInformation;
				if (tpose_joint == null) {
					Debug.LogError("joint " + target_nr + " is null");
					continue;
				}
				Vector3 tpose_translation               = tpose_joint.localPosition;
				Quaternion tpose_local_rotation         = tpose_joint.localRotation;
				Quaternion tpose_parent_global_rotation = tpose_joint.parentRotation;
				
				Quaternion fs_joint_rotation_local_from_t_pose = Quaternion.identity;
				Vector3 fs_joint_translation_local_from_t_pose = new Vector3(0, 0, 0);
				
				// Sum the translation to apply
				int value_count_trans = 0;
				for (int mapping_nr = 0; mapping_nr < retargeting.GetNumberOfTranslationMappings(); mapping_nr++) {
					string mapping_target = retargeting.GetTranslationMappingDestination (mapping_nr);
					if (!mapping_target.Equals(tpose_joint.transformName)) {
						continue;
					}
					string mapping_src = retargeting.GetTranslationMappingSource (mapping_nr);
					int src_index = rig.BoneIndex (mapping_src);
					if (src_index >= 0) {
						double mapping_weight = retargeting.GetTranslationMappingWeight (mapping_nr);
						fs_joint_translation_local_from_t_pose += state.BoneTranslation (src_index) * (float)mapping_weight;
						value_count_trans++;
					} else {
						Debug.Log ("Could not find source index for '" + mapping_src + "'");
					}
				} 
				
				// Convert translation to global translation
				//Vector3 unity_joint_translation_local = fs_joint_translation_local_from_t_pose + tpose_translation;
				Vector3 unity_joint_translation_local = 
					Quaternion.Inverse(tpose_parent_global_rotation) * fs_joint_translation_local_from_t_pose
					+ tpose_translation;
						
				// Sum the rotations to apply
				int value_count_rot = 0;
				for (int mapping_nr = 0; mapping_nr < retargeting.GetNumberOfRotationMappings(); mapping_nr++) {
					string mapping_target = retargeting.GetRotationMappingDestination (mapping_nr);
					if (!mapping_target.Equals (tpose_joint.transformName)) {
						continue;
					}
					string mapping_src = retargeting.GetRotationMappingSource (mapping_nr);
					int src_index = rig.BoneIndex (mapping_src);
					if (src_index >= 0) {
						double mapping_weight = retargeting.GetRotationMappingWeight (mapping_nr);
						
						// use slerp for weighting
						fs_joint_rotation_local_from_t_pose = Quaternion.Slerp (Quaternion.identity, state.BoneRotation (src_index), (float)mapping_weight);
						// TODO: here we should accumulate if there are more than one sources (like with blendshapes)
						value_count_rot++;
					} else {
						Debug.Log ("Could not find source rotation for '" + mapping_src);
					}
				} 
				
				// Convert to local unity rotation
				Quaternion unity_joint_rotation_local = 
						Quaternion.Inverse(tpose_parent_global_rotation) 
					 		* fs_joint_rotation_local_from_t_pose 
							* tpose_parent_global_rotation
							* tpose_local_rotation; // The initial local rotation;

				if (value_count_trans > 0 || value_count_rot > 0) {
					values[target_nr] = new TransformationValue(unity_joint_rotation_local, unity_joint_translation_local);
				}
			}
			
			return values;
		}
Пример #13
0
	    public bool Equals(Rig other) {
	    
	        if ((m_shapes.Count != other.m_shapes.Count) || (m_bones.Count != other.m_bones.Count)) {
	            return false;
	        }
	
	        // Since we do not have duplicates and we only reach here if we have the same
	        // number of bones and shapes in both rigs, we can check only in one direction with Contains() tests.
	        // The order of the entries does not have to be the same
	        for (int i = 0; i < m_shapes.Count; i++) {
	            if (!m_shapes.Contains(other.m_shapes[i])) {
	                return false;
	            }
	        }
	
	        for (int i = 0; i < m_bones.Count; i++) {
	            if (!m_bones.Contains(other.m_bones[i])) {
	                return false;
	            }
	        }
	
	        return true;
	    }
Пример #14
0
        /**
         *	Evaluates the target transformation based on the state of a rig and a retargeting configuration.
         *  If a transform is not affected by the retargeting then the value of the transform is null.
         */
        public static TransformationValue [] evaluate_target_transformations(ClipRetargeting retargeting,
                                                                             Rig rig,
                                                                             RigState state,
                                                                             ArrayList target_transformations)
        {
            if (retargeting == null || rig == null || state == null || target_transformations == null)
            {
                Debug.LogError("cannot evaluat target transformations as one or more object is null");
                return(null);
            }

            int n_target_transformations = target_transformations.Count;

            TransformationValue [] values = new TransformationValue[n_target_transformations];
            // We iterate over the target transformations and accumulate all sources to them
            for (int target_nr = 0; target_nr < target_transformations.Count; target_nr++)
            {
                // get original rotation and translation from tpose
                TransformationInformation tpose_joint = target_transformations[target_nr] as TransformationInformation;
                if (tpose_joint == null)
                {
                    Debug.LogError("joint " + target_nr + " is null");
                    continue;
                }
                Vector3    tpose_translation            = tpose_joint.localPosition;
                Quaternion tpose_local_rotation         = tpose_joint.localRotation;
                Quaternion tpose_parent_global_rotation = tpose_joint.parentRotation;

                Quaternion fs_joint_rotation_local_from_t_pose    = Quaternion.identity;
                Vector3    fs_joint_translation_local_from_t_pose = new Vector3(0, 0, 0);

                // Sum the translation to apply
                int value_count_trans = 0;
                for (int mapping_nr = 0; mapping_nr < retargeting.get_number_of_translation_mappings(); mapping_nr++)
                {
                    string mapping_target = retargeting.get_translation_mapping_destination(mapping_nr);
                    if (!mapping_target.Equals(tpose_joint.transformName))
                    {
                        continue;
                    }
                    string mapping_src = retargeting.get_translation_mapping_source(mapping_nr);
                    int    src_index   = rig.bone_index(mapping_src);
                    if (src_index >= 0)
                    {
                        double mapping_weight = retargeting.get_translation_mapping_weight(mapping_nr);
                        fs_joint_translation_local_from_t_pose += state.bone_translation(src_index) * (float)mapping_weight;
                        value_count_trans++;
                    }
                    else
                    {
                        Debug.Log("Could not find source index for '" + mapping_src + "'");
                    }
                }

                // Convert translation to global translation
                //Vector3 unity_joint_translation_local = fs_joint_translation_local_from_t_pose + tpose_translation;
                Vector3 unity_joint_translation_local =
                    Quaternion.Inverse(tpose_parent_global_rotation) * fs_joint_translation_local_from_t_pose
                    + tpose_translation;

                // Sum the rotations to apply
                int value_count_rot = 0;
                for (int mapping_nr = 0; mapping_nr < retargeting.get_number_of_rotation_mappings(); mapping_nr++)
                {
                    string mapping_target = retargeting.get_rotation_mapping_destination(mapping_nr);
                    if (!mapping_target.Equals(tpose_joint.transformName))
                    {
                        continue;
                    }
                    string mapping_src = retargeting.get_rotation_mapping_source(mapping_nr);
                    int    src_index   = rig.bone_index(mapping_src);
                    if (src_index >= 0)
                    {
                        double mapping_weight = retargeting.get_rotation_mapping_weight(mapping_nr);

                        // use slerp for weighting
                        fs_joint_rotation_local_from_t_pose = Quaternion.Slerp(Quaternion.identity, state.bone_rotation(src_index), (float)mapping_weight);
                        // TODO: here we should accumulate if there are more than one sources (like with blendshapes)
                        value_count_rot++;
                    }
                    else
                    {
                        Debug.Log("Could not find source rotation for '" + mapping_src);
                    }
                }

                // Convert to local unity rotation
                Quaternion unity_joint_rotation_local =
                    Quaternion.Inverse(tpose_parent_global_rotation)
                    * fs_joint_rotation_local_from_t_pose
                    * tpose_parent_global_rotation
                    * tpose_local_rotation;                                     // The initial local rotation;

                if (value_count_trans > 0 || value_count_rot > 0)
                {
                    values[target_nr] = new TransformationValue(unity_joint_rotation_local, unity_joint_translation_local);
                }
            }

            return(values);
        }
Пример #15
0
		/**
	     * @brief Loads an FST retargeting file from faceshift which contains the retargeting information
	     * @param[in] path The path to the file
	     * @param onlyRig Should only the rig be loaded (true) or also the mapping (false)
	     */
		new public bool LoadRetargetingFromAsset(TextAsset asset) {
		
			Rig new_rig = new Rig();
			if (!new_rig.LoadFromFST(asset.bytes)) return false;
			
			if (IsSourceRigDifferent(new_rig)) {
				if (cachedRigLoaded && !SourceRigChangedAskToContinue()) {
					// The user wants to cancel
					return false;
				}
				
				// Apply new rig
				m_fs_Rig = new_rig;
				
				// Cache new rig
				SaveSourceRig();
			}
			 
			return base.LoadRetargetingFromAsset(asset);
		}
Пример #16
0
		private bool IsSourceRigDifferent(Rig newRig) {
			return !newRig.Equals(m_fs_Rig);
		}
Пример #17
0
        /**
         * @brief Reads an fsb file and returns a clip constructed from the the content of the fsb file.
         * @param[in] data  The binary data from the fsb file.
         * @return A clip with the track data imported from the fsb file, null if there was some error during loading.
         */
        public static Clip Read(byte[] data)
        {
            DataParser parser = new DataParser();

            parser.ExtractData(data, false, 0.0);

            if (parser.Valid())
            {
                Rig rig = new Rig();

                // add hardcoded bone names of fsb file
                rig.AddBone("Neck");
                rig.AddBone("EyeLeft");
                rig.AddBone("EyeRight");

                for (int i = 0; i < parser.fsBlendShapeNames.Length; i++)
                {
                    rig.AddShape(parser.fsBlendShapeNames[i]);
                }

                Clip clip = new Clip(rig);

                while (parser.CountAvailableTracks() > 0)
                {
                    TrackData track_data = parser.Dequeue();

                    if (!track_data.TrackSuccess)
                    {
                        // do not save the state if the tracking data is not valid
                        Debug.LogWarning("this frame doesn't contain valid tracking data");
                        continue;
                    }

                    RigState state = clip.NewState(track_data.TimeStamp);

                    state.SetTrackingSuccessful(track_data.TrackSuccess);

                    if (rig.NumShapes() != track_data.n_coefficients())
                    {
                        Debug.LogError("num blendshapes do not agree in file with " + rig.NumShapes() +
                                       " in rig and " + track_data.n_coefficients() + " in state");
                        return(null);
                    }

                    // Assume the head translation to be joint 0 (Neck)
                    state.SetBoneTranslation(0, track_data.HeadTranslation());

                    // bone indices same as the order when added to the rig
                    state.SetBoneRotation(0, track_data.HeadRotation());
                    state.SetBoneRotation(1, track_data.LeftEyeRotation());
                    state.SetBoneRotation(2, track_data.RightEyeRotation());

                    for (int i = 0; i < track_data.n_coefficients(); i++)
                    {
                        state.SetBlendshapeCoefficient(i, track_data.Coefficient[i]);
                    }
                }

                return(clip);
            }
            else
            {
                Debug.LogError("cannot parse fsb file");
            }

            return(null);
        }
Пример #18
0
 /**
  * @brief Create a new clip with a specific rig.
  * @param[in] rig     The rig of the clip.
  */
 public Clip(Rig rig)
 {
     m_rig    = rig;
     m_states = new List <RigState>();
 }
Пример #19
0
	    public Faceshift()
	    {
			mutexOnTargetBlendshapeList = new Mutex();
	        m_fs_Rig = new Rig();
	        cachedRigLoaded = LoadCachedSourceRig();
	    }
Пример #20
0
	    /**
	     * @brief Create a new clip with a specific rig.
	     * @param[in] rig     The rig of the clip.
	     */
	    public Clip(Rig rig) {
	        m_rig = rig;
	        m_states = new List<RigState>();
	    }
Пример #21
0
        void Update()
        {
            // ten kod kalkuluje bazowa pozycje glowy
            // trzeba jeszcze dorobic zeby przechwytywal trigerra
            // i wtedy zmieniał isBaseCalculated na false
            // i resetował timer i kalkulował jeszcze raz
            // pozniej trzeba jeszcze dodac zeby kazda metoda zwracała
            // to co zwraca minus base
            if (!isBaseCalculated)
            {
                timer += Time.deltaTime;
                if (timer < baseCalculationTime)
                {
                    if (getXHeadRotation() != -1)
                    {
                        baseX += getXHeadRotation();
                        ticksX++;
                    }

                    if (getYHeadRotation() != -1)
                    {
                        baseY += getYHeadRotation();
                        ticksY++;
                    }
                }
                else
                {
                    baseX           /= ticksX;
                    baseY           /= ticksY;
                    isBaseCalculated = true;
                }
            }


            new_data = false;
            m_mutex.WaitOne();
            // check if there are new blendshape names, and if so update
            if (newBlendShapeNamesArrived())
            {
                m_rig = getRigFromBlendShapeNames(getBlendShapeNames());
            }

            // get most recent tracking data
            while (m_data_parser.CountAvailableTracks() > 0)
            {
                m_current_track = m_data_parser.Dequeue();
                new_data        = true;
            }

            // check that we have a rig (set up from blendshape names) with the same number of blendshapes as what we receive
            if (m_rig != null && m_current_track != null)
            {
                int n_track_coefficients = m_current_track.n_coefficients();
                int n_rig_coefficients   = m_rig.num_shapes();
                if (n_track_coefficients != n_rig_coefficients)
                {
                    Debug.LogWarning("number of coefficients of rig and tracking state have changed: " + n_track_coefficients + " vs " + n_rig_coefficients);
                    // clear the current rig as it is not usable with the data coming from faceshift
                    m_rig           = null;
                    m_current_track = null;
                    // get again the blendshapes from fs studio
                    askForBlendshapeNames();
                }
            }
            m_mutex.ReleaseMutex();

            if (m_rig != null && m_current_track != null && m_retargeting != null)
            {
                if (new_data && m_current_track.TrackSuccess)
                {
                    // create a rig state
                    RigState state = new RigState(m_rig);
                    state.set_timestamp(m_current_track.TimeStamp);
                    state.set_bone_translation(0, m_current_track.HeadTranslation());
                    state.set_bone_rotation(0, m_current_track.HeadRotation());
                    state.set_bone_rotation(1, m_current_track.LeftEyeRotation());
                    state.set_bone_rotation(2, m_current_track.RightEyeRotation());

                    for (int i = 0; i < m_rig.num_shapes(); i++)
                    {
                        state.set_blendshape_coefficient(i, m_current_track.Coefficient [i]);
                    }

                    // evaluate joint transformations
                    TransformationValue [] transformation_values = null;
                    if (m_tpose != null && m_tpose.m_joints.Count == m_game_object_transformations.Count)
                    {
                        // evaluate using tpose
                        transformation_values = Utils.evaluate_target_transformations(m_retargeting, m_rig, state, m_tpose.m_joints);
                    }
                    else
                    {
                        // evaluate using state from start of application
                        transformation_values = Utils.evaluate_target_transformations(m_retargeting, m_rig, state, m_game_object_transformations);
                    }

                    if (transformation_values.Length == m_game_object_transformations.Count)
                    {
                        for (int index = 0; index < transformation_values.Length; index++)
                        {
                            // Apply the value for this target
                            if (transformation_values [index] != null)
                            {
                                TransformationInformation joint = m_game_object_transformations [index] as TransformationInformation;
                                joint.transform.localRotation = transformation_values [index].m_rotation;
                                joint.transform.localPosition = transformation_values [index].m_translation;
                            }
                        }
                    }
                    else
                    {
                        Debug.LogError("Cannot create transformation as evaluated shape size is incorrect");
                    }

                    // evaluate blendshape valuesf
                    BlendshapeValue [] values = Utils.evaluate_target_blendshapes(m_retargeting, m_rig, state, m_game_object_blendshapes);

                    if (values.Length == m_game_object_blendshapes.Count)
                    {
                        for (int index = 0; index < m_game_object_blendshapes.Count; index++)
                        {
                            BlendshapeInfo bs_info = m_game_object_blendshapes [index] as BlendshapeInfo;
                            // Apply the value for this target
                            if (bs_info != null && values [index] != null)
                            {
                                bs_info.m_mesh_renderer.SetBlendShapeWeight(bs_info.m_index, (float)values [index].m_value);
                            }
                        }
                    }
                    else
                    {
                        Debug.LogError("Cannot create blendshapes as evaluated shape size is incorrect");
                    }
                }
            }
        }
Пример #22
0
	    /**
	     * @brief Loads an FST file from faceshift which contains the retargeting information
	     * @param[in] path The path to the file
	     * @param onlyRig Should only the rig be loaded (true) or also the mapping (false)
	     */
	    public bool LoadRetargetingFromFile(string path)
	    {
	        Rig new_rig = new Rig();
			if (!new_rig.LoadFromFST(path)) return false;
	
			if (IsSourceRigDifferent(new_rig)) {
	            if (cachedRigLoaded && !SourceRigChangedAskToContinue()) {
	                // The user wants to cancel
	                return false;
	            }
	
	            // Apply new rig
	            m_fs_Rig = new_rig;
	
	            // Cache new rig
	            SaveSourceRig();
	        }
	
	    	ClipRetargeting retargeting = ClipRetargeting.Load(path);
			if (retargeting != null && !retargeting.IsEmpty()) {
				m_Retargeting = retargeting;
				m_RetargetingAsset = null; // clear asset as we use a file
				return true;
			} else {
				return false;
			}   
	    }
Пример #23
0
		/**
		 *	Evaluates the target blendshape values based on the state of a rig and a retargeting configuration.
		 *  If a blendshape is not affected by the retargeting then the value of this blendshape is null.
		 */
		public static BlendshapeValue [] EvaluateTargetBlendshapes(ClipRetargeting retargeting,
						                                             Rig rig,
						                                             RigState state,
						                                             ArrayList target_blendshapes) {
						                                             
			int n_target_blendshapes = target_blendshapes.Count;
			BlendshapeValue [] values = new BlendshapeValue[n_target_blendshapes];
			// We iterate over the targets and accumulate all sources to them
			for (int index = 0; index < n_target_blendshapes; index++) {
				double value = 0.0;
				int value_count = 0;
				for (int mapping_nr = 0; mapping_nr < retargeting.GetNumberOfBlendshapeMappings(); mapping_nr++) {
					string mapping_target = retargeting.GetBlendshapeMappingDestination(mapping_nr);
					if (!mapping_target.Equals(((BlendshapeInfo)target_blendshapes[index]).m_name)) {
						continue;
					}
					string mapping_src = retargeting.GetBlendshapeMappingSource(mapping_nr);
					int src_index = rig.ShapeIndex(mapping_src);
					if (src_index >= 0) {
						double mapping_weight = retargeting.GetBlendshapeMappingWeight(mapping_nr);
						value += state.BlendshapeCoefficient(src_index) * mapping_weight;
						value_count++;
					} else {
						Debug.Log("Could not find source blend shape '" + mapping_src);
					}
				} 
				// Apply the value for this target
				if (value_count > 0) {
					values[index] = new BlendshapeValue(value);
				}
			}
			return values;
		}
Пример #24
0
 /**
  * @brief Create track state with shapes and bones.
  * @param[in] rig The rig for which to create the state.
  */
 public RigState(Rig rig)
 {
     m_blendshape_coefficients = new double[rig.NumShapes()];
     m_bone_translations       = new Vector3[rig.NumBones()];
     m_bone_rotations          = new Quaternion[rig.NumBones()];
 }
Пример #25
0
	    //! @brief Loads a faceshift clip
	    public void LoadFSB(string path) {
	    
			if (!File.Exists (path)) {
				#if UNITY_EDITOR
				EditorUtility.DisplayDialog("Clip loading failed", "File " + path + " does exist", "Ok");
				#endif
				return;
			}
			
	        Clip new_clip = FsbReader.Read(path);
			if (new_clip == null) {
				Debug.LogError("could not read clip from file " + path);
				#if UNITY_EDITOR
				EditorUtility.DisplayDialog("Load failed", "File " + path + " does not contain a clip", "Ok");
				#endif
				return;
			}
	
	        Rig clip_rig = new_clip.Rig();
	
			if (IsSourceRigDifferent(clip_rig)) {
				if ((cachedRigLoaded) && (!SourceRigChangedAskToContinue ())) {
					// The user wants to cancel
					return;
				}
	        }
	
			// always save new rig from the fsb file to have the same order
	
			// Apply new rig
			m_fs_Rig = clip_rig;
			
			// Cache new rig
			SaveSourceRig();
	
	        m_clip = new_clip;
			m_clip_path = path;
	    }
Пример #26
0
 private bool IsSourceRigDifferent(Rig newRig)
 {
     return(!newRig.Equals(m_fs_Rig));
 }
Пример #27
0
	    /**
	     * @brief Create track state with shapes and bones.
	     * @param[in] rig The rig for which to create the state.
	     */
	    public RigState(Rig rig) {
	    
	        m_blendshape_coefficients = new double[rig.NumShapes()];
	        m_bone_translations = new Vector3[rig.NumBones()];
	        m_bone_rotations = new Quaternion[rig.NumBones()];
	    }
Пример #28
0
 public Faceshift()
 {
     mutexOnTargetBlendshapeList = new Mutex();
     m_fs_Rig        = new Rig();
     cachedRigLoaded = LoadCachedSourceRig();
 }
Пример #29
0
		private void ClearCachedRig() {
			m_fs_Rig = new Rig();
		}
Пример #30
0
        //! @brief Save retargeting to file.
        public bool Save(string filename, Rig sourceRig)
        {
            StreamWriter stream = File.CreateText(filename);

            //////////////
            /// Blend shapes
            // Get list of all blend shapes
            List <string> possible_source_blend_shapes = null;

            if (sourceRig != null)
            {
                // We also store the blend shapes that are not connected
                possible_source_blend_shapes = new List <string>();

                for (int i = 0; i < sourceRig.NumShapes(); i++)
                {
                    possible_source_blend_shapes.Add(sourceRig.ShapeName(i));
                }
            }

            // write blendshapes
            foreach (Mapping entry in m_blendshape_mapping)
            {
                stream.WriteLine("bs = " + entry.source + " = " + entry.destination + " = " + entry.weight);
                possible_source_blend_shapes.Remove(entry.source);
            }

            // write not mapped blendshapes
            foreach (string entry in possible_source_blend_shapes)
            {
                stream.WriteLine("bs = " + entry);
            }

            //////////////
            /// Rotations
            // Get list of all rotations
            List <string> possible_source_rotations = null;

            if (sourceRig != null)
            {
                // We also store the rotations that are not connected
                possible_source_rotations = new List <string>();

                for (int i = 0; i < sourceRig.NumBones(); i++)
                {
                    possible_source_rotations.Add(sourceRig.BoneName(i));
                }
            }

            // write rotations
            foreach (Mapping entry in m_rotation_mapping)
            {
                stream.WriteLine("rotation = " + entry.source + " = " + entry.destination + " = " + entry.weight);
                possible_source_rotations.Remove(entry.source);
            }

            // write not mapped rotations
            foreach (string entry in possible_source_rotations)
            {
                stream.WriteLine("rotation = " + entry);
            }

            //////////////
            /// Translations
            // Get list of all translations
            List <string> possible_source_translations = null;

            if (sourceRig != null)
            {
                // We also store the translations that are not connected
                possible_source_translations = new List <string>();

                for (int i = 0; i < sourceRig.NumBones(); i++)
                {
                    possible_source_translations.Add(sourceRig.BoneName(i));
                }
            }

            // write translations
            foreach (Mapping entry in m_translation_mapping)
            {
                stream.WriteLine("translation = " + entry.source + " = " + entry.destination + " = " + entry.weight);
                possible_source_translations.Remove(entry.source);
            }

            // write not mapped translations
            foreach (string entry in possible_source_translations)
            {
                stream.WriteLine("translation = " + entry);
            }

            stream.Close();

            return(true);
        }
Пример #31
0
 private void ClearCachedRig()
 {
     m_fs_Rig = new Rig();
 }
Пример #32
0
        /**
         * @brief Reads an fsb file and returns a clip constructed from the the content of the fsb file.
         * @param[in] filename  The filename of the fsb file.
         * @return A clip with the track data imported from the fsb file, null if there was some error during loading.
         */
        public static Clip read(string filename)
        {
            if (!File.Exists(filename))
            {
                return(null);
            }

            FileStream fileReader = File.OpenRead(filename);
            int        size       = (int)fileReader.Length;

            byte [] data      = new byte[size];
            int     size_read = fileReader.Read(data, 0, size);

            if (size != size_read)
            {
                Debug.LogError("Reading file unsuccessful: read " + size_read + " bytes instead of " + size + " bytes");
                return(null);
            }

            DataParser parser = new DataParser();

            parser.ExtractData(data);

            if (parser.Valid())
            {
                Rig rig = new Rig();

                // add hardcoded bone names of fsb file
                rig.add_bone("Neck");
                rig.add_bone("EyeLeft");
                rig.add_bone("EyeRight");

                for (int i = 0; i < parser.fsBlendShapeNames.Length; i++)
                {
                    rig.add_shape(parser.fsBlendShapeNames[i]);
                }

                Clip clip = new Clip(rig);

                while (parser.CountAvailableTracks() > 0)
                {
                    TrackData track_data = parser.Dequeue();

                    if (!track_data.TrackSuccess)
                    {
                        // do not save the state if the tracking data is not valid
                        Debug.LogWarning("this frame doesn't contain valid tracking data");
                        continue;
                    }

                    RigState state = clip.new_state(track_data.TimeStamp);

                    if (rig.num_shapes() != track_data.n_coefficients())
                    {
                        Debug.LogError("num blendshapes do not agree in file with " + rig.num_shapes() +
                                       " in rig and " + track_data.n_coefficients() + " in state");
                        return(null);
                    }

                    // Assume the head translation to be joint 0 (Neck)
                    state.set_bone_translation(0, track_data.HeadTranslation());

                    // bone indices same as the order when added to the rig
                    state.set_bone_rotation(0, track_data.HeadRotation());
                    state.set_bone_rotation(1, track_data.LeftEyeRotation());
                    state.set_bone_rotation(2, track_data.RightEyeRotation());

                    for (int i = 0; i < track_data.n_coefficients(); i++)
                    {
                        state.set_blendshape_coefficient(i, track_data.Coefficient[i]);
                    }
                }

                return(clip);
            }
            else
            {
                Debug.LogError("cannot parse fsb file");
            }

            return(null);
        }
		/// <summary>
		/// Performs faceshift live tracking animation given a rig and a state.
		/// </summary>
		public void UpdateAnimation(Rig rig, RigState state) {
			
			if (rig == null || state == null) return;
			
			// evaluate joint transformations
			TransformationValue [] transformationsTracking = null;
			if (m_TPose != null && m_TPose.m_joints.Count == m_GameObjectTransformations.Count) {
				// evaluate using tpose
				transformationsTracking = Utils.EvaluateTargetTransformations(m_Retargeting, rig, state, m_TPose.m_joints);
			} else {
				// evaluate using state from start of application
				transformationsTracking = Utils.EvaluateTargetTransformations(m_Retargeting, rig, state, m_GameObjectTransformations);
			}
	
			if (transformationsTracking != null) {
				if (!ApplyTransformations(transformationsTracking, 1.0f)) {
					Debug.LogError("Cannot apply tracking transformations as evaluated shape size is incorrect");
				}
			}
	
			if (state != null) {
				BlendshapeValue [] blendshapesTracking = Utils.EvaluateTargetBlendshapes(m_Retargeting, rig, state, m_GameObjectBlendshapes);
				if (!ApplyBlendshapes(blendshapesTracking, 1.0f)) {
					Debug.LogError("Cannot apply tracking blendshapes as the number of blendshapes is not the same");
				}
			}
		}