Howdy, Stranger!

It looks like you're new here. Sign in or register to get started.

If you have any questions, reports, suggestions, or requests about Live2D, please send them to this forum.
※We cannot guarantee statements or answers from Live2D staff. Thank you for your understanding in advance.
 
Live2D Cubism
Cubism Products and Downloads
Cubism product manuals and tutorials
Cubism Editor Manual    Cubism Editor Tutorial    Cubism SDK Manual    Cubism SDK Tutorial
[About macOS Sequoia] (Updated October 22, 2024)
Live2D Cubism Editor 5.1.02 now supports macOS Sequoia.
Other Live2D Cubism products currently released are not guaranteed to work on macOS Sequoia.
Please refrain from upgrading macOS, as it may not operate properly.

Have automatic blinking/breathing.

edited December 2023 in Help
Hello!

How do I make a character have automatic blinking and breathing? I have made a variant of the SDK's SimpleModel.cs and I use .mtn files to change the pose and show emotions, but after the animation is played, the character stays still and stiff. I'd be very thankful if someone could tell me how to have her appear alive with breathing and blinking.

Comments

  • edited March 2016
    There is a blinking and breathing function in SimpleModel.cs of Demo project .
    You can make automatic blinking and breathing the following code .
    // Breath
    double timeSec = UtSystem.getUserTimeMSec() / 1000.0;
    double t = timeSec * 2 * Math.PI;
    live2DModel.setParamFloat("PARAM_BREATH", (float)(0.5f + 0.5f * Math.Sin(t / 3.0)));
    
    // EYE Blink
    eyeBlink.setParam(live2DModel);
    
  • I added it in, and it works! Thank you naotaro!
  • I have run into an issue with the blinking. After the blink happens, the eyes become 100% open, and they stay like that. Is there a way to fix it?

  • I see.
    In the case of you , it is better not to use the EyeBlink function .
    There was EyeBlink motion function in Live2D Animator .

    I think that good to make motion with Live2D Animator !
  • edited April 2016
    Ah. This is certainly a good approach to the problem. I am thankful for the information you've given me, however, I would prefer to find a coded solution. Or is it just impossible to achieve this kind of coded eyeblink result with the current SDK? If it is so, well, then there is nothing to do... But if not, then something can be done.

    My models look like this in the game:

    Normal open (0.5)

    Semi-open (aproximately 0.3)

    Wide open (1.0)

    As shown, the eye "open" parameter value depends on what .mtn is loaded into the model. I'm using the SimpleModel.cs as a base.

    Perhaps I need to use a different base?
  • I found a solution to the problem and use the multParamFloat Function .


    I test code is as follows .
    double t = (UtSystem.getUserTimeMSec()/1000.0) * 2 * Math.PI  ;
    live2DModel.setParamFloat( "PARAM_ANGLE_X" , (float) (30 * Math.Sin( t/3.0 )) ) ;
    // EYE Blink
    eyeBlink.setParam(live2DModel);
    live2DModel.multParamFloat("PARAM_EYE_R_OPEN", 0.6f);
    
    Please try to adjust the value .
    001.gif 662.6K
  • edited April 2016
    Yes! I believe that this is a better and an improved solution, and I greatly appreciate your post, however, it is still not quite what I'm looking for. I will explain with some graphs:

    Here is an eye parameter without any blinking:


    This is what I am looking for:


    This is what your code currently does.


    So, the "eyeblink-down" works well. The problem is the "eyeblink-up". It needs to return to the "original" curve.

    Is a way to achieve that?

    If there is no different or better way to achieve the result I'm looking for, I have two ideas. I'd like to know which one would be more wise for me to choose. Please note that I really really want to find a coded and more elegant solution than these ideas I have, but I'm determined to achieve the eyeblink result.

    Idea 1:

    Would it be possible to create a "ghost" of the eyeblink parameter, which doesn't blink, and then a "real" version that blinks?



    The ghost is the eyeblink value without any blinking. The on-screen blinking will take the Ghost value when it is not blinking, but when the blinking motion is activated, it will do the blink and ignore the Ghost value, until it returns to it.

    Idea 2:



    I could make an additional parameter called "Force Blinking", which looks like the chart above, and then control the blinking through it by having the value of "Force Blinking" change from 1.0 to 0.0 and then back at random moments, like normal blinking.


    I repeat that I would much prefer to find a simpler and coded solution, but I am currently not knowledgeable enough in coding and Live2D's SDK to know how to do it in a better way, so please forgive my clumsiness.

    I deeply appreciate the input until now, and thank you in advance for reading my long post.
  • @CBeam
    Thanks for the detailed explanation. As naotaro pointed out multParamFloat() should be the way to go. But this might be an issue with the framework. Could you replace the the file in the framework with the one attached to this message and check whether it works better?

    In your own code use the initial version naotaro posted, i.e.:
    // Breath double timeSec = UtSystem.getUserTimeMSec() / 1000.0; double t = timeSec * 2 * Math.PI; live2DModel.setParamFloat("PARAM_BREATH", (float)(0.5f + 0.5f * Math.Sin(t / 3.0))); // EYE Blink eyeBlink.setParam(live2DModel);

    Please let me know if that worked.
  • edited April 2016
    @andi.g@live2d

    I'm sorry, but your proposed code does not work. The cs file you have linked me is missing the "setParam" function which you're asking me to add.



    However, "updateParam()" does exist, so I've tried with "eyeBlink.updateParam(live2DModel)" instead.

    That didn't work either. Full experience and testing with this in the spoiler.

    The eye would just remain closed once the blink happened, never opening again until another .mtn was activated.




    I tried adding a Debug.Log() to every switch case within the EyeBlink code and then I ran it, but without "Debug.Log("EyeStateInterval")" because it was too spammy (https://i.gyazo.com/7fa6857f21d74a318d19cacd59c9170b.png). I got the following:


    I tried changing "MultParamfloat" to "SetParamFloat", and it worked!...But I got the 100% open eye problem again.



    Does the "Mult" in MultParamfloat mean Multiply? Maybe the eyes remain closed because once the eyes are at 0, the eyeblink is then multiplying something by zero to open it again and getting more zero?

  • edited April 2016
    I deeply appreciate the help until now, @andi.g@live2d and @naotaro, thank you. I've had a bit of an "Eureka" moment and I have managed to code my own solution, and it works.

    Since "SetParam" works, but had the 100% eye-open problem, what I did was to adjust to what value the SetParam reached upon performing the eye-opening action by setting it to be what value it has when motionMgr.isFinished() is called. My solution unfortunately doesn't work for mtns that are being played live due to that, but the result still looks natural and a couple of my motions actually implement blinking as part of the emotion being shown (especially in the Tsundere's case, example here: http://i.imgur.com/Oqw9gzO.gif, as she condescends people or blinks repeatedly while being flustered and blushing). So it's a feature that works in my favor, since automated blinking without that feature could've interfered with the expression.

    Here it is if you'd like to check it out. It's a variation of the regular L2DEyeblink but its within the Model's cs file.


    in Update()
    if (motionMgr.isFinished() && !idling)
    {
    idling = true;
    Debug.Log("It's Finished");
    MyEyeState = EyeState.First;
    eyeL_base = live2DModel.getParamFloat("PARAM_EYE_L_OPEN");
    eyeR_base = live2DModel.getParamFloat("PARAM_EYE_R_OPEN");
    }

    if (idling)
    UpdateEyes();


    Additional functions
    void AssignEyes(float EyeL, float EyeR)
    {
    eyeL_base = EyeL;
    eyeR_base = EyeR;
    }

    public long calcNextBlink()
    {
    long time = UtSystem.getUserTimeMSec();
    double r = UtMath.randDouble();//0..1
    return (long)(time + r * (2 * blinkIntervalMsec - 1));
    }

    void UpdateEyes()
    {
    long time = UtSystem.getUserTimeMSec();
    float multiplier = 0;
    float t = 0;

    switch (MyEyeState)
    {
    case EyeState.Closing:

    t = (time - stateStartTime) / (float)closingMotionMsec;
    if (t >= 0)
    {
    t = 1;
    MyEyeState = EyeState.Closed;
    stateStartTime = time;
    }
    break;
    case EyeState.Closed:

    t = (time - stateStartTime) / (float)closedMotionMsec;
    if (t >= 1)
    {
    MyEyeState = EyeState.Opening;//j/ 次から開き始める
    stateStartTime = time;
    }
    multiplier = 0;//j/ 閉じた状態
    break;
    case EyeState.Opening:

    t = ((time - stateStartTime) / (float)openingMotionMsec);
    if (t >= 1)
    {
    t = 1;
    MyEyeState = EyeState.Interval;
    nextBlinkTime = calcNextBlink();
    }
    multiplier = t;
    break;
    case EyeState.Interval:
    if (this.nextBlinkTime < time)
    {
    MyEyeState = EyeState.Closing;
    stateStartTime = time;
    }
    multiplier = 1;
    break;
    case EyeState.First:
    default:

    MyEyeState = EyeState.Interval;
    nextBlinkTime = calcNextBlink();
    multiplier = 1;
    break;

    }


    live2DModel.setParamFloat("PARAM_EYE_L_OPEN", (float)eyeL_base * multiplier);
    live2DModel.setParamFloat("PARAM_EYE_R_OPEN", (float)eyeR_base * multiplier);
    }

  • Cool that you found a solution. I'm going to look into it again next week if that's fine for you.
Sign In or Register to comment.