forked from cgvr/DeltaVR
complete animating mouth scale based on amplitude timeline
This commit is contained in:
@@ -196,15 +196,20 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 8a215290e2c2e1d43983b61cb160e241, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
mouthTransform: {fileID: 5759406807219530703}
|
||||
mouthScalingMultiplier: 2.5
|
||||
mouthMovementDuration: 0.25
|
||||
voicelinesFolder: CharacterVoicelines
|
||||
characterSpecificFolder: Chef
|
||||
voiceLineKeys:
|
||||
- Chef/Ulrich_Serve
|
||||
- Chef/Ulrich_Get_Correctly
|
||||
- Chef/Ulrich_Excellent
|
||||
- Chef/Ulrich_Terribly_Sorry_1
|
||||
- Chef/Ulrich_Enjoy
|
||||
- Ulrich_Serve
|
||||
- Ulrich_Get_Correctly
|
||||
- Ulrich_Excellent
|
||||
- Ulrich_Terribly_Sorry_1
|
||||
- Ulrich_Enjoy
|
||||
mouth: {fileID: 5759406807219530703}
|
||||
minScaleY: 0.3
|
||||
maxScaleY: 1
|
||||
gain: 30
|
||||
attack: 0.6
|
||||
release: 0.2
|
||||
fmodWhisperBridge: {fileID: 0}
|
||||
notepadText: {fileID: 0}
|
||||
notepad: {fileID: 0}
|
||||
|
||||
Binary file not shown.
@@ -335,7 +335,7 @@ public class AudioManager : MonoBehaviour
|
||||
}
|
||||
|
||||
instance.start();
|
||||
// instance.release();
|
||||
//instance.release();
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ public abstract class NPCController : MonoBehaviour
|
||||
{
|
||||
protected Transform playerTransform;
|
||||
|
||||
[Header("Voiceline Amplitude Timeline Config")]
|
||||
public string voicelinesFolder = "CharacterVoicelines";
|
||||
public string characterSpecificFolder;
|
||||
public string[] voiceLineKeys;
|
||||
|
||||
|
||||
@@ -20,17 +23,14 @@ public abstract class NPCController : MonoBehaviour
|
||||
public float attack = 0.6f; // faster opening
|
||||
public float release = 0.2f; // slower closing
|
||||
|
||||
[Header("Timeline Folder (StreamingAssets recommended)")]
|
||||
public string timelineFolder = "CharacterVoicelines";
|
||||
|
||||
private float[] rmsCurve;
|
||||
private EventInstance currentVoicelineEvent;
|
||||
private bool isSpeaking;
|
||||
private float smoothed;
|
||||
|
||||
private int sampleRate = 50; // RMS samples per second (20ms windows)
|
||||
// If you change RMS window in Python, update this
|
||||
|
||||
private const float FRAME_DURATION = 0.02f;
|
||||
private float sampleRate = 1f / FRAME_DURATION; // RMS samples per second (20ms windows)
|
||||
|
||||
|
||||
// Start is called before the first frame update
|
||||
@@ -62,7 +62,6 @@ public abstract class NPCController : MonoBehaviour
|
||||
|
||||
private void AnimateMouth()
|
||||
{
|
||||
|
||||
// get FMOD timeline position
|
||||
currentVoicelineEvent.getTimelinePosition(out int ms);
|
||||
float time = ms / 1000f;
|
||||
@@ -88,6 +87,23 @@ public abstract class NPCController : MonoBehaviour
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void StopSpeaking()
|
||||
{
|
||||
isSpeaking = false;
|
||||
smoothed = minScaleY;
|
||||
|
||||
if (mouth != null)
|
||||
{
|
||||
var scale = mouth.localScale;
|
||||
scale.y = minScaleY;
|
||||
mouth.localScale = scale;
|
||||
}
|
||||
|
||||
currentVoicelineEvent.release();
|
||||
}
|
||||
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (other.gameObject.tag == "Player Head")
|
||||
@@ -120,45 +136,28 @@ public abstract class NPCController : MonoBehaviour
|
||||
}
|
||||
|
||||
string key = voiceLineKeys[voiceLineId];
|
||||
|
||||
LoadCurve(key); // load RMS data
|
||||
Debug.Log("loaded timeline curve");
|
||||
|
||||
currentVoicelineEvent = AudioManager.Instance.PlayDialogue(key, gameObject);
|
||||
|
||||
currentVoicelineEvent = AudioManager.Instance.PlayDialogue(characterSpecificFolder + "/" + key, gameObject);
|
||||
if (!currentVoicelineEvent.isValid())
|
||||
{
|
||||
Debug.LogError("Failed to start dialogue event.");
|
||||
return;
|
||||
}
|
||||
|
||||
//isSpeaking = true;
|
||||
isSpeaking = true;
|
||||
|
||||
// Stop mouth on end
|
||||
currentVoicelineEvent.setCallback((type, inst, param) =>
|
||||
{
|
||||
if (type == EVENT_CALLBACK_TYPE.STOPPED)
|
||||
{
|
||||
isSpeaking = false;
|
||||
smoothed = minScaleY;
|
||||
|
||||
if (mouth != null)
|
||||
{
|
||||
Vector3 s = mouth.localScale;
|
||||
s.y = minScaleY;
|
||||
mouth.localScale = s;
|
||||
}
|
||||
}
|
||||
return FMOD.RESULT.OK;
|
||||
});
|
||||
float voicelineDuration = rmsCurve.Length * FRAME_DURATION;
|
||||
Invoke(nameof(StopSpeaking), voicelineDuration);
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// Load RMS Timeline (.txt)
|
||||
// ---------------------------
|
||||
|
||||
// ---------------------------
|
||||
// Load RMS Timeline (.txt)
|
||||
// ---------------------------
|
||||
private void LoadCurve(string key)
|
||||
{
|
||||
string folderPath = Path.Combine(Application.streamingAssetsPath, timelineFolder);
|
||||
string folderPath = Path.Combine(Application.streamingAssetsPath, voicelinesFolder, characterSpecificFolder);
|
||||
string filePath = Path.Combine(folderPath, key + ".txt");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
|
||||
Reference in New Issue
Block a user