AkAcousticPortal.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /*******************************************************************************
  2. The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
  3. Technology released in source code form as part of the game integration package.
  4. The content of this file may not be used without valid licenses to the
  5. AUDIOKINETIC Wwise Technology.
  6. Note that the use of the game engine is subject to the Unreal(R) Engine End User
  7. License Agreement at https://www.unrealengine.com/en-US/eula/unreal
  8. License Usage
  9. Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
  10. this file in accordance with the end user license agreement provided with the
  11. software or, alternatively, in accordance with the terms contained
  12. in a written agreement between you and Audiokinetic Inc.
  13. Copyright (c) 2023 Audiokinetic Inc.
  14. *******************************************************************************/
  15. #pragma once
  16. #include "Components/TextRenderComponent.h"
  17. #include "GameFramework/Volume.h"
  18. #include "AkGameplayTypes.h"
  19. #include "Wwise/AkPortalObstructionAndOcclusionService.h"
  20. #if WITH_EDITOR
  21. #include "AkSettings.h"
  22. #endif
  23. #include "AkAcousticPortal.generated.h"
  24. class UAkRoomComponent;
  25. class UAkLateReverbComponent;
  26. class FAkEnvironmentIndex;
  27. UCLASS(ClassGroup = Audiokinetic, hidecategories = (Advanced, Attachment, Volume), BlueprintType, meta = (BlueprintSpawnableComponent))
  28. class AKAUDIO_API UAkPortalComponent : public USceneComponent
  29. {
  30. GENERATED_BODY()
  31. public:
  32. UAkPortalComponent(const class FObjectInitializer& ObjectInitializer);
  33. /**
  34. * Enables the portal. Emitters positioned in the AkRoomComponent in front of and behind the portal emit through it.
  35. */
  36. UFUNCTION(BlueprintCallable, Category = "Audiokinetic|AkPortalComponent")
  37. void EnablePortal();
  38. /**
  39. * Disables the portal. Emitters positioned in the AkRoomComponent in front of and behind the portal do not emit through it.
  40. */
  41. UFUNCTION(BlueprintCallable, Category = "Audiokinetic|AkPortalComponent")
  42. void DisablePortal();
  43. /**
  44. * Returns an AkAcousticPortalState, which represents current the state of the portal: Enabled or Disabled.
  45. */
  46. UFUNCTION(BlueprintCallable, Category = "Audiokinetic|AkPortalComponent")
  47. AkAcousticPortalState GetCurrentState() const;
  48. /**
  49. * Returns a floating point number between 0 and 1 that represents the occlusion value applied to the portal. A value of 0 indicates that the portal is not occluded and a value of 1 indicates that it is completely occluded.
  50. */
  51. UFUNCTION(BlueprintCallable, Category = "Audiokinetic|AkPortalComponent")
  52. float GetPortalOcclusion() const;
  53. /**
  54. * Sets a new portal occlusion value. A value of 0 indicates that the portal is not occluded and a value of 1 indicates that it is completely occluded.
  55. * The occlusion value is applied to the portal with AK::SpatialAudio::SetPortalObstructionAndOcclusion.
  56. * Portal occlusion can be used to modulate sound in response to a door opening or closing.
  57. *
  58. * @param InPortalOcclusion The new portal occlusion value.
  59. */
  60. UFUNCTION(BlueprintCallable, Category = "Audiokinetic|AkPortalComponent")
  61. void SetPortalOcclusion(float InPortalOcclusion);
  62. /**
  63. * Returns the UPrimitiveComponent to which this Ak Portal Component is attached.
  64. */
  65. UFUNCTION(BlueprintCallable, Category = "Audiokinetic|AkPortalComponent")
  66. UPrimitiveComponent* GetPrimitiveParent() const;
  67. /**
  68. * Returns true if the portal position and orientation are valid. Portals have a front and a back room.
  69. * They must have at least one connected room, the front room must be different than the back room, and the rooms cannot be a Reverb Zone and its parent.
  70. */
  71. UFUNCTION(BlueprintCallable, Category = "Audiokinetic|AkPortalComponent")
  72. bool PortalPlacementValid() const;
  73. /**
  74. * If true, the room connections for this portal can change during runtime when this portal moves.
  75. * For worlds containing many rooms, this can be expensive. Note that this portal's room connections may still change, even when bDynamic = false, when dynamic rooms are moved (i.e. when rooms move who have bDynamic = true).
  76. */
  77. UPROPERTY(EditAnywhere, BlueprintSetter = SetDynamic, Category = "AkPortalComponent", meta = (DisplayName = "Is Dynamic"))
  78. bool bDynamic = false;
  79. UFUNCTION(BlueprintSetter, Category = "AkPortalComponent")
  80. void SetDynamic(bool bInDynamic);
  81. /**
  82. * Initially enables or disables the portal. When the portal is enabled, emitters positioned in the AkRoomComponent in front of and behind the portal emit through it.
  83. */
  84. UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "AkPortalComponent")
  85. AkAcousticPortalState InitialState = AkAcousticPortalState::Open;
  86. /**
  87. * The initial occlusion value applied to the portal. When the occlusion value is set to 0, the portal is not occluded, and when it is set to 1, the portal is completely occluded.
  88. * The occlusion value is directly applied to the portal with AK::SpatialAudio::SetPortalObstructionAndOcclusion.
  89. * Portal occlusion can be used to modulate sound in response to a door opening or closing.
  90. */
  91. UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "AkPortalComponent|Obstruction Occlusion", meta = (ClampMin = 0.0f, ClampMax = 1.0f))
  92. float InitialOcclusion = 0.f;
  93. /** Time interval between obstruction checks; a direct line of sight between the current portal and an emitter, a listener, or another portal. Set to 0 to disable obstruction checks. Valid range [0, [.*/
  94. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AkPortalComponent|Obstruction Occlusion", meta = (ClampMin = 0.f))
  95. float ObstructionRefreshInterval = .0f;
  96. /** Collision channel for obstruction checks; a direct line of sight between the current portal and an emitter, a listener, or another portal. */
  97. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AkPortalComponent|Obstruction Occlusion")
  98. TEnumAsByte<ECollisionChannel> ObstructionCollisionChannel = ECollisionChannel::ECC_Visibility;
  99. void ResetPortalState();
  100. void ResetPortalOcclusion();
  101. FVector GetExtent() const;
  102. AkRoomID GetFrontRoomID() const;
  103. AkRoomID GetBackRoomID() const;
  104. AkPortalID GetPortalID() const { return AkPortalID(this); }
  105. /** Update the room connections for the portal, given the portals current transform.
  106. Return true if the room connections have changed.
  107. */
  108. bool UpdateConnectedRooms(bool in_bForceUpdate = false);
  109. void RemovePortalConnections();
  110. const TWeakObjectPtr<UAkRoomComponent> GetFrontRoomComponent() const { return FrontRoom; }
  111. const TWeakObjectPtr<UAkRoomComponent> GetBackRoomComponent() const { return BackRoom; }
  112. virtual void BeginPlay() override;
  113. #if WITH_EDITOR
  114. virtual void BeginDestroy() override;
  115. virtual void InitializeComponent() override;
  116. virtual void OnComponentCreated() override;
  117. virtual void PostLoad() override;
  118. virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override;
  119. void UpdateTextRotations() const;
  120. void UpdateRoomNames();
  121. #endif // WITH_EDITOR
  122. virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction * ThisTickFunction) override;
  123. virtual void OnRegister() override;
  124. virtual void OnUnregister() override;
  125. virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport) override;
  126. virtual bool MoveComponentImpl(
  127. const FVector & Delta,
  128. const FQuat & NewRotation,
  129. bool bSweep,
  130. FHitResult * Hit,
  131. EMoveComponentFlags MoveFlags,
  132. ETeleportType Teleport) override;
  133. FString GetPortalName();
  134. private:
  135. TWeakObjectPtr<class UPrimitiveComponent> Parent;
  136. void InitializeParent();
  137. void SetSpatialAudioPortal();
  138. void FindConnectedComponents(FAkEnvironmentIndex& RoomQuery, TWeakObjectPtr<UAkRoomComponent>& out_pFront, TWeakObjectPtr<UAkRoomComponent>& out_pBack);
  139. AkAcousticPortalState PortalState = AkAcousticPortalState::Open;
  140. float PortalOcclusion = 0.f;
  141. static const float RoomsRefreshIntervalGame;
  142. static const float RoomsRefreshDistanceThreshold;
  143. static const float RoomsRefreshMinRotationThreshold_Degrees;
  144. float RoomsRefreshIntervalSeconds = 0.5f;
  145. float LastRoomsUpdate = 0.0f;
  146. FVector PreviousLocation;
  147. FRotator PreviousRotation;
  148. bool PortalNeedsUpdate = false;
  149. bool PortalOcclusionChanged = false;
  150. bool PortalRoomsNeedUpdate = false;
  151. TWeakObjectPtr<UAkRoomComponent> FrontRoom;
  152. TWeakObjectPtr<UAkRoomComponent> BackRoom;
  153. AkPortalObstructionAndOcclusionService ObstructionServiceFrontRoom;
  154. AkPortalObstructionAndOcclusionService ObstructionServiceBackRoom;
  155. #if WITH_EDITOR
  156. static const float RoomsRefreshIntervalEditor;
  157. void HandleObjectsReplaced(const TMap<UObject*, UObject*>& ReplacementMap);
  158. class UDrawPortalComponent* DrawPortalComponent = nullptr;
  159. void RegisterVisEnabledCallback();
  160. void InitializeDrawComponent();
  161. void DestroyDrawComponent();
  162. FDelegateHandle ShowPortalsChangedHandle;
  163. bool AreTextVisualizersInitialized() const;
  164. void InitTextVisualizers();
  165. void DestroyTextVisualizers();
  166. void UpdateTextVisibility();
  167. // Updates the location, rotation and visibility of the text visualizers
  168. void UpdateTextLocRotVis();
  169. bool bWasSelected = false;
  170. #endif
  171. #if WITH_EDITORONLY_DATA
  172. UPROPERTY(SkipSerialization, NonTransactional)
  173. mutable UTextRenderComponent* FrontRoomText = nullptr;
  174. UPROPERTY(SkipSerialization, NonTransactional)
  175. mutable UTextRenderComponent* BackRoomText = nullptr;
  176. #endif
  177. };
  178. UCLASS(ClassGroup = Audiokinetic, hidecategories = (Advanced, Attachment, Volume), BlueprintType)
  179. class AKAUDIO_API AAkAcousticPortal : public AVolume
  180. {
  181. GENERATED_BODY()
  182. public:
  183. AAkAcousticPortal(const class FObjectInitializer& ObjectInitializer);
  184. UFUNCTION(BlueprintCallable, Category = "Audiokinetic|AkAcousticPortal")
  185. void EnablePortal();
  186. UFUNCTION(BlueprintCallable, Category = "Audiokinetic|AkAcousticPortal")
  187. void DisablePortal();
  188. UFUNCTION(BlueprintCallable, Category = "Audiokinetic|AkAcousticPortal")
  189. AkAcousticPortalState GetCurrentState() const;
  190. UPROPERTY(VisibleAnywhere, Category = "AcousticPortal", BlueprintReadOnly, meta = (ShowOnlyInnerProperties))
  191. UAkPortalComponent* Portal = nullptr;
  192. virtual void PostRegisterAllComponents() override;
  193. virtual void PostLoad() override;
  194. virtual void Serialize(FArchive& Ar) override;
  195. #if WITH_EDITOR
  196. void FitRaycast();
  197. void FitPortal();
  198. virtual void PostEditMove(bool bFinished) override;
  199. virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
  200. bool GetBestHits(FVector& Start0, FVector& End0, FVector& Start1, FVector& End1)
  201. {
  202. if (BestFitValid)
  203. {
  204. Start0 = BestFit[0];
  205. End0 = BestFit[1];
  206. Start1 = BestFit[2];
  207. End1 = BestFit[3];
  208. return true;
  209. }
  210. return false;
  211. }
  212. float GetDetectionRadius() const { return DetectionRadius; }
  213. bool GetFitToGeometry() const { return FitToGeometry; }
  214. bool GetIsDragging() const { return IsDragging; }
  215. virtual FName GetCustomIconName() const override
  216. {
  217. static const FName IconName("ClassIcon.AkAcousticPortal");
  218. return IconName;
  219. }
  220. #endif
  221. protected:
  222. static const int kNumRaycasts = 128;
  223. #if WITH_EDITORONLY_DATA
  224. void ClearBestFit();
  225. /**
  226. Automatically fit the Ak Acoustic Portal to surrounding geometry. The fitting operation is performed after enabling this property, or after moving the actor to a new location.
  227. To find portals in surrounding geometry, rays emanating spherically outwards are cast from the origin of the actor in an attempt to detect sets of parallel surfaces.
  228. The "best" detected parallel surfaces are indicated with yellow outline when dragging the actor to a new location.
  229. */
  230. UPROPERTY(EditAnywhere, Category = "Fit to Geometry")
  231. bool FitToGeometry = false;
  232. /**
  233. Sets the collision channel for the ray traces performed to fit the portal to the surrounding geometry. When set to 'Use Integration Settings Default', the value will be taken from the DefaultFitToGeometryCollisionChannel in the Wwise Integration Settings.
  234. */
  235. UPROPERTY(EditAnywhere, Category = "Fit to Geometry")
  236. TEnumAsByte<EAkCollisionChannel> CollisionChannel = { EAkCollisionChannel::EAKCC_UseIntegrationSettingsDefault };
  237. #if WITH_EDITOR
  238. /**
  239. Converts between EAkCollisionChannel and ECollisionChannel. Returns Wwise Integration Settings default if CollisionChannel == UseIntegrationSettingsDefault. Otherwise, casts CollisionChannel to ECollisionChannel.
  240. */
  241. UFUNCTION(BlueprintCallable, Category = "Fit to Geometry")
  242. ECollisionChannel GetCollisionChannel();
  243. #endif
  244. /**
  245. Limits the effective portal opening size that can be detected when fitting the portal to surrounding geometry.
  246. Increase this value to find larger openings; decrease it if large portals are erroneously detected, for example ones that span whole rooms.
  247. The slider range can be expanded by entering a text value into this field.
  248. */
  249. UPROPERTY(EditAnywhere, Category = "Fit to Geometry", meta = (ClampMin = 1.0f, ClampMax = 100000.0f, UIMin = 100.0f, UIMax = 5000.0f))
  250. float DetectionRadius = 500.0f;
  251. FVector SavedRaycastOrigin;
  252. bool bUseSavedRaycastOrigin = false;
  253. FVector BestFit[4];
  254. bool BestFitValid = false;
  255. bool IsDragging = false;
  256. #endif
  257. private:
  258. /** As of Wwise 2020.1, the InitialState is contained in the AkPortalComponent */
  259. UPROPERTY()
  260. AkAcousticPortalState InitialState;
  261. UPROPERTY(Transient)
  262. bool bRequiresStateMigration = false;
  263. bool bRequiresTransformMigration = false;
  264. };