跳至主要内容

SoundTrace SDK for Unity

SoundTrace Unity SDK 是一款即時空間音訊外掛,用於將 Unity 的網格、Renderer 材質插槽、音源與聆聽者連接到 STCoreV2

本頁以目前 Unity SDK 的公開元件與 Inspector 契約為準。

要求與平台

項目目前套件狀態
Unity2022.3 LTS 或更新版本
隨附原生外掛macOS、Windows x64、iOS、Android
Linux目前套件不含二進位檔,需在 Linux 主機上另行建置
Unity WebGL不支援。Unity WebGL 無法使用以 OnAudioFilterRead 為基礎的 DSP 處理

Use GPU Backend 會為 reflection 與 reverb propagation 要求 WebGPU compute provider。 diffraction 仍由 CPU 計算。實際是否啟用取決於原生外掛與裝置;GPU 初始化失敗時使用 CPU propagation。

安裝

SoundTrace Unity SDK 套件與安裝說明會透過已簽約的評估或授權交付管道提供。 請遵循收到的發行套件所附安裝步驟。

在 Package Manager 中選擇 SoundTrace SDK,然後透過 Samples > Demo Assets > Import 匯入範例。

Unity Audio 設定

  1. 開啟 Edit > Project Settings > Audio
  2. Default Speaker Mode 設為 Stereo
  3. DSP Buffer Size 設為 Best latency

Unity Audio 設定

如果這些設定不一致,Manager 與 Listener Inspector 會顯示警告。

Audio Asset Import 設定

以使用單聲道音源為前提,音訊剪輯設定為 PCM 格式。

Audio Asset Import 設定

最快設定

  1. 在空白 GameObject 上加入 SoundTraceManager
  2. 在 Main Camera 上加入 SoundTraceListener
  3. 在音源 GameObject 上加入 SoundTraceSource,並為同一 GameObject 上的 AudioSource 指定 clip。
  4. 在要作為聲學幾何體的 Mesh GameObject 上加入 SoundTraceObject
  5. 如有需要,在與 Manager 相同的 GameObject 上加入 SoundTracePathVisualizer
  6. 在 Play Mode 中檢查 Console 錯誤、聲音與 path。

在所有同時載入的 scene 中,只能各有一個啟用中的 Manager 與 Path Visualizer。 可以註冊多個 Listener,但 Source 渲染會使用第一個註冊的 PrimaryListener

元件概覽

元件作用必要相依性
SoundTraceManager管理執行階段、scene、材質註冊與 propagation backend每個執行階段 1 個
SoundTraceListenerListener transform、ray 品質、輸出/HRTF 設定啟用中的 Manager
SoundTraceSourceAudioSource 輸出空間化並設定各類 path同一 GameObject 上的 AudioSource、啟用中的 Listener
SoundTraceObject將 Mesh 與 submesh 材質註冊到聲學 sceneMeshFilterMeshRenderer
SoundTracePathVisualizer偵錯顯示有效 path 與 hit triangle與 Manager 相同的 GameObject

SoundTraceManager

SoundTraceManager Inspector

Inspector

欄位預設值行為
bool propagateOnStarttrueStart() 中同步初始 scene graph 與 transform,然後要求第一次 propagation。
bool loadDefaultMaterialsOnEnabletrueOnEnable() 中將隨附的 Material Preset Library 註冊到原生 material table。
int propagationThreadCount-1指定聲音引擎內部 propagation job 的執行執行緒數。在原生平台上,-1std::thread::hardware_concurrency() 回傳的邏輯執行緒數自動設定,01 以單執行緒運作。2 以上使用指定數量,其中包含呼叫執行緒。
bool useGpuBackendfalsepropagation 不使用 job 多執行緒,而是透過 GPU compute shader 計算。
int pathCacheSize256生成 path 的 cache buffer size,最小值為 0,最大值為 1024。數值越高,空間音訊效果越好,但計算量也會隨之增加。建議依裝置效能,從低於預設值 256 的設定開始。

公開屬性

屬性型別/存取方式準確含義
Instancestatic SoundTraceManager / get; private set;所有已載入 scene 共用的單例 Manager;沒有啟用中的 Manager 時為 null
DefaultMaterialsLoadedint / get; private set;OnEnable() 中自動註冊的隨附材質數量。關閉自動載入或 asset 遺失時為 0
SceneSoundScene / get; private set;Manager 擁有的底層 scene。處於停用狀態或初始化失敗後為 null
PrimaryListenerSoundTraceListener / getSource 渲染使用的第一個已註冊 Listener;沒有 Listener 時為 null
ListenerCountint / get目前註冊到 Manager 的 Listener 數量。
SourceCountint / get目前註冊到 Manager 的 Source 數量。
ObjectCountint / get目前註冊到 Manager 的 Object 數量。
LastValidPathCountint / get; private set;最近完成的 propagation 結果中的有效 path 數量。無法執行 propagation 時為 0
LastNativeErrorstring / get; private set;最近的 scene graph 或 propagation 錯誤;沒有錯誤時為空字串。
PropagationThreadCountint / getpropagation job 的執行執行緒數量。-1 表示最大值。
IsGpuPropagatebool / get; private set;exaPropagatorInitGpu() 是否成功並啟用了 GPU propagation provider。
GpuBackendStatusstring / get; private set;GPU Backend 初始化結果:GPU activeCPU fallback (<ExaResult>): <error>
PathCacheSizeint / get生成 path 的 cache buffer size。

公開方法

方法行為
public void ResetMotionState()在 teleport、respawn 或 scene 切換後,立即重設所有已註冊 Listener 與 Source 的 motion history。

SoundTraceListener

SoundTraceListener Inspector

通常加入 Main Camera。

Inspector

欄位預設值範圍/選項
Quality PresetFastCustomFastMiddleQuality
Ray Resolution161..32;水平與垂直使用相同值
Ray Depth41..16
Output ModeHeadsetHeadsetSpeaker
HRTFHRIR Interpolated以下三種模式

選擇 FastMiddleQuality 時,會同時套用 ray 值與相關的 render 品質值, ray 欄位也會在 Inspector 中停用。若要直接編輯這些值,請先選擇 Custom。 從預設返回 Custom 時,會保留最後套用的值。

預設Ray ResolutionRay Depth建議起點
Custom已儲存的值已儲存的值手動調校
Fast164行動平台、大量音源
Middle248一般遊戲與桌面平台
Quality3212音訊比重較高、其他處理負載較低的應用程式

HRTF 與輸出模式

模式所需 asset說明
Band8不載入外部 HRTF table 的輕量模式
HrirKU100_convolution.bytesHRIR 模式
HRIR InterpolatedKU100_convolution.bytes在 HRIR 模式中套用插值計算,以增強方向感。

Asset 從 Runtime/Resources/SoundTrace/HRTF/ 載入。如果所需 asset 不存在或為空, Listener 初始化會失敗,且不會自動切換到其他模式。

SoundTraceSource

SoundTraceSource Inspector

SoundTraceSource 處理同一 GameObject 上的 AudioSource 輸出。啟用時,會將 AudioSource.spatialBlendAudioSource.dopplerLevel 設為 0,讓 SoundTrace 負責空間化與 Doppler。

Inspector

欄位預設值行為
Intensity1Source 發射強度,範圍為 0..10
Ray Resolution24對 Reverb ray 的水平與垂直解析度套用相同數值,範圍為 1..32
Reverb Ray Depth4Reverb ray 的最大反射深度,範圍為 1..16
Enable Directtrue啟用 Direct path。
Enable Reflectiontrue啟用 Reflection path。
Enable Diffractiontrue啟用 Diffraction path。
Enable Reverbtrue啟用 Reverb path。
Enable Transmissiontrue啟用 Transmission path。
Direct Attenuation1.0Direct path 的距離衰減。數值越大,在相同距離下聽到的聲音越小。範圍為 0.5..1.5
Reflection Attenuation1.0Reflection path 的距離衰減。數值越大,在相同距離下聽到的聲音越小。範圍為 0.5..1.5
Diffraction Attenuation1.0Diffraction path 的距離衰減。數值越大,在相同距離下聽到的聲音越小。範圍為 0.5..1.5
Reverb Attenuation1.0Reverb path 的距離衰減。數值越大,在相同距離下聽到的聲音越小。範圍為 0.5..1.5
Transmission Attenuation1.0Transmission path 的距離衰減。數值越大,在相同距離下聽到的聲音越小。範圍為 0.5..1.5
Max Delay Seconds1.0 sSource renderer 保留的最大 propagation delay。時間越長,記憶體使用量越多。範圍為 0.01..5 s
Path Fade Time Seconds0.066 sPath 進入或離開 renderer 時使用的 fade 時間,範圍為 0.001..0.5 s
Path Hold Time Seconds0.120 s消失的 non-direct path 開始 fade 前的保留時間。0 會停用 hold。
Max Delay Rate0.1每個 sample 允許的最大 delay 變化量,範圍為 0.001..0.999
Bypassfalse跳過 SoundTrace spatial rendering,並直接傳遞原始 AudioSource 輸出。

Distance Attenuation 值越大,對應 path 的距離衰減越快。Show Gizmo 會在 Scene View 中 分別顯示 Direct、Reflection、Diffraction、Reverb 與 Transmission 的可達範圍。

Render Tuning 套用於 source-listener 配對。Path Hold = 0 會關閉 hold。

公開方法

方法動作
SetBypass(bool enabled)true 時跳過 SoundTrace spatial rendering,並直接傳遞原始 AudioSource 輸出;為 false 時重新套用 SoundTrace rendering。
ResetMotionState()將目前 Transform 重新設為 motion 基準點,並以速度 0 反映,避免 teleport 或 respawn 後出現 Doppler spike。

若要同步多個 AudioSource 的播放時機,請以相同的 AudioSettings.dspTime 為基準呼叫 PlayScheduled()

SoundTraceObject

SoundTraceObject Inspector

SoundTraceObject 會註冊 MeshFilter.sharedMesh 與 Renderer 的 submesh 材質插槽。 由於 Build 中需要讀取網格資料,請在 Import Settings 中啟用 Read/Write Enabled

Geometry 與 BVH

Scene View 中顯示的 BVH

欄位預設值說明
BVH TypeLBVH_SIMD8HKDTreeLBVHLBVH_SIMD4LBVH_SIMD8LBVH_SIMD16
BVH Max Depth121..32
Primitives Per Leaf161..128
Update ModeStaticStaticDynamicRefitRebuild

BVH Type

BVH Type說明
HKDTree使用以 KD 分割為基礎的 traversal。它支援 Refit,但 Refit 後會切換為 BVH-style fallback traversal。不支援 GPU backend。
LBVH以 Morton code 為基礎,rebuild 速度比 HKDTree 更快,並支援 Refit。透過底層 API 上傳 vertex 後進行 Refit,可用於 SkinnedMesh 或 procedural mesh 變形。純量格式不支援 GPU backend。
LBVH_SIMD4以 4 個一組的 SIMD batch 平行處理 LBVH leaf intersection。支援 Refit 及支援 GPU Backend。
LBVH_SIMD8以 8 個一組的 SIMD batch 平行處理 LBVH leaf intersection,為目前的預設值。支援 Refit 及支援 GPU Backend。
LBVH_SIMD16以 16 個一組的 SIMD batch 平行處理 LBVH leaf intersection。支援 Refit 及支援 GPU Backend。

如果在要求 GPU 的 scene 中選擇 HKDTree 或純量 LBVH,Inspector 會顯示警告。

Update Mode

Update ModeSTCoreV2 update policy含意
StaticEXA_OBJECT_UPDATE_STATIC (0)執行階段不更新 TLAS/BLAS。用於不移動的 level geometry。
RefitEXA_OBJECT_UPDATE_REFIT (1)形變(deformation)策略:refit mesh BLAS 並更新 TLAS bounds。適用於 topology 維持不變的 skinned 與 procedural mesh。
RebuildEXA_OBJECT_UPDATE_REBUILD (2)用於 topology 會改變的 geometry,會重新建置 BVH。
DynamicEXA_OBJECT_UPDATE_DYNAMIC (3)僅 Transform 變化時,只更新 TLAS instance。

Refit 與 vertex 上傳

Refit 是 STCoreV2 中用於 vertex 形變(skinned animation)的 update policy。但 core 不會自行決定何時上傳 vertex:mesh 更新採用 exaMeshUpdateVerticesexaMeshRefit 的 2-call protocol,而 object 上的 Refit 是讓該結果反映到 BLAS 與 TLAS bounds 的策略開關。 換言之,上傳 vertex 的一方是 host SDK

目前 Unity 的 SoundTraceObject MonoBehaviour 只會自動同步 Transform,不會呼叫 vertex 上傳。 它要求 MeshFilter/MeshRenderer,因此不會直接繫結 SkinnedMeshRenderer,且 mesh geometry 只在 OnEnable 時快照一次。因此若要在 Unity 中讓 skinned 或 procedural 形變反映到聲音上, 請將 Update Mode 設為 Refit,並如下所示透過 MeshCore 自行上傳 vertex。UE 外掛的 SoundTracingObjectComponent 會為 skeletal mesh 自動完成這項上傳。

using Exarion.SoundTrace;
using Exarion.SoundTrace.Core;
using Exarion.SoundTrace.Native;
using UnityEngine;

[RequireComponent(typeof(SoundTraceObject))]
public sealed class SoundTraceSkinnedRefit : MonoBehaviour
{
[SerializeField] private SkinnedMeshRenderer skin;

private SoundTraceObject _object;
private Mesh _baked;
private ExaVec3f[] _vertices;

private void Awake()
{
_object = GetComponent<SoundTraceObject>();
_baked = new Mesh();
}

private void LateUpdate()
{
SoundMeshCore mesh = _object.MeshCore;
if (mesh == null || !mesh.IsValid)
return;

// 1) bake 目前的 pose 並讀取 vertex。這是 Unity Mesh API,必須在 main thread 執行。
skin.BakeMesh(_baked);
Vector3[] baked = _baked.vertices;
if (_vertices == null || _vertices.Length != baked.Length)
_vertices = new ExaVec3f[baked.Length];
for (int i = 0; i < baked.Length; ++i)
_vertices[i] = new ExaVec3f(baked[i].x, baked[i].y, baked[i].z);

// 2) 上傳與 refit 在 control thread 上以 2-call protocol 執行。
ExaVec3f[] vertices = _vertices;
SoundTraceControlThread.Invoke(() =>
{
if (mesh.UpdateVertices(vertices))
mesh.Refit();
});
}

private void OnDestroy()
{
if (_baked != null)
Destroy(_baked);
}
}

注意事項:

  • vertex 數量必須與建置時完全一致。數量不符時 exaMeshUpdateVertices 會以 EXA_ERR_INVALID_ARG 拒絕。請將 SkinnedMeshRenderer 的 bind pose mesh 放入 MeshFilter.sharedMesh,使數量對齊。
  • vertex 以 mesh 區域座標系原樣上傳。object 的 position、rotation、scale 由 SoundTraceObject 另行同步,因此 BakeMesh 也應使用不套用 scale 的形式。
  • native mesh 由 SoundTraceMeshCache 以 Mesh asset、material slot 與 BVH 設定為鍵進行 refcount 共用。當多個 object 使用相同組合時,refit 其中一個會讓它們全部產生相同形變。 若需各自獨立形變,請為每個 object 使用不同的 Mesh instance。
  • SoundTraceControlThread.Invoke 是封鎖式呼叫。每個 frame 對大量 object 呼叫會讓 main thread 排在 control thread 的 propagation frame 之後等待,請將 refit 對象限制在少量 object。
  • BVH Type 請使用可 refit 的 LBVH 系列。HKDTree 也能 refit,但之後 traversal 會切換為 BVH-style fallback。
  • triangle index 改變的 topology 變更無法以 refit 處理。請透過 MeshCore.SetData(...) 重新建置,並將 Update Mode 設為 Rebuild

公開方法

Auto Set 會將 Renderer material 名稱與隨附 preset 配對。如果 imported model root 上沒有 mesh,而是由 child 持有 geometry,請使用 Add To Child Meshes

方法動作
AutoSetMaterialSlots()走訪所有 submesh,將 Renderer material 名稱與隨附 preset 自動配對,並更新插槽設定。
GetMaterialPresetIndex(int slotIndex)傳回指定插槽的 preset index。沒有插槽或插槽 index 無效時傳回 0
GetPresetName(int slotIndex)傳回指定插槽所用 preset 的顯示名稱。找不到 preset 時傳回 Concrete
SetMaterialPresetIndex(int slotIndex, int presetIndex)變更一個插槽的 preset。presetIndex 最小會修正為 0,插槽 index 無效時傳回 false
SetMaterialPresetForAllSlots(int presetIndex)對所有插槽套用相同 preset。presetIndex 最小會修正為 0,沒有可套用的插槽時傳回 false
GetNativeMaterialIndices()以 native mesh 註冊所需的陣列格式傳回每個 submesh 的 preset index。空白或缺少的插槽使用 0
GetTriangleCount()加總所有 submesh 的 index 數並傳回 triangle 數。沒有 mesh 時傳回 0
static IsGpuCompatibleBvhType(BvhType value)當值為 LBVH_SIMD4LBVH_SIMD8LBVH_SIMD16 時傳回 true

聲學材質與 Transmission

預設創作資產為 Runtime/Resources/SoundTrace/SoundTraceMaterialPresetLibrary.asset。 在 SoundTrace > Material Preset Library 中可以執行以下操作:

  • 加入、刪除預設並調整順序
  • 匯入/匯出 soundMaterial.json,或重新匯入隨附 JSON
  • 編輯 Scattering 與 8 頻帶 Reflection、Absorption、Transmission 圖表
  • 選擇 Transmission Model

Material Preset Library

頻帶中心為 67.51252505001000200040008000 Hz。材質順序必須與資料表索引一致。

依頻帶編輯材質圖表

Transmission Model

模型輸入幾何體條件
Surface每個頻帶中穿過表面後保留的透射能量係數 0..1可用於開放面與薄表面
Solid Distance每個頻帶中透射能量達到 -30 dB 時的材質參考距離(m),不得小於 0需要封閉體積與一致的面方向

Solid Distance 的輸入不是物件的實際厚度。執行階段會依照在幾何體內部的實際 穿行距離套用衰減。變更模式不會自動計算這 8 個值,因此請填入全部已驗證值, 不要維持預設的 0 狀態。

在 JSON 中,如果沒有 transmissionDistanceToMinus30DbMeters,則使用 Surface; 如果此欄位包含恰好 8 個有限且不小於 0 的值,則使用 Solid Distance。 匯出為 Surface 時會省略此欄位,而不是寫入 null 或空陣列。

SoundTracePathVisualizer

SoundTracePathVisualizer Inspector

只能在與 Manager 相同的 GameObject 上加入一個。

Inspector 欄位預設值說明
Enable Path Visualization開啟是否顯示 path mesh
Refresh Interval Ms50重新產生視覺化 mesh 的最小間隔;不影響聲學 propagation 週期
Max Visualized Paths1024最多顯示的 path 數量
Path Width0.08線寬
Path Alpha Intensity0.5顯示強度
Draw Hit Triangles關閉在 Scene View 中顯示 hit triangle

Direct、Reflection、Diffraction、Reverb 與 Transmission 會依 path 類型使用不同顏色顯示。 此元件用於偵錯,在效能測量與 release build 中應停用。

主要公開成員為 Instance、設定/計數屬性、Render()Clear()

範例

ST_SampleScene01

ST_SampleScene01

用於檢查基本房間、音源、聆聽者、幾何體、材質預設與路徑視覺化。

ST_SampleScene02

ST_SampleScene02

用於檢查音源/聆聽者移動、材質預設切換,以及 Unity 原始音訊與 SoundTrace 輸出的比較。

ST_SampleScene03

ST_SampleScene03

用於檢查大型空間中的多個音源、牆面遮蔽、移動期間的 HRTF 方向感與房間響應。

疑難排解

症狀檢查項目
沒有聲音Console 中第一個 Manager 初始化錯誤、Stereo/Best latency、AudioSource clip、是否存在 Manager/Listener
Source/Listener/Object 要求 Manager檢查連鎖錯誤之前記錄的 Failed to initialize SoundTraceManager 原因
HRTF 初始化失敗所選模式對應的 Resources asset 是否存在,以及檔案是否為空
Geometry 未生效Read/Write Enabled、MeshFilter/MeshRenderer、子網格位置、註冊狀態
執行階段變形 mesh 未生效僅設定 Update Mode 不會上傳頂點/拓撲;需要獨立的底層幾何體更新路徑
GPU 未啟用檢查 GpuBackendStatus、Console 回退原因、Object 是否選擇 SIMD BVH
Teleport 後音高跳變變更 transform 後立即呼叫 ResetMotionState()
效能不足Quality → Middle → Fast 順序檢查,縮小 path cache buffer,然後停用路徑視覺化
多個音源聽起來像梳狀濾波使用相同的 AudioSettings.dspTime 呼叫 PlayScheduled()

後續文件