void OnEnable() { FacePlus.StartUp(); if (Application.HasProLicense()) // TODO: report pro license required { record = Resources.Load("Record Button") as Texture; stop = Resources.Load("Stop Button") as Texture; play = Resources.Load("Play Button") as Texture; stopPlaying = Resources.Load("Stop Button - Gray") as Texture; } options = new Options() { mode = (Mode)EditorPrefs.GetInt("FacePlus.Options.Mode", (int)Mode.Realtime), recordAudio = EditorPrefs.GetBool("FacePlus.Options.RecordAudio", true), spacebarRecord = EditorPrefs.GetBool("FacePlus.Options.SpacebarRecord", true), warnBeforeDelete = EditorPrefs.GetBool("FacePlus.Options.WarnBeforeDelete", true), requiresConfirmation = EditorPrefs.GetBool("FacePlus.Options.RequiresConfirmation", true), keyframeReduction = EditorPrefs.GetBool("FacePlus.Options.KeyframeReduction", false), smoothTangents = EditorPrefs.GetBool("FacePlus.Options.SmoothTangents", false), changeCamera = EditorPrefs.GetBool("FacePlus.Options.ChangeCamera", false), //flag to change capture device cameraLost = EditorPrefs.GetBool("FacePlus.Options.CameraLost", false) //flag to change capture device }; recordButtonTexture = record; }
public void RecordModule() { for (int i = 0; i < affectedBlendshapes.Length; i++) { string shape = affectedBlendshapes[i]; float[] channelVector = FacePlus.GetCurrentVector(); for (int j = 0; j < channelVector.Length; j++) { string channel = FacePlus.GetChannelName(j); if (shape == channel) { //shaper.channelMapping[channel].Offset *= sensitivity; float amount = 100f / (channelVector[j] + shaper.channelMapping[channel].Offset / 100f); //float s = Mathf.Clamp((amount-100f)/300f, 0f, 1f); //amount = amount * s * s * (3 - 2 * s); //amount = amount * s * s * s* (s*(6*s - 15)+10); shaper.channelMapping[channel].Scale = amount; Debug.Log("recorded " + shape + " scale: " + shaper.channelMapping[shape].Scale + " offset : " + shaper.channelMapping[shape].Offset); } } } }
void SolveSetDrivenKeys() { foreach (Transform j in faceJoints) { Vector3 curTranslate = initialTranslation[j]; Vector3 curRotate = initialRotation[j]; Vector3 curScale = initialScale[j]; for (int i = 0; i < FacePlus.ChannelCount; i++) { string channelName = FacePlus.GetChannelName(i); if (!channelName.Contains("Head_Joint::") && !channelName.Contains("_Eye_Joint::")) { var map = FaceCapture.Instance.channelMapping; if (!map.ContainsKey(channelName)) { return; } curTranslate += Vector3.Lerp(Vector3.zero, (map[channelName] as SetDrivenKeyTarget).deltaTranslate[j], map[channelName].Amount / 100); curRotate += Vector3.Lerp(Vector3.zero, (map[channelName] as SetDrivenKeyTarget).deltaRotate[j], map[channelName].Amount / 100); curScale += Vector3.Lerp(Vector3.zero, (map[channelName] as SetDrivenKeyTarget).deltaScale[j], map[channelName].Amount / 100); } } j.localPosition = curTranslate; j.localRotation = Quaternion.Euler(curRotate); j.localScale = curScale; } }
void DoLogin() { FacePlus.StartUp(); Authentication.Login(user, pass, (msg) => { Debug.Log("Logged in successfully"); shouldStartTracking = true; _login_str = msg; }, (error, message) => { shouldClearLogin = true; login_error_message = error; _login_str = message; }, "Demo"); }
void SetBaseline() { float[] channelVector = FacePlus.GetCurrentVector(); for (int i = 0; i < channelVector.Length; i++) { string channel = FacePlus.GetChannelName(i); if (!channel.Contains("Mix::")) { continue; } if (shaper.channelMapping.ContainsKey(channel)) { shaper.channelMapping[channel].Offset = -channelVector[i] * shaper.channelMapping[channel].Scale; //Debug.Log ("set baseline for " + channel + " as " + channelVector[i]); } } }
void OnGUI() { //Error handling if (FacePlus.HasError && FacePlus.GetError() != "") { faceplus_error_message = FacePlus.GetError(); GUILayout.Window(0, windowRect, ErrorWindow, "Mixamo Face Plus"); } if (Authentication.CanUseFacePlus && FacePlus.IsInitComplete) { return; } windowRect = new Rect(Screen.width / 2 - windowWidth / 2, 3 * Screen.height / 4 - windowHeight / 2, windowWidth, windowHeight); GUILayout.Window(0, windowRect, LoginWindow, "Mixamo Face Plus"); }
void CameraSelectGUI() //handles camera selection { bool changeFlag = false; EditorGUILayout.BeginHorizontal(); GUILayout.Label("Camera:", GUILayout.Width(100)); //Camera selection dropdown int cameraCount = FacePlus.GetCameraCount(); cams = new string[cameraCount]; for (int j = 0; j < cameraCount; j++) { cams[j] = FacePlus.GetCameraDeviceName(j); } if (cams == null || cams.Length < 1) { cams = new string[] { "No Cameras detected" } } ; if (currentCamIndex > cams.Length - 1) { currentCamIndex = 0; } //check for changes in status if (!string.IsNullOrEmpty(currentCam)) { if (currentCam.CompareTo(cams[currentCamIndex]) != 0) { int j; for (j = 0; j < cameraCount; j++) { if (cams[j].CompareTo(currentCam) == 0) { currentCamIndex = j; break; } } //camera no longer exists if (j == cameraCount) { options.cameraLost = true; } } } int index = EditorGUILayout.Popup(currentCamIndex, cams); currentCam = cams[index]; if (index < cams.Length + 1) { //if the camera has changed or been lost if ((index != currentCamIndex) || options.cameraLost) { options.cameraLost = false; options.changeCamera = true; Debug.Log("New Camera Device Selected."); } currentCamIndex = index; } FacePlus.DeviceID = index; EditorGUILayout.EndHorizontal(); } void RealtimeCaptureGUI() { EditorGUILayout.BeginHorizontal(); GUILayout.Label("Microphone:", GUILayout.Width(100)); //Microphone selection dropdown string[] devices = Microphone.devices; mics = new string[devices.Length + 1]; mics[0] = "Disabled"; for (int i = 0; i < devices.Length; i++) { mics[i + 1] = devices[i]; } if (mics == null || mics.Length <= 1) { mics = new string[] { "No microphones detected" } } ; if (EditorPrefs.HasKey("FacePlus.Microphone")) { currentMicIndex = EditorPrefs.GetInt("FacePlus.Microphone"); } if (currentMicIndex > mics.Length - 1) { currentMicIndex = 0; } int index = EditorGUILayout.Popup(currentMicIndex, mics); if (index < mics.Length) { currentMic = mics[index]; currentMicIndex = index; } EditorPrefs.SetInt("FacePlus.Microphone", currentMicIndex); if (currentMic == "No microphones detected" || currentMic == "Disabled") { options.recordAudio = false; } else { options.recordAudio = true; } EditorGUILayout.EndHorizontal(); //camera selection GUI CameraSelectGUI(); // track EditorGUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); // record or stop recording if (character.State == CaptureState.Recording) { if (GUILayout.Button(stop, GUILayout.Width(60)) || SpacePressed()) { if (options.recordAudio) { Microphone.End(currentMic); } character.StopRecording(() => { SaveClip(); SaveAudioClip(); Repaint(); }); } } else { GUI.enabled = character.CanRecord; if (GUILayout.Button(record, GUILayout.Width(60)) || SpacePressed()) { if (!character.Live) { character.StartLiveTracking(); } if (clip != null && clip.length > 1.00f && options.requiresConfirmation) { overwrite = EditorUtility.DisplayDialog("This take will be overwritten!", "You can create a new take to avoid overwriting.", "Record anyway", "Cancel"); if (!overwrite) { return; } overwrite = false; } character.OnStartRecording += StartRecordAudio; //add audiorecord to event so it doesn't go too early character.StartRecording(); Repaint(); } } if (character.State == CaptureState.Playing) { if (GUILayout.Button(stopPlaying, GUILayout.Width(60))) { character.StopPlayback(); PlayBackAudio(false); Repaint(); } } else { GUI.enabled = character.CanPlay; if (GUILayout.Button(play, GUILayout.Width(60))) { character.StartPlayback(); PlayBackAudio(true); Repaint(); } } if (options.changeCamera) { options.changeCamera = false; if (character.State == CaptureState.Live) { FacePlus.StopTracking(); } character.StartLiveTracking(); } if (character != null && character.State == CaptureState.BakingAnimation) { ProgressBar(character.Progress, "Baking Animation"); } else { TimeSliderGUI(); } GUI.enabled = true; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); // GUILayout.Label ("Record Audio:"); // options.recordAudio = EditorGUILayout.Toggle (options.recordAudio, GUILayout.Width (15)); if (character != null) { if (options.mode == Mode.Realtime && !character.Live && Authentication.CanUseFacePlus) { Logger.Info("start live tracking - toggled checkbox"); if (character.Movie != null) { character.Movie.Dispose(); } character.StartLiveTracking(); Logger.Info("done calling startlivetracking"); } } EditorGUILayout.EndHorizontal(); if (GUILayout.Button("Check Minimum Requirements")) { Application.OpenURL("http://hubs.ly/y02VLJ0"); } } void OfflineCaptureGUI() { /*EditorGUILayout.BeginHorizontal(); //Titles Grouping Start * EditorGUILayout.LabelField("Animate from imported movie", EditorStyles.boldLabel); * EditorGUILayout.EndHorizontal(); // Titles Grouping End */ EditorGUILayout.BeginHorizontal(); // Video Select Grouping Start GUILayout.Label("Video:", GUILayout.Width(100)); if (GUILayout.Button("Browse...", GUILayout.Width(70))) { videoPath = EditorUtility.OpenFilePanel("Select your Video", "", ""); } GUILayout.Label(Path.GetFileName(videoPath)); // TODO: Clip the path! EditorGUILayout.EndHorizontal(); // Video Select Grouping End EditorGUILayout.BeginHorizontal(); GUILayout.Label("Frame Rate: ", GUILayout.Width(100)); frameRate = EditorGUILayout.FloatField(frameRate, GUILayout.Width(35)); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); if (character.State == CaptureState.RecordingFromVideo) { if (GUILayout.Button(stop, GUILayout.Width(60)) || SpacePressed() || character.videoFinished) //if video finishes { character.StopRecordingFromVideo(() => { character.videoFinished = false; SaveClip(); Repaint(); }); } } else { GUI.enabled = character.CanRecord; if (GUILayout.Button(record, GUILayout.Width(60)) || SpacePressed()) { if (clip != null && clip.length > 0f && options.requiresConfirmation) { Logger.Info("overwriting"); overwrite = EditorUtility.DisplayDialog("This take will be overwritten!", "You can create a new take to avoid overwriting", "Record anyway", "Cancel"); if (!overwrite) { return; } overwrite = false; } if (!string.IsNullOrEmpty(videoPath)) { var videoFolder = Path.GetDirectoryName(videoPath); var videoFilename = Path.GetFileName(videoPath); character.SetImportMovie(videoFolder, videoFilename); } else // TODO: error about no file selected { } Repaint(); } } if (character.State == CaptureState.PlayingWithVideo) { if (GUILayout.Button(stopPlaying, GUILayout.Width(60))) { character.StopPlaybackWithVideo(); Repaint(); } } else { GUI.enabled = character.CanPlayWithVideo; if (GUILayout.Button(play, GUILayout.Width(60))) { character.StartPlaybackWithVideo(); Repaint(); } } if (character != null && character.State == CaptureState.RecordingFromVideo) { GUI.enabled = true; ProgressBar(character.Progress, "Processing Video: " + character.CurrentVideoFrame + " / " + character.TotalVideoFrames); } else if (character != null && character.State == CaptureState.BakingAnimation) { GUI.enabled = true; ProgressBar(character.Progress, "Baking Animation"); } else { TimeSliderGUI(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); GUI.enabled = true; } void TimeSliderGUI() { GUILayout.BeginVertical(); timeSlider = character.Progress; timeSlider = GUILayout.HorizontalSlider(timeSlider, 0.0f, 1.0f); // 0 - 1 so you can force normalized playback across the timeline GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); var tmp = GUI.enabled; GUI.enabled = true; GUILayout.Label(string.Format("Time: {0,5:##0.0} / {1,2:0.0}", character.ClipPosition, character.ClipLength)); GUI.enabled = tmp; GUILayout.EndHorizontal(); GUILayout.EndVertical(); } void FacePlusErrorGUI() { Color previousContent = GUI.contentColor; EditorGUILayout.BeginHorizontal(); GUI.contentColor = Color.red; GUILayout.Label("Faceplus Error: " + FacePlus.GetError()); EditorGUILayout.EndHorizontal(); GUI.contentColor = previousContent; } void FacePlusMessageGUI() { GUILayout.BeginHorizontal(); GUIStyle style = new GUIStyle(EditorStyles.label); style.wordWrap = true; style.padding = new RectOffset(5, 5, 5, 5); GUILayout.Label(_login_str, style); if (GUILayout.Button("Dismiss")) { _login_str = null; } GUILayout.EndHorizontal(); Divider(); EditorGUILayout.Space(); } void MainGUI() { EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button(displayName, EditorStyles.miniButton)) { Authentication.Logout(); _login_str = null; EditorPrefs.DeleteKey("FacePlus.Password"); password = ""; if (character.State == CaptureState.Live) { character.StopLiveTracking(); } needsRepainting = true; } EditorGUILayout.EndHorizontal(); Divider(); EditorGUILayout.Space(); //Errors if (FacePlus.HasError && FacePlus.GetError() != "") { FacePlusErrorGUI(); } //Messages if (_login_str != null && _login_str != "") { FacePlusMessageGUI(); } //Takes GUILayout.BeginHorizontal(); GUILayout.Label("Current Take:", GUILayout.Width(100)); var newClip = (AnimationClip)EditorGUILayout.ObjectField(clip, typeof(AnimationClip)); GUILayout.EndHorizontal(); // load a clip if the clip changes if (newClip != clip && newClip != null) { clip = newClip; if (character != null && character.channelMapping != null) { character.Load(clip); } } // load a clip if we don't have one already if (character != null && clip != null && !character.HasClip && character.channelMapping != null) { character.Load(clip); } EditorGUILayout.BeginHorizontal(); GUILayout.Label("", GUILayout.Width(100)); if (GUILayout.Button("Create New")) { clip = CreateClip(); } // Disable following buttons when there's no clip. GUI.enabled = clip != null; if (GUILayout.Button("Find in Assets")) { //Find the clip within the Project window in Unity. EditorGUIUtility.PingObject(clip); } GUI.enabled = true; EditorGUILayout.EndHorizontal(); GUILayout.EndVertical(); EditorGUILayout.BeginVertical(); //Super V EditorGUILayout.Space(); if (!EditorApplication.isPlaying) { needsLoginStringCleared = true; if (GUILayout.Button("Start Scene")) { EditorApplication.isPlaying = true; Repaint(); } EditorGUILayout.Space(); } else if (character == null) { GUILayout.Label("Please attach a FaceCapture component to your Character."); } else { Divider(); // Mode Selection Dropdown EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Capture Mode:", GUILayout.Width(100)); int newMode = EditorGUILayout.Popup((int)options.mode, modes); if ((Mode)newMode != options.mode) { // TODO: do cleanup when switching modes if (newMode != (int)Mode.Realtime) { character.StopLiveTracking(); } options.mode = (Mode)newMode; } EditorGUILayout.EndHorizontal(); if (options.mode == Mode.Realtime) { /*if(character.State != CaptureState.Live){ * character.Movie.Dispose(); * }*/ RealtimeCaptureGUI(); } else { OfflineCaptureGUI(); } EditorGUILayout.Space(); } //Divider(); OptionsGUI(); EditorGUILayout.Space(); Divider(); CalibrateGUI(); FuseGUI(); LinkGUI(); } void OnGUI() { autoRepaintOnSceneChange = true; var c = FaceCapture.Instance; if (character == null && c != null && Authentication.CanUseFacePlus) { if (options.mode == Mode.Realtime) { Logger.Info("Starting tracking..."); c.StartLiveTracking(); } } character = c; if (character) { character.OnStopPlayback -= OnPlaybackStopped; character.OnStopPlayback += OnPlaybackStopped; } EditorGUILayout.Space(); GUILayout.BeginVertical(); // 1 if (!Authentication.CanUseFacePlus) { LoginWindow(); } else { MainGUI(); } EditorGUILayout.EndVertical(); } private AnimationClip CreateClip() { string path = EditorUtility.SaveFilePanelInProject("New Animation Clip", FirstAvailableClipName(), "anim", "Where would you like to save this?"); Logger.Info("Got this path to create clip in: " + path); if (!string.IsNullOrEmpty(path)) { AnimationClip emptyClip = new AnimationClip(); #if !UNITY_4_2 AnimationUtility.SetAnimationType(emptyClip, ModelImporterAnimationType.Generic); #endif AssetDatabase.CreateAsset(emptyClip, path); AssetDatabase.Refresh(); Logger.Info("Clip is null? " + (emptyClip == null)); return(emptyClip); } return(null); }
public Dictionary <string, AnimationTarget> CreateMap() { var channelMapping = new Dictionary <string, AnimationTarget>(); //create empty targets for all face joints for (int i = 0; i < FacePlus.ChannelCount; i++) { string channelName = FacePlus.GetChannelName(i); if (!channelName.Contains("Head_Joint::") && !channelName.Contains("_Eye_Joint::")) { Debug.Log("Mapped channel to SDK: " + channelName + " => " + faceJoints); channelMapping.Add(channelName, new SetDrivenKeyTarget(faceJoints)); } } //read preset if any Hashtable sdkDefinition = (Hashtable)JSON.JsonDecode(SDK_Definition.text); if (sdkDefinition != null) { foreach (var sdkKey in sdkDefinition.Keys) { var sdk = (Hashtable)sdkDefinition[sdkKey]; string sdkName = "Mix::" + sdkKey; foreach (var jointKey in sdk.Keys) { var joint = (Hashtable)sdk[jointKey]; //find matching transform Transform jointXform = faceJoints.Where((j) => j.name.ToString() == jointKey.ToString()) .DefaultIfEmpty(null) .LastOrDefault(); if (jointXform == null) { continue; } float dtx = 0f; float dty = 0f; float dtz = 0f; float drx = 0f; float dry = 0f; float drz = 0f; float dsx = 0f; float dsy = 0f; float dsz = 0f; foreach (var attrKey in joint.Keys) { var val = float.Parse(joint[attrKey].ToString()); switch ((attrKey as string)) { case "dtx": dtx = val; break; case "dty": dty = val; break; case "dtz": dtz = val; break; case "drx": drx = val; break; case "dry": dry = val; break; case "drz": drz = val; break; case "dsx": dsx = val; break; case "dsy": dsy = val; break; case "dsz": dsz = val; break; } } //set mapping (channelMapping[sdkName] as SetDrivenKeyTarget).deltaTranslate[jointXform] = new Vector3(dtx, dty, dtz); (channelMapping[sdkName] as SetDrivenKeyTarget).deltaRotate[jointXform] = new Vector3(drx, dry, drz); (channelMapping[sdkName] as SetDrivenKeyTarget).deltaScale[jointXform] = new Vector3(dsx, dsy, dsz); } } } // Head rotation if (headJoint != null) { channelMapping.Add("Head_Joint::Rotation_X", new JointTarget("Head_Joint::Rotation_X", TransformComponent.LocalRotationX, headJoint)); channelMapping.Add("Head_Joint::Rotation_Y", new JointTarget("Head_Joint::Rotation_Y", TransformComponent.LocalRotationY, headJoint, -1.0f)); channelMapping.Add("Head_Joint::Rotation_Z", new JointTarget("Head_Joint::Rotation_Z", TransformComponent.LocalRotationZ, headJoint, -1.0f)); // animation requires the w component, but we are animating with euler angles, // so need to add a dummy channel to capture w channelMapping.Add("Head Joint W", new JointTarget("Head Joint W", TransformComponent.LocalRotationW, headJoint)); } // Left Eye if (leftEye != null) { channelMapping.Add("Left_Eye_Joint::Rotation_X", new JointTarget("Left_Eye_Joint::Rotation_X", TransformComponent.LocalRotationX, leftEye)); channelMapping.Add("Left_Eye_Joint::Rotation_Y", new JointTarget("Left_Eye_Joint::Rotation_Y", TransformComponent.LocalRotationY, leftEye, -1.0f)); channelMapping.Add("Left Eye Z", new JointTarget("Left Eye Z", TransformComponent.LocalRotationZ, leftEye)); channelMapping.Add("Left Eye W", new JointTarget("Left Eye W", TransformComponent.LocalRotationW, leftEye)); } // Right Eye if (rightEye != null) { channelMapping.Add("Right_Eye_Joint::Rotation_X", new JointTarget("Right_Eye_Joint::Rotation_X", TransformComponent.LocalRotationX, rightEye)); channelMapping.Add("Right_Eye_Joint::Rotation_Y", new JointTarget("Right_Eye_Joint::Rotation_Y", TransformComponent.LocalRotationY, rightEye, -1.0f)); channelMapping.Add("Right Eye Z", new JointTarget("Right Eye Z", TransformComponent.LocalRotationZ, rightEye)); channelMapping.Add("Right Eye W", new JointTarget("Right Eye W", TransformComponent.LocalRotationW, rightEye)); } // Add all the face joints, so their values get recorded foreach (var joint in faceJoints) { channelMapping.Add(joint.name + " r.x", new JointTarget(joint.name + " r.x", TransformComponent.LocalRotationX, joint)); channelMapping.Add(joint.name + " r.y", new JointTarget(joint.name + " r.y", TransformComponent.LocalRotationY, joint)); channelMapping.Add(joint.name + " r.z", new JointTarget(joint.name + " r.z", TransformComponent.LocalRotationZ, joint)); channelMapping.Add(joint.name + " r.w", new JointTarget(joint.name + " r.w", TransformComponent.LocalRotationW, joint)); /* * channelMapping.Add (joint.name + " s.x", * new JointTarget(joint.name + " s.x", TransformComponent.LocalScaleX, joint)); * channelMapping.Add (joint.name + " s.y", * new JointTarget(joint.name + " s.y", TransformComponent.LocalScaleY, joint)); * channelMapping.Add (joint.name + " s.z", * new JointTarget(joint.name + " s.z", TransformComponent.LocalScaleZ, joint)); */ channelMapping.Add(joint.name + " p.x", new JointTarget(joint.name + " p.x", TransformComponent.LocalPositionX, joint)); channelMapping.Add(joint.name + " p.y", new JointTarget(joint.name + " p.y", TransformComponent.LocalPositionY, joint)); channelMapping.Add(joint.name + " p.z", new JointTarget(joint.name + " p.z", TransformComponent.LocalPositionZ, joint)); /**/ } return(channelMapping); }