live2D (sdk가 6.5 미지원으로 sprite로 대응)
This commit is contained in:
526
Assets/Live2D/Cubism/Framework/Physics/CubismPhysicsSubRig.cs
Normal file
526
Assets/Live2D/Cubism/Framework/Physics/CubismPhysicsSubRig.cs
Normal file
@@ -0,0 +1,526 @@
|
||||
/**
|
||||
* Copyright(c) Live2D Inc. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by the Live2D Open Software license
|
||||
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
|
||||
*/
|
||||
|
||||
|
||||
using Live2D.Cubism.Core;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace Live2D.Cubism.Framework.Physics
|
||||
{
|
||||
/// <summary>
|
||||
/// Children of rig.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class CubismPhysicsSubRig
|
||||
{
|
||||
/// <summary>
|
||||
/// Name.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public string Name;
|
||||
|
||||
/// <summary>
|
||||
/// Input.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public CubismPhysicsInput[] Input;
|
||||
|
||||
/// <summary>
|
||||
/// Original Input.
|
||||
/// </summary>
|
||||
[NonSerialized]
|
||||
public CubismPhysicsInput[] OriginalInput;
|
||||
|
||||
/// <summary>
|
||||
/// Output.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public CubismPhysicsOutput[] Output;
|
||||
|
||||
/// <summary>
|
||||
/// Original Output.
|
||||
/// </summary>
|
||||
[NonSerialized]
|
||||
public CubismPhysicsOutput[] OriginalOutput;
|
||||
|
||||
/// <summary>
|
||||
/// Particles.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public CubismPhysicsParticle[] Particles;
|
||||
|
||||
/// <summary>
|
||||
/// Normalization.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public CubismPhysicsNormalization Normalization;
|
||||
|
||||
/// <summary>
|
||||
/// Rig.
|
||||
/// </summary>
|
||||
public CubismPhysicsRig Rig
|
||||
{
|
||||
get { return _rig; }
|
||||
set { _rig = value; }
|
||||
}
|
||||
|
||||
[NonSerialized]
|
||||
private CubismPhysicsRig _rig;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Output result of physics operations before applying to parameters.
|
||||
/// </summary>
|
||||
private struct SubRigPhysicsOutput
|
||||
{
|
||||
public float[] Output;
|
||||
}
|
||||
|
||||
[NonSerialized]
|
||||
private SubRigPhysicsOutput _currentRigOutput; // Results of the latest pendulum calculation.
|
||||
|
||||
[NonSerialized]
|
||||
private SubRigPhysicsOutput _previousRigOutput; // Result of previous pendulum calculation.
|
||||
|
||||
/// <summary>
|
||||
/// Applies the specified weights from the latest and one previous result of the pendulum operation.
|
||||
/// </summary>
|
||||
/// <param name="weight">Weight of latest results.</param>
|
||||
public void Interpolate(float weight)
|
||||
{
|
||||
// Load input parameters.
|
||||
for (int i = 0; i < Output.Length; ++i)
|
||||
{
|
||||
if (Output[i].Destination == null)
|
||||
{
|
||||
var destination = Rig.Controller.Parameters.FindById(Output[i].DestinationId);
|
||||
if (destination == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Output[i].Destination = destination;
|
||||
}
|
||||
|
||||
UpdateOutputParameterValue(
|
||||
Output[i].Destination,
|
||||
ref Output[i].Destination.Value,
|
||||
_previousRigOutput.Output[i] * (1 - weight) + _currentRigOutput.Output[i] * weight,
|
||||
Output[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates parameter from output value.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Target parameter.</param>
|
||||
/// <param name="parameterValue">Target parameter Value.</param>
|
||||
/// <param name="translation">Translation.</param>
|
||||
/// <param name="output">Output value.</param>
|
||||
private void UpdateOutputParameterValue(CubismParameter parameter, ref float parameterValue, float translation, CubismPhysicsOutput output)
|
||||
{
|
||||
var outputScale = 1.0f;
|
||||
|
||||
outputScale = output.GetScale();
|
||||
|
||||
var value = translation * outputScale;
|
||||
|
||||
|
||||
if (value < parameter.MinimumValue)
|
||||
{
|
||||
if (value < output.ValueBelowMinimum)
|
||||
{
|
||||
output.ValueBelowMinimum = value;
|
||||
}
|
||||
|
||||
|
||||
value = parameter.MinimumValue;
|
||||
}
|
||||
else if (value > parameter.MaximumValue)
|
||||
{
|
||||
if (value > output.ValueExceededMaximum)
|
||||
{
|
||||
output.ValueExceededMaximum = value;
|
||||
}
|
||||
|
||||
|
||||
value = parameter.MaximumValue;
|
||||
}
|
||||
|
||||
|
||||
var weight = (output.Weight / CubismPhysics.MaximumWeight);
|
||||
|
||||
if (weight >= 1.0f)
|
||||
{
|
||||
parameterValue = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = (parameterValue * (1.0f - weight)) + (value * weight);
|
||||
parameterValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Updates particles in every frame.
|
||||
/// </summary>
|
||||
/// <param name="strand">Particles.</param>
|
||||
/// <param name="totalTranslation">Total translation.</param>
|
||||
/// <param name="totalAngle">Total angle.</param>
|
||||
/// <param name="wind">Direction of wind.</param>
|
||||
/// <param name="thresholdValue">Value of threshold.</param>
|
||||
/// <param name="deltaTime">Time of delta.</param>
|
||||
private void UpdateParticles(
|
||||
CubismPhysicsParticle[] strand,
|
||||
Vector2 totalTranslation,
|
||||
float totalAngle,
|
||||
Vector2 wind,
|
||||
float thresholdValue,
|
||||
float deltaTime
|
||||
)
|
||||
{
|
||||
strand[0].Position = totalTranslation;
|
||||
|
||||
var totalRadian = CubismPhysicsMath.DegreesToRadian(totalAngle);
|
||||
var currentGravity = CubismPhysicsMath.RadianToDirection(totalRadian);
|
||||
currentGravity.Normalize();
|
||||
|
||||
for (var i = 1; i < strand.Length; ++i)
|
||||
{
|
||||
strand[i].Force = (currentGravity * strand[i].Acceleration) + wind;
|
||||
|
||||
strand[i].LastPosition = strand[i].Position;
|
||||
|
||||
// The Cubism Editor expects 30 FPS so we scale here by 30...
|
||||
var delay = strand[i].Delay * deltaTime * 30.0f;
|
||||
|
||||
var direction = strand[i].Position - strand[i - 1].Position;
|
||||
var radian = CubismPhysicsMath.DirectionToRadian(strand[i].LastGravity, currentGravity) / CubismPhysics.AirResistance;
|
||||
|
||||
|
||||
direction.x = ((Mathf.Cos(radian) * direction.x) - (direction.y * Mathf.Sin(radian)));
|
||||
direction.y = ((Mathf.Sin(radian) * direction.x) + (direction.y * Mathf.Cos(radian)));
|
||||
|
||||
|
||||
strand[i].Position = strand[i - 1].Position + direction;
|
||||
|
||||
|
||||
var velocity = strand[i].Velocity * delay;
|
||||
var force = strand[i].Force * delay * delay;
|
||||
|
||||
|
||||
strand[i].Position = strand[i].Position + velocity + force;
|
||||
|
||||
|
||||
var newDirection = strand[i].Position - strand[i - 1].Position;
|
||||
|
||||
newDirection.Normalize();
|
||||
|
||||
|
||||
strand[i].Position = strand[i - 1].Position + newDirection * strand[i].Radius;
|
||||
|
||||
if (Mathf.Abs(strand[i].Position.x) < thresholdValue)
|
||||
{
|
||||
strand[i].Position.x = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
if (delay != 0.0f)
|
||||
{
|
||||
strand[i].Velocity =
|
||||
((strand[i].Position - strand[i].LastPosition) / delay) * strand[i].Mobility;
|
||||
}
|
||||
|
||||
|
||||
strand[i].Force = Vector2.zero;
|
||||
strand[i].LastGravity = currentGravity;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates particles in stabilization function.
|
||||
/// </summary>
|
||||
/// <param name="strand">Particles</param>
|
||||
/// <param name="totalTranslation">Total translation.</param>
|
||||
/// <param name="totalAngle">Total angle.</param>
|
||||
/// <param name="wind">Direction of wind.</param>
|
||||
/// <param name="thresholdValue">Value of threshold.</param>
|
||||
private void UpdateParticlesForStabilization(
|
||||
CubismPhysicsParticle[] strand,
|
||||
Vector2 totalTranslation,
|
||||
float totalAngle,
|
||||
Vector2 wind,
|
||||
float thresholdValue
|
||||
)
|
||||
{
|
||||
strand[0].Position = totalTranslation;
|
||||
|
||||
var totalRadian = CubismPhysicsMath.DegreesToRadian(totalAngle);
|
||||
var currentGravity = CubismPhysicsMath.RadianToDirection(totalRadian);
|
||||
currentGravity.Normalize();
|
||||
|
||||
for (var i = 1; i < strand.Length; ++i)
|
||||
{
|
||||
strand[i].Force = (currentGravity * strand[i].Acceleration) + wind;
|
||||
|
||||
strand[i].LastPosition = strand[i].Position;
|
||||
|
||||
strand[i].Velocity = Vector2.zero;
|
||||
var force = strand[i].Force;
|
||||
force.Normalize();
|
||||
|
||||
strand[i].Position = strand[i - 1].Position + force * strand[i].Radius;
|
||||
|
||||
if (Mathf.Abs(strand[i].Position.x) < thresholdValue)
|
||||
{
|
||||
strand[i].Position.x = 0.0f;
|
||||
}
|
||||
|
||||
strand[i].Force = Vector2.zero;
|
||||
strand[i].LastGravity = currentGravity;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes <see langword="this"/>.
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
var strand = Particles;
|
||||
|
||||
// Initialize the top of particle.
|
||||
strand[0].InitialPosition = Vector2.zero;
|
||||
strand[0].LastPosition = strand[0].InitialPosition;
|
||||
strand[0].LastGravity = Rig.Gravity;
|
||||
strand[0].LastGravity.y *= -1.0f;
|
||||
|
||||
|
||||
// Initialize particles.
|
||||
for (var i = 1; i < strand.Length; ++i)
|
||||
{
|
||||
var radius = Vector2.zero;
|
||||
radius.y = strand[i].Radius;
|
||||
strand[i].InitialPosition = strand[i - 1].InitialPosition + radius;
|
||||
strand[i].Position = strand[i].InitialPosition;
|
||||
strand[i].LastPosition = strand[i].InitialPosition;
|
||||
strand[i].LastGravity = Rig.Gravity;
|
||||
strand[i].LastGravity.y *= -1.0f;
|
||||
}
|
||||
|
||||
|
||||
// Initialize inputs.
|
||||
OriginalInput = new CubismPhysicsInput[Input.Length];
|
||||
for (var i = 0; i < Input.Length; ++i)
|
||||
{
|
||||
OriginalInput[i] = Input[i];
|
||||
Input[i].InitializeGetter();
|
||||
}
|
||||
|
||||
_previousRigOutput = new SubRigPhysicsOutput();
|
||||
_currentRigOutput = new SubRigPhysicsOutput();
|
||||
|
||||
Array.Resize(ref _previousRigOutput.Output, Output.Length);
|
||||
Array.Resize(ref _currentRigOutput.Output, Output.Length);
|
||||
|
||||
// Initialize outputs.
|
||||
OriginalOutput = new CubismPhysicsOutput[Output.Length];
|
||||
for (var i = 0; i < Output.Length; ++i)
|
||||
{
|
||||
OriginalOutput[i] = Output[i];
|
||||
Output[i].InitializeGetter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate rig in every frame.
|
||||
/// </summary>
|
||||
/// <param name="deltaTime"></param>
|
||||
public void Evaluate(float deltaTime)
|
||||
{
|
||||
var totalAngle = 0.0f;
|
||||
var totalTranslation = Vector2.zero;
|
||||
|
||||
for (var i = 0; i < Input.Length; ++i)
|
||||
{
|
||||
ref var input = ref Input[i];
|
||||
var weight = input.Weight / CubismPhysics.MaximumWeight;
|
||||
|
||||
if (input.Source == null)
|
||||
{
|
||||
input.Source = Rig.Controller.Parameters.FindById(input.SourceId);
|
||||
input.SourceIndex = Array.IndexOf(Rig.Controller.Parameters, input.Source);
|
||||
}
|
||||
|
||||
var parameter = input.Source;
|
||||
input.GetNormalizedParameterValue(
|
||||
ref totalTranslation,
|
||||
ref totalAngle,
|
||||
parameter,
|
||||
ref Rig.ParametersCache[input.SourceIndex],
|
||||
Normalization,
|
||||
weight
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
var radAngle = CubismPhysicsMath.DegreesToRadian(-totalAngle);
|
||||
|
||||
|
||||
totalTranslation.x = (totalTranslation.x * Mathf.Cos(radAngle) - totalTranslation.y * Mathf.Sin(radAngle));
|
||||
totalTranslation.y = (totalTranslation.x * Mathf.Sin(radAngle) + totalTranslation.y * Mathf.Cos(radAngle));
|
||||
|
||||
|
||||
UpdateParticles(
|
||||
Particles,
|
||||
totalTranslation,
|
||||
totalAngle,
|
||||
Rig.Wind,
|
||||
CubismPhysics.MovementThreshold * Normalization.Position.Maximum,
|
||||
deltaTime
|
||||
);
|
||||
|
||||
|
||||
for (var i = 0; i < Output.Length; ++i)
|
||||
{
|
||||
ref var currentRigOutput = ref _currentRigOutput.Output[i];
|
||||
_previousRigOutput.Output[i] = currentRigOutput;
|
||||
|
||||
ref var output = ref Output[i];
|
||||
|
||||
if (output.Destination == null)
|
||||
{
|
||||
var destination = Rig.Controller.Parameters.FindById(output.DestinationId);
|
||||
if (destination == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
output.Destination = destination;
|
||||
}
|
||||
|
||||
var particleIndex = output.ParticleIndex;
|
||||
|
||||
if (particleIndex < 1 || particleIndex >= Particles.Length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Update each time as the index may fluctuate.
|
||||
output.DestinationIndex = Array.IndexOf(Rig.Controller.Parameters, output.Destination);
|
||||
|
||||
var translation = Particles[particleIndex].Position -
|
||||
Particles[particleIndex - 1].Position;
|
||||
|
||||
var parameter = output.Destination;
|
||||
var outputValue = output.GetValue(
|
||||
translation,
|
||||
Particles,
|
||||
particleIndex,
|
||||
Rig.Gravity
|
||||
);
|
||||
|
||||
currentRigOutput = outputValue;
|
||||
|
||||
UpdateOutputParameterValue(parameter, ref Rig.ParametersCache[output.DestinationIndex], outputValue, output);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the state in which the physics operation stabilizes at the current parameter values.
|
||||
/// </summary>
|
||||
public void Stabilization()
|
||||
{
|
||||
var totalAngle = 0.0f;
|
||||
var totalTranslation = Vector2.zero;
|
||||
|
||||
for (var i = 0; i < Input.Length; ++i)
|
||||
{
|
||||
var weight = Input[i].Weight / CubismPhysics.MaximumWeight;
|
||||
|
||||
if (Input[i].Source == null)
|
||||
{
|
||||
Input[i].Source = Rig.Controller.Parameters.FindById(Input[i].SourceId);
|
||||
}
|
||||
var index = Array.IndexOf(Rig.Controller.Parameters, Input[i].Source);
|
||||
|
||||
var parameter = Input[i].Source;
|
||||
Input[i].GetNormalizedParameterValue(
|
||||
ref totalTranslation,
|
||||
ref totalAngle,
|
||||
parameter,
|
||||
ref Input[i].Source.Value,
|
||||
Normalization,
|
||||
weight
|
||||
);
|
||||
Rig.ParametersCache[index] = Input[i].Source.Value;
|
||||
}
|
||||
|
||||
|
||||
var radAngle = CubismPhysicsMath.DegreesToRadian(-totalAngle);
|
||||
|
||||
|
||||
totalTranslation.x = (totalTranslation.x * Mathf.Cos(radAngle) - totalTranslation.y * Mathf.Sin(radAngle));
|
||||
totalTranslation.y = (totalTranslation.x * Mathf.Sin(radAngle) + totalTranslation.y * Mathf.Cos(radAngle));
|
||||
|
||||
|
||||
UpdateParticlesForStabilization(
|
||||
Particles,
|
||||
totalTranslation,
|
||||
totalAngle,
|
||||
Rig.Wind,
|
||||
CubismPhysics.MovementThreshold * Normalization.Position.Maximum
|
||||
);
|
||||
|
||||
|
||||
for (var i = 0; i < Output.Length; ++i)
|
||||
{
|
||||
_previousRigOutput.Output[i] = _currentRigOutput.Output[i];
|
||||
|
||||
if (Output[i].Destination == null)
|
||||
{
|
||||
var destination = Rig.Controller.Parameters.FindById(Output[i].DestinationId);
|
||||
if (destination == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Output[i].Destination = destination;
|
||||
}
|
||||
|
||||
var particleIndex = Output[i].ParticleIndex;
|
||||
|
||||
if (particleIndex < 1 || particleIndex >= Particles.Length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var index = Array.IndexOf(Rig.Controller.Parameters, Output[i].Destination);
|
||||
|
||||
var translation = Particles[particleIndex].Position -
|
||||
Particles[particleIndex - 1].Position;
|
||||
|
||||
var parameter = Output[i].Destination;
|
||||
var outputValue = Output[i].GetValue(
|
||||
translation,
|
||||
Particles,
|
||||
particleIndex,
|
||||
Rig.Gravity
|
||||
);
|
||||
|
||||
_currentRigOutput.Output[i] = outputValue;
|
||||
_previousRigOutput.Output[i] = outputValue;
|
||||
UpdateOutputParameterValue(parameter, ref Output[i].Destination.Value, outputValue, Output[i]);
|
||||
|
||||
Rig.ParametersCache[index] = Output[i].Destination.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user