using UnityEngine; using Wwise.Wooduan.Components; using Wwise.Wooduan.Core; using Wwise.Wooduan.Tools; public partial class AkSurfaceReflector : AkComponent, ICullableAudioObject, IAkSpatialAudioObject { [UnityEngine.Tooltip("Enable or disable geometric diffraction for this mesh.")] public bool EnableDiffraction = true; [Tooltip("The unique cull distance of this geometry")] public float cullDistance = 30; [Tooltip("Optional room with which this surface reflector is associated. " + "It is recommended to associate geometry with a particular room if the geometry is fully contained within the room and the room does not share any geometry with any other rooms. " + "Doing so reduces the search space for ray casting performed by reflection and diffraction calculations.")] public AkSpatialAudioRoom AssociatedRoom = null; private MeshFilter _meshFilter; private void OnEnable() { _meshFilter = GetComponent(); if (!AssociatedRoom) AssociatedRoom = AkOutdoor.GetInstance(); if (AssociatedRoom) AssociatedRoom.RegisterGeometry(this); Refresh(true); } private void OnDisable() { if (AssociatedRoom) AssociatedRoom.UnregisterGeometry(this); Refresh(false); } public void AutoFindAssociatedRoom() { var room = SpatialAudioManager.FindRoomAtPosition(transform.position); if (room) AssociatedRoom = room; } #region ICullableAudioObject public bool IsCulled { get; set; } public void TryCull(Vector3 listenerPosition) { if (cullDistance <= 0f) return; if (Vector3.Distance(transform.position, listenerPosition) > cullDistance) OnCull(); else OnReveal(); } public void OnCull() { if (IsCulled) return; IsCulled = true; Refresh(false); AkWooduanHelper.DebugToConsole(AudioLogVerbosity.Notification, AudioObjectType.Geometry, AudioTriggerSource.AkSurfaceReflector, AudioAction.Cull, name, gameObject); } public void OnReveal() { if (!IsCulled) return; IsCulled = false; Refresh(true); AkWooduanHelper.DebugToConsole(AudioLogVerbosity.Notification, AudioObjectType.Geometry, AudioTriggerSource.AkSurfaceReflector, AudioAction.Reveal, name, gameObject); } #endregion ICullableAudioObject internal void Refresh(bool active) { if (!AkSoundEngine.IsInitialized()) return; if (active && SpatialAudioManager.GeometryEnabled) RegisterInWwise(); else UnregisterInWwise(); } public override bool IsValid() { return _meshFilter; } #region IAkSpatialAudioObject public bool IsRegisteredInWwise { get; set; } public void RegisterInWwise() { if (AkSoundEngine.IsInitialized() && !IsRegisteredInWwise && IsValid()) { RemoveGeometry(); IsRegisteredInWwise = SetGeometryFromMesh(); } } public void UnregisterInWwise() { if (AkSoundEngine.IsInitialized() && !IsRegisteredInWwise && IsValid()) { RemoveGeometry(); IsRegisteredInWwise = false; } } public bool SetGeometryFromMesh() { if (!Mesh) return false; var vertices = Mesh.vertices; // Remove duplicate vertices var vertRemap = new int[vertices.Length]; var uniqueVerts = new System.Collections.Generic.List(); var vertDict = new System.Collections.Generic.Dictionary(); for (var v = 0; v < vertices.Length; ++v) { int vertIdx = 0; if (!vertDict.TryGetValue(vertices[v], out vertIdx)) { vertIdx = uniqueVerts.Count; uniqueVerts.Add(vertices[v]); vertDict.Add(vertices[v], vertIdx); } vertRemap[v] = vertIdx; } int vertexCount = uniqueVerts.Count; var vertexArray = new UnityEngine.Vector3[vertexCount]; for (var v = 0; v < vertexCount; ++v) { var point = transform.TransformPoint(uniqueVerts[v]); vertexArray[v].x = point.x; vertexArray[v].y = point.y; vertexArray[v].z = point.z; } int surfaceCount = Mesh.subMeshCount; var numTriangles = Mesh.triangles.Length / 3; if ((Mesh.triangles.Length % 3) != 0) { UnityEngine.Debug.LogFormat("SetGeometryFromMesh({0}): Wrong number of triangles", Mesh.name); } using (var surfaceArray = new AkAcousticSurfaceArray(surfaceCount)) using (var triangleArray = new AkTriangleArray(numTriangles)) { int triangleArrayIdx = 0; for (var s = 0; s < surfaceCount; ++s) { var surface = surfaceArray[s]; var triangles = Mesh.GetTriangles(s); var triangleCount = triangles.Length / 3; if ((triangles.Length % 3) != 0) { UnityEngine.Debug.LogFormat("SetGeometryFromMesh({0}): Wrong number of triangles in submesh {1}", Mesh.name, s); } AK.Wwise.AcousticTexture acousticTexture = null; float occlusionValue = 1.0f; if (s < AcousticTextures.Length) acousticTexture = AcousticTextures[s]; if (s < TransmissionLossValues.Length) occlusionValue = TransmissionLossValues[s]; surface.textureID = acousticTexture == null ? AK.Wwise.AcousticTexture.InvalidId : acousticTexture.Id; surface.transmissionLoss = occlusionValue; surface.strName = name + "_" + Mesh.name + "_" + s; for (var i = 0; i < triangleCount; ++i) { var triangle = triangleArray[triangleArrayIdx]; triangle.point0 = (ushort)vertRemap[triangles[3 * i + 0]]; triangle.point1 = (ushort)vertRemap[triangles[3 * i + 1]]; triangle.point2 = (ushort)vertRemap[triangles[3 * i + 2]]; triangle.surface = (ushort)s; if (triangle.point0 != triangle.point1 && triangle.point0 != triangle.point2 && triangle.point1 != triangle.point2) { ++triangleArrayIdx; } else { UnityEngine.Debug.LogFormat("SetGeometryFromMesh({0}): Skipped degenerate triangle({1}, {2}, {3}) in submesh {4}", Mesh.name, 3 * i + 0, 3 * i + 1, 3 * i + 2, s); } } } if (triangleArrayIdx > 0) { var associatedRoomID = AssociatedRoom && AssociatedRoom.enabled ? AssociatedRoom.GetID() : AkRoom.INVALID_ROOM_ID; return AkSoundEngine.SetGeometry( GetID(), triangleArray, (uint)triangleArrayIdx, vertexArray, (uint)vertexArray.Length, surfaceArray, (uint)surfaceArray.Count(), associatedRoomID, EnableDiffraction, EnableDiffractionOnBoundaryEdges, false) == AKRESULT.AK_Success; } else { UnityEngine.Debug.LogFormat("SetGeometry({0}): No valid triangle was found. Geometry was not set", Mesh.name); } } return false; } #endregion IAkSpatialAudioObject }