private void FacialFrameToBuffer([NotNull] Dictionary <string, float> map, [NotNull] float[] buffer)
        {
            var currentTime = playerControl.relativeTime;

            foreach (var kv in map)
            {
                var index = Array.IndexOf(_blendShapeNamesFastLookup, kv.Key);

                if (index >= 0)
                {
                    Debug.Assert(index >= LipSyncCount);

                    float value;

                    do
                    {
                        if (EyesFilteredMorphs.Contains(kv.Key))
                        {
                            value = 0;
                            break;
                        }

                        if (EyesAffectedMorphs.Contains(kv.Key))
                        {
                            if (_currEyeClosed)
                            {
                                value = 0;
                                break;
                            }
                            else if (currentTime < _eyeCloseStartTime + HalfEyeBlinkTime)
                            {
                                value = 0;
                                break;
                            }
                        }

                        value = kv.Value * 100;
                    } while (false);

                    buffer[index - LipSyncCount] = value;
                }
            }
        }
示例#2
0
        private VmdFacialFrame[] CreateFacialExpressionFrames([NotNull] ScenarioObject facialExpr, int formationNumber)
        {
            var frameList = new List <VmdFacialFrame>();

            var expControls = facialExpr.Scenario.WhereToArray(s => s.Type == ScenarioDataType.FacialExpression && s.Idol == formationNumber - 1);

            Debug.Assert(expControls.Length > 0, "Expression controls should exist.");

            var mappings = _conversionConfig.FacialExpressionMappings;

            // Note that here we don't process blinks (which happens in MLTD)
            for (var i = 0; i < expControls.Length; i++)
            {
                var exp         = expControls[i];
                var currentTime = (float)exp.AbsoluteTime;

                bool areEyesOpen;

                var eyesClosedRatio = exp.EyeClosed ? 1.0f : 0.0f;

                frameList.Add(CreateFacialFrame(currentTime, "E_metoji_r", eyesClosedRatio));
                frameList.Add(CreateFacialFrame(currentTime, "E_metoji_l", eyesClosedRatio));

                if (i > 0)
                {
                    if (expControls[i - 1].EyeClosed != exp.EyeClosed)
                    {
                        frameList.Add(CreateFacialFrame(currentTime - HalfEyeBlinkTime, "E_metoji_r", 1 - eyesClosedRatio));
                        frameList.Add(CreateFacialFrame(currentTime - HalfEyeBlinkTime, "E_metoji_l", 1 - eyesClosedRatio));
                    }
                }

                if (exp.EyeClosed)
                {
                    areEyesOpen = false;
                }
                else
                {
                    do
                    {
                        if (i > 0)
                        {
                            if (expControls[i - 1].EyeClosed)
                            {
                                areEyesOpen = false;
                                break;
                            }
                        }

                        if (i < expControls.Length - 1)
                        {
                            if (expControls[i + 1].EyeClosed)
                            {
                                if (currentTime >= expControls[i + 1].AbsoluteTime - HalfEyeBlinkTime)
                                {
                                    areEyesOpen = false;
                                    break;
                                }
                            }
                        }

                        areEyesOpen = true;
                    } while (false);
                }

                {
                    // The key associated with a group of morph values, representing a whole facial expression
                    var expressionKey = exp.Param;

                    if (!mappings.ContainsKey(expressionKey))
                    {
                        Trace.TraceWarning("Facial expression key {0} is not found (at time {1}), using default emotion instead.", exp.Param, currentTime);

                        expressionKey = 0;
                    }

                    foreach (var kv in mappings[expressionKey])
                    {
                        var morphName = kv.Key;

                        if (EyesFilteredMorphs.Contains(morphName))
                        {
                            continue;
                        }

                        if (EyesAffectedMorphs.Contains(morphName) && !areEyesOpen)
                        {
                            continue;
                        }

                        frameList.Add(CreateFacialFrame(currentTime, morphName, kv.Value));
                    }

                    // TODO: There is still one problem though, if an eye morph (say, E_wink_l) is activated BEFORE blinking, there is still a disaster.
                    //       But I am not sure how to handle that case. If that happens, it probably means something went wrong in animation directing.
                    //       Logical animations won't let you blink while you are winking.

                    if (i > 0)
                    {
                        if (expControls[i - 1].Param != exp.Param)
                        {
                            var lastExpressionKey = expControls[i - 1].Param;

                            if (!mappings.ContainsKey(lastExpressionKey))
                            {
                                Trace.TraceWarning("Facial expression key {0} is not found (at time {1}), using default emotion instead.", expControls[i - 1].Param, (float)expControls[i - 1].AbsoluteTime);

                                lastExpressionKey = 0;
                            }

                            var expectedTransitionStartTime = currentTime - FacialExpressionTransitionTime;

                            foreach (var kv in mappings[lastExpressionKey])
                            {
                                var morphName = kv.Key;

                                if (EyesFilteredMorphs.Contains(morphName))
                                {
                                    continue;
                                }

                                if (EyesAffectedMorphs.Contains(morphName) && !areEyesOpen)
                                {
                                    continue;
                                }

                                // So... do we have to "restore" some morphs after blinking? I think not. Otherwise it will become very strange.
                                frameList.Add(CreateFacialFrame(expectedTransitionStartTime, morphName, kv.Value));
                            }
                        }
                    }
                }
            }

            return(frameList.ToArray());
        }