From 6c6cf63668adbbb3a07870fc00d96470e43354ec Mon Sep 17 00:00:00 2001 From: "DESKTOP-VVOCIJO\\PC" Date: Mon, 27 Apr 2026 10:48:22 +0900 Subject: [PATCH] =?UTF-8?q?2026-04-27=20=EC=BA=90=EB=A6=AD=ED=84=B0=20?= =?UTF-8?q?=EB=A6=BD=EC=8B=B1=ED=81=AC=20=ED=94=84=EB=A1=9C=ED=86=A0?= =?UTF-8?q?=ED=83=80=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 4 +- Assets/01_Scenes/MyProject/GameScene.unity | 4 +- .../02_Scripts/Communication/Voice/LipSync.cs | 109 ++++++++++++++++++ .../Communication/Voice/LipSync.cs.meta | 2 + .../Expressions/BMAC_OpenMouse_Big.anim | 3 + .../Expressions/BMAC_OpenMouse_Big.anim.meta | 8 ++ .../Expressions/BMAC_OpenMouse_Small.anim | 3 + .../BMAC_OpenMouse_Small.anim.meta | 8 ++ Assets/03_Models/_Characters/Gray/Gray.prefab | 4 +- .../_Characters/Violet/Violet.prefab | 4 +- .../03_Models/_Characters/White/White.prefab | 4 +- 11 files changed, 143 insertions(+), 10 deletions(-) create mode 100644 Assets/02_Scripts/Communication/Voice/LipSync.cs create mode 100644 Assets/02_Scripts/Communication/Voice/LipSync.cs.meta create mode 100644 Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Big.anim create mode 100644 Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Big.anim.meta create mode 100644 Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Small.anim create mode 100644 Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Small.anim.meta diff --git a/.vscode/settings.json b/.vscode/settings.json index ada647b7..81230413 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -60,12 +60,12 @@ "*.asset": "yaml", "*.meta": "yaml", "*.prefab": "yaml", - "*.unity": "yaml", + "*.unity": "yaml" }, "explorer.fileNesting.enabled": true, "explorer.fileNesting.patterns": { "*.sln": "*.csproj", "*.slnx": "*.csproj" }, - "dotnet.defaultSolution": "VR_MyProject.slnx" + "dotnet.defaultSolution": "Shopping_UnityVR.slnx" } \ No newline at end of file diff --git a/Assets/01_Scenes/MyProject/GameScene.unity b/Assets/01_Scenes/MyProject/GameScene.unity index a7e448ec..6475210b 100644 --- a/Assets/01_Scenes/MyProject/GameScene.unity +++ b/Assets/01_Scenes/MyProject/GameScene.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ebeb5b4fe52ac010bffb787acd6c6fcd33ec469167ea2d2098f18a45006450a -size 13302919 +oid sha256:ab6c630f9be636cc333d9961c2f0edc81c5027a5a24d680d67ee4fabf7826ae7 +size 13304416 diff --git a/Assets/02_Scripts/Communication/Voice/LipSync.cs b/Assets/02_Scripts/Communication/Voice/LipSync.cs new file mode 100644 index 00000000..a2debdde --- /dev/null +++ b/Assets/02_Scripts/Communication/Voice/LipSync.cs @@ -0,0 +1,109 @@ +using System; +using UnityEngine; + +// 보이스 진폭에 따라 입 관련 블렌드셰이프 그룹의 weight를 직접 제어 +// LateUpdate에서 갱신해 Animator가 같은 프레임에 0으로 세팅한 값을 덮어씀 +[RequireComponent(typeof(CharacterVoiceObject))] +public class LipSync : MonoBehaviour +{ + [Serializable] + private struct LipShape + { + public string Name; + [Range(0f, 100f)] public float MaxWeight; // amplitude=1일 때 도달할 weight + } + + [Header("Refs")] + [SerializeField] private SkinnedMeshRenderer _meshRenderer; + + // BMAC_OpenMouse_Big 클립의 입 관련 셰이프 프리셋 + [Header("Mouth Preset (입 최대 시 weight)")] + [SerializeField] private LipShape[] _shapes = + { + new() { Name = "Expression_SurpriesedMouth", MaxWeight = 50f }, + new() { Name = "Expression_MouthSad_L", MaxWeight = 10f }, + new() { Name = "Expression_MouthSad_R", MaxWeight = 10f }, + new() { Name = "Expression_MouthWide_L", MaxWeight = 30f }, + new() { Name = "Expression_MouthWide_R", MaxWeight = 30f }, + new() { Name = "Expression_LipsOh", MaxWeight = 100f }, + new() { Name = "Expression_LipsO", MaxWeight = 5f }, + }; + + [Header("Tuning")] + [SerializeField, Range(0f, 20f)] private float _amplitudeScale = 6f; // RMS → 0~1 매핑 배수 + [SerializeField, Range(0f, 0.05f)] private float _noiseFloor = 0.005f; + [SerializeField, Range(0f, 30f)] private float _smoothingSpeed = 15f; + [SerializeField] private int _sampleSize = 256; + + private AudioSource _audioSource; + private int[] _indices; + private float[] _sampleBuffer; + private float _currentAmplitude; + + private void Awake() + { + var voiceObj = GetComponent(); + _audioSource = voiceObj != null ? voiceObj.VoiceSource : null; + + // 메시 자동 탐색 — 첫 번째 셰이프 이름을 가진 SkinnedMeshRenderer 사용 + if (_meshRenderer == null && _shapes.Length > 0) + { + string probe = _shapes[0].Name; + foreach (var smr in GetComponentsInChildren(true)) + { + if (smr.sharedMesh != null && smr.sharedMesh.GetBlendShapeIndex(probe) >= 0) + { + _meshRenderer = smr; + break; + } + } + } + + // 인덱스 캐시 + _indices = new int[_shapes.Length]; + if (_meshRenderer != null && _meshRenderer.sharedMesh != null) + { + var mesh = _meshRenderer.sharedMesh; + for (int i = 0; i < _shapes.Length; i++) + { + _indices[i] = mesh.GetBlendShapeIndex(_shapes[i].Name); + if (_indices[i] < 0) + Debug.LogWarning($"[LipSync] 블렌드셰이프 없음: {_shapes[i].Name}", this); + } + } + else + { + for (int i = 0; i < _indices.Length; i++) _indices[i] = -1; + } + + if (_audioSource == null) + Debug.LogWarning("[LipSync] CharacterVoiceObject.VoiceSource 미할당", this); + + _sampleBuffer = new float[_sampleSize]; + } + + private void LateUpdate() + { + if (_audioSource == null || _meshRenderer == null) return; + + // PlayOneShot도 잡히도록 항상 샘플링 — 무음은 노이즈 플로어로 컷 + _audioSource.GetOutputData(_sampleBuffer, 0); + + float sumSq = 0f; + for (int i = 0; i < _sampleBuffer.Length; i++) + sumSq += _sampleBuffer[i] * _sampleBuffer[i]; + + float rms = Mathf.Sqrt(sumSq / _sampleBuffer.Length); + rms = Mathf.Max(0f, rms - _noiseFloor); + float target = Mathf.Clamp01(rms * _amplitudeScale); + + _currentAmplitude = Mathf.Lerp(_currentAmplitude, target, Time.deltaTime * _smoothingSpeed); + + // Animator가 같은 프레임에 0으로 덮은 값을 LateUpdate에서 다시 씌움 + for (int i = 0; i < _shapes.Length; i++) + { + if (_indices[i] < 0) continue; + _meshRenderer.SetBlendShapeWeight(_indices[i], _currentAmplitude * _shapes[i].MaxWeight); + } + } +} diff --git a/Assets/02_Scripts/Communication/Voice/LipSync.cs.meta b/Assets/02_Scripts/Communication/Voice/LipSync.cs.meta new file mode 100644 index 00000000..bd5c5fa6 --- /dev/null +++ b/Assets/02_Scripts/Communication/Voice/LipSync.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 160aeff980f9a0546a56b85727e287f8 \ No newline at end of file diff --git a/Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Big.anim b/Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Big.anim new file mode 100644 index 00000000..2050ee81 --- /dev/null +++ b/Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Big.anim @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f744f74c917443f36fe481bd34542572c1a27bc492da22910f0e39464ba7e9f8 +size 9815 diff --git a/Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Big.anim.meta b/Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Big.anim.meta new file mode 100644 index 00000000..6c82a239 --- /dev/null +++ b/Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Big.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c8d0283ff08da174784f1ec8827f28ec +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Small.anim b/Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Small.anim new file mode 100644 index 00000000..2ce1aa8b --- /dev/null +++ b/Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Small.anim @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa07154974f3a4ba5fd7c4046c66a07182df1d71b18370b0454ca8f7c54b9211 +size 8653 diff --git a/Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Small.anim.meta b/Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Small.anim.meta new file mode 100644 index 00000000..72362d9a --- /dev/null +++ b/Assets/03_Models/_Characters/Base/Animations/Expressions/BMAC_OpenMouse_Small.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 410d5556fb8a2524a93097611687d170 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/03_Models/_Characters/Gray/Gray.prefab b/Assets/03_Models/_Characters/Gray/Gray.prefab index 94751670..d83d7cce 100644 --- a/Assets/03_Models/_Characters/Gray/Gray.prefab +++ b/Assets/03_Models/_Characters/Gray/Gray.prefab @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f3d7e322233777bfb474f9aa8cfa1f468629bb94792cd03c5e6f6cfd9341bd67 -size 157128 +oid sha256:fdc3a696c83f06d87445c284d59babbd25c86395641b7affdf72fea032b1d925 +size 157146 diff --git a/Assets/03_Models/_Characters/Violet/Violet.prefab b/Assets/03_Models/_Characters/Violet/Violet.prefab index 045dd768..ce3b947c 100644 --- a/Assets/03_Models/_Characters/Violet/Violet.prefab +++ b/Assets/03_Models/_Characters/Violet/Violet.prefab @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9f44e4ce352204fd363ec16069478ceec079998016ea2986bd2830de00c25730 -size 158056 +oid sha256:a24f3a0692c625f614facee15c8686616ce99206619f2291cc3345db1ebe41da +size 158074 diff --git a/Assets/03_Models/_Characters/White/White.prefab b/Assets/03_Models/_Characters/White/White.prefab index 8d05ea73..4f597064 100644 --- a/Assets/03_Models/_Characters/White/White.prefab +++ b/Assets/03_Models/_Characters/White/White.prefab @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c0bc7ba99bb031da145661b852af7cf59a437cd6dd5c21aafee5583301f68f3d -size 159375 +oid sha256:62948abd6001cec66afc111f8e1165fdb09b1725ed968d5b0b32b099dec574cd +size 159393