EVMC4U and EasyMotionRecorder complete hack for VMC protocol live capture in a Window

This is a COMPLETE HACK, but in case anyone comes across this thread from the EVMC4U (EasyVirtualMotionCaptureForUnity) reference, I hacked a copy of the code to run in a Unity Window instead of as a Component, then merged in parts of EasyMotionRecorder. By doing that I was able to capture animation clips without leaving Editor mode. While embarrassed at the complete hack, sharing here (https://gist.github.com/alankent/ee46bb20adce9c09be1a47dcb1179f91) in case useful to anyone who wants to clean it up.

But it means I can drag a character into a window field, click a single button to start receiving VMC events, then click another button to start/stop recording an animation clip. Sometimes I have to restart Unity (I am probably not managing the background VMC protocol receiving thread lifecycle correctly), but not having to enter Play mode is saving me time.

7566577--936649--upload_2021-10-12_8-34-56.png

To be clear, this is unrelated to the Unity live capture tools. I am using some older tools more common in the VRoid Studio / VTuber community. I am not saying the VMC protocol is better, just that some people have set ups using it already - e.g. for their VTuber channel.

Why did I copy and hack so much code? Unfortunately the original code had assumptions built in about being a Component (e.g. to find the Animator component). So I quickly copied those classes into my class, then made a few little tweaks so it could run as a Window and changed a few defaults to reduce the number of settings in the Window (I don’t need to change them). The “right” solution would be to suggest some code refactoring back to the original projects so more code was in separate classes, allowing it to be shared between Component and Window usage.

But the end result is I can capture .anim files for use with the Unity Sequences package much quicker now without having to enter “Play” mode to capture a recording.

I think I hit that one before, but cannot remember the details... The source code is here. https://github.com/neon-izm/EasyMotionRecorder/blob/master/EasyMotionRecorder/Assets/EasyMotionRecorder/Scripts/MotionDataRecorder.cs#L167 Line 167 is trying to add something to the "Poses" field, but something is not initialized... and I don't know why.

So this is just some random suggestions sorry:

  • I notice there are three warnings in the console that are hidden. Are they anything relevant? (Could you share them in case?)
  • Could you try not nesting the objects? I have ExternalReceiver with its children, then as siblings EasyMotionRecorder and the character model (Base 1 in your case). I am just wondering if initialization sequences are affected for some reason.
    7592113--941467--upload_2021-10-21_14-7-52.png

  • Does you model have an avatar description? I am using VRoid Studio (I realize you are not), and it has the following components, which includes a reference to an Avatar Description.
    7592113--941473--upload_2021-10-21_14-10-25.png
    The Avatar Description I have (created by VRoid Studio) maps bones to Avatar bones.
    7592113--941476--upload_2021-10-21_14-11-34.png

  • Do other avatar animation clips work with your model? Just trying to eliminate possible problems.

I don't see what is going wrong. I don't know if you have a programming background, but walking through the code there is an Update() function that watches for the "R" and "X" key presses. The "R" key press (line 78) calls RecordStart() (line 174), which initalizes "Poses" line 182. "_recording" should never be set to "true" unless this happens. The LateUpdate() function (called per frame sometime after Update()) is then serializing the pose information and adding it to the Poses list (which is failing).

If you are up to it (sorry, not sure of your background!), what can help is to edit the MotionDataRecorder.cs file (the path name is in the stack trace you shared) and add Debug.Log(Poses); to line 167 so its like:

Line 167: Debug.Log(Poses); Poses.Poses.Add(serializedPose);

I get the following Console output:
7592113--941479--upload_2021-10-21_14-20-26.png

I am wondering if you get the same, or you get "null" instead of "(Entum.HumanoidPoses)". If its not null, try Debug.Log(Poses.Poses); and try again. This will help work out if Poses is null or Poses.Poses (the member of the Poses object). Feel free to also try Debug.Log(serializedPose); as well. Is it null?

Basically something on that line has a null value - "Poses", "Poses.Poses", or "serializedPose" - just trying to work out which one of the three is null. That might give a hint as to the next step to explore.

(But bottom line is I cannot see what is going wrong.)

7592113--941470--upload_2021-10-21_14-8-54.png

Hi! Remote debugging is always painful sorry. A few more things to try.

Could you try downloading UnityChan (free asset from Unity asset store). Try doing motion recording on that character instead. If that works, it means its something inside your model that needs to be adjusted.

Do you know how to create a timeline and add animation clips to it? That would be another test. I would first create a timeline, put UnityChan in a scene, drag Unity chan into the timeline window and create a "animation track", then drag an animation clip into the timeline track for Unity chan (she comes with animation clips from asset store as well). You should be able to preview the timeline on the character (in editor mode). If that works, repeat for your own character. Does that work? This will demonstrate that animation clips can work on your character (ignoring easy motion recorder etc). Note: there are lots of YouTube videos showing the above if you have not done it before.

Did you manage to confirm your animator has the avatar set? If the avatar description is not correct that is the sort of thing that could go wrong. (I am hoping the above steps will also confirm the character is correctly set up with an avatar.)

Did you manage to get the Debug statements in? You probably need to stop and hit play again for the changes to be picked up and used. I was hoping to get a copy of the output of the debug messages. It should print something to the console. (I note there was a console message hidden, the first of the three buttons in top right corner was not pressed.) But using UnityChan I would suggest first.

Oh, the "_animator = null" bit I assume you meant "_animator == null"? The two equals signs is a check for null. It should bomb out quickly with a debug message in the log if not set. It is mandatory your character has an animator, but I think it does or you would not have been able to put your model in the easy motion recorder property. I am more wondering if the avatar property of the animator is not set.