AkSurfaceReflectorSetComponent.cpp 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403
  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. #include "AkSurfaceReflectorSetComponent.h"
  16. #include "AkAudioDevice.h"
  17. #include "AkComponentHelpers.h"
  18. #include "AkReverbDescriptor.h"
  19. #include "AkRoomComponent.h"
  20. #include "AkSettings.h"
  21. #include "AkSpatialAudioVolume.h"
  22. #include "WwiseUEFeatures.h"
  23. #include "Components/BrushComponent.h"
  24. #include "EngineUtils.h"
  25. #include "Model.h"
  26. #include "GameFramework/Volume.h"
  27. #include "UObject/Object.h"
  28. #if WITH_EDITOR
  29. #include "AkAudioStyle.h"
  30. #include "Editor.h"
  31. #include "EditorGeometry.h"
  32. #include "EditorModeManager.h"
  33. #include "EditorModes.h"
  34. #include "EditorModeTools.h"
  35. #include "GeometryEdMode.h"
  36. #include "LevelEditorViewport.h"
  37. #include "Kismet/KismetMathLibrary.h"
  38. #endif
  39. #if WITH_EDITOR
  40. struct FFacePlane
  41. {
  42. FFacePlane(FVector InOrigin, FVector InUp, FVector InRight)
  43. : Origin(InOrigin)
  44. , Up(InUp)
  45. , Right(InRight)
  46. {}
  47. /* Transform a point in world space to coordinates on the plane. */
  48. FVector2D WorldToPlaneCoordinates(FVector WorldPoint) const
  49. {
  50. float X = FVector::DotProduct((WorldPoint - Origin), Right);
  51. float Y = FVector::DotProduct((WorldPoint - Origin), Up);
  52. return FVector2D(X, Y);
  53. }
  54. /* Transform an edge in world space to an edge defined by plane coordinates. */
  55. void WorldToPlaneEdge(FVector WorldStart, FVector WorldEnd, FVector2D& PlaneStart, FVector2D& PlaneEnd, float ExtendAmount = 0.0f) const
  56. {
  57. PlaneStart = WorldToPlaneCoordinates(WorldStart);
  58. PlaneEnd = WorldToPlaneCoordinates(WorldEnd);
  59. if (ExtendAmount > 0.0f)
  60. {
  61. PlaneStart += (PlaneStart - PlaneEnd).GetSafeNormal() * ExtendAmount;
  62. PlaneEnd += (PlaneEnd - PlaneStart).GetSafeNormal() * ExtendAmount;
  63. }
  64. }
  65. FVector Origin = FVector::ZeroVector;
  66. FVector Up = FVector::UpVector;
  67. FVector Right = FVector::RightVector;
  68. };
  69. namespace TextAlignmentHelpers
  70. {
  71. /* Get the four edges of the text render component in world space. */
  72. TArray<FAkSurfaceEdgeInfo> GetTextEdges(const UTextRenderComponent& TextComp, const FVector& TextBottomLeft, const FFacePlane& FacePlane, const float scale)
  73. {
  74. TArray<FAkSurfaceEdgeInfo> Edges;
  75. FVector LocalTextSize = TextComp.GetTextLocalSize();
  76. const float TextSizeVer = LocalTextSize.Z * scale;
  77. const float TextSizeHor = LocalTextSize.Y * scale;
  78. const FVector BottomRight = TextBottomLeft + TextSizeHor * FacePlane.Right;
  79. const FVector TopLeft = TextBottomLeft + TextSizeVer * FacePlane.Up;
  80. const FVector TopRight = TopLeft + TextSizeHor * FacePlane.Right;
  81. Edges.Add(FAkSurfaceEdgeInfo(TextBottomLeft, BottomRight));
  82. Edges.Add(FAkSurfaceEdgeInfo(TopLeft, TopRight));
  83. Edges.Add(FAkSurfaceEdgeInfo(TextBottomLeft, TopLeft));
  84. Edges.Add(FAkSurfaceEdgeInfo(BottomRight, TopRight));
  85. return Edges;
  86. }
  87. FVector From2D(const FVector2D& Vec2D)
  88. {
  89. return FVector(Vec2D.X, Vec2D.Y, 0.0f);
  90. }
  91. /* Query where BrushEdge bisects TextEdge. BisectionRatio indicates the length ratio at which TextEdge is intersected by BrushEdge.
  92. This is used to determine the scaling factor for the text visualizers on each face. */
  93. void GetTextEdgeBisection(const FAkSurfaceEdgeInfo& TextEdge, const FAkSurfaceEdgeInfo& BrushEdge, const FFacePlane& Plane, float& BisectionRatio)
  94. {
  95. BisectionRatio = 0.0f;
  96. const float Tolerance = 0.1f;
  97. FVector2D TextEdgeStart2D, TextEdgeEnd2D, BrushEdgeStart2D, BrushEdgeEnd2D;
  98. Plane.WorldToPlaneEdge(TextEdge.V0(), TextEdge.V1(), TextEdgeStart2D, TextEdgeEnd2D);
  99. Plane.WorldToPlaneEdge(BrushEdge.V0(), BrushEdge.V1(), BrushEdgeStart2D, BrushEdgeEnd2D, 2.0f);
  100. FVector Intersection = FVector::ZeroVector;
  101. // If TextEdge and BrushEdge are almost parallel, record no intersection.
  102. if (FMath::Abs((FVector2D::DotProduct((BrushEdgeEnd2D - BrushEdgeStart2D).GetSafeNormal(), (TextEdgeEnd2D - TextEdgeStart2D).GetSafeNormal()))) >= 0.95f)
  103. return;
  104. if (FMath::SegmentIntersection2D(From2D(TextEdgeStart2D), From2D(TextEdgeEnd2D), From2D(BrushEdgeStart2D), From2D(BrushEdgeEnd2D), Intersection))
  105. {
  106. // Ignore intersection with the first vertex of TextEdge
  107. if (Intersection.Equals(From2D(TextEdgeStart2D), Tolerance))
  108. return;
  109. BisectionRatio = (Intersection - From2D(TextEdgeStart2D)).Size() / (TextEdgeEnd2D - TextEdgeStart2D).Size();
  110. }
  111. }
  112. /* Use Tangent and Normal to determine the up vector. Uses the viewport client orientation to align up with camera. */
  113. FVector DetermineUpVector(const FVector& Tangent, FVector& Normal, const FVector& CamToCentre)
  114. {
  115. if (GCurrentLevelEditingViewportClient != nullptr)
  116. {
  117. if (FVector::DotProduct(CamToCentre, Normal) < 0.0f)
  118. {
  119. Normal *= -1.0f;
  120. }
  121. }
  122. FVector Up = -FVector::CrossProduct(Tangent, Normal);
  123. Up.Normalize();
  124. if (GCurrentLevelEditingViewportClient != nullptr)
  125. {
  126. FVector CamUp = UKismetMathLibrary::GetUpVector(GCurrentLevelEditingViewportClient->GetViewRotation());
  127. if (FVector::DotProduct(Up, CamUp) < 0.0f)
  128. {
  129. Up *= -1.0f;
  130. }
  131. }
  132. return Up;
  133. }
  134. /* Set the text alignment for TextComp according to where the AlginmentEdge is in relation to the MidPoint. */
  135. void SetTextAlignment(UTextRenderComponent* TextComp, const FAkSurfaceEdgeInfo& AlignmentEdge, const FVector& MidPoint)
  136. {
  137. TextComp->SetHorizontalAlignment(EHTA_Left);
  138. TextComp->SetVerticalAlignment(EVRTA_TextBottom);
  139. const FVector& AnchorVertex = AlignmentEdge.V0();
  140. // 'Probe' slightly up and right of the AnchorVertex to determine how the text should be aligned vertically and horizontally.
  141. FVector TextWorldUp = TextComp->GetUpVector();
  142. FVector Probe = AnchorVertex + TextWorldUp;
  143. if ((MidPoint - Probe).Size() > (MidPoint - AnchorVertex).Size())
  144. TextComp->SetVerticalAlignment(EVRTA_TextTop);
  145. // Since the normal faces out of the face, we actually probe to the "left" of the anchor point (hence the subtract instead of add).
  146. Probe = AnchorVertex - TextComp->GetRightVector();
  147. if ((Probe - AlignmentEdge.V1()).Size() > (AnchorVertex - AlignmentEdge.V1()).Size())
  148. TextComp->SetHorizontalAlignment(EHTA_Right);
  149. }
  150. float GetDistanceScaling(UTextRenderComponent* TextComp)
  151. {
  152. float DistanceScaling = 1.0f;
  153. if (GCurrentLevelEditingViewportClient != nullptr)
  154. {
  155. DistanceScaling = (GCurrentLevelEditingViewportClient->GetViewLocation() - TextComp->GetComponentLocation()).Size();
  156. }
  157. if (DistanceScaling > 1.0f)
  158. {
  159. // empirically derived through experimentation
  160. DistanceScaling = DistanceScaling / 800.0f;
  161. }
  162. return DistanceScaling;
  163. }
  164. }
  165. #endif
  166. UAkSurfaceReflectorSetComponent::UAkSurfaceReflectorSetComponent(const class FObjectInitializer& ObjectInitializer) :
  167. Super(ObjectInitializer)
  168. {
  169. // Property initialization
  170. bWantsOnUpdateTransform = true;
  171. bEnableSurfaceReflectors = true;
  172. bEnableDiffraction = true;
  173. bEnableDiffractionOnBoundaryEdges = false;
  174. #if WITH_EDITOR
  175. PropertyChangedHandle = FCoreUObjectDelegates::OnObjectPropertyChanged.AddUObject(this, &UAkSurfaceReflectorSetComponent::OnPropertyChanged);
  176. PrimaryComponentTick.bCanEverTick = true;
  177. bTickInEditor = true;
  178. WasSelected = false;
  179. #endif
  180. }
  181. void UAkSurfaceReflectorSetComponent::BeginDestroy()
  182. {
  183. Super::BeginDestroy();
  184. #if WITH_EDITOR
  185. FCoreUObjectDelegates::OnObjectPropertyChanged.Remove(PropertyChangedHandle);
  186. #endif
  187. }
  188. void UAkSurfaceReflectorSetComponent::OnRegister()
  189. {
  190. Super::OnRegister();
  191. InitializeParentBrush();
  192. SendSurfaceReflectorSet();
  193. UpdateSurfaceReflectorSet();
  194. #if WITH_EDITOR
  195. if (AssociatedRoom != nullptr)
  196. {
  197. UAkRoomComponent* room = Cast<UAkRoomComponent>(AssociatedRoom->GetComponentByClass(UAkRoomComponent::StaticClass()));
  198. if (room != nullptr)
  199. {
  200. UE_LOG(LogAkAudio, Warning, TEXT("AkSurfaceReflectorSetComponent %s is associated to Room %s. The AssociatedRoom property is deprecated, it will be removed in a future version. We recommend not using it and leaving it set to None."), *GetOwner()->GetName(), *room->GetRoomName());
  201. }
  202. }
  203. #endif
  204. }
  205. void UAkSurfaceReflectorSetComponent::InitializeParentBrush(bool fromTick /* = false */)
  206. {
  207. AVolume* Parent = Cast<AVolume>(GetOwner());
  208. if (Parent)
  209. {
  210. ParentBrush = Parent->Brush;
  211. #if WITH_EDITOR
  212. // For runtime viewports, delay the UpdatePolys call until post-registration in tick.
  213. // When editing geometry in the editor, the brush vertex data can sometimes be out of date at this point, causing the
  214. // EdgeMap to be incorrect, which results in the visualizer drawing incorrect edges.
  215. SchedulePolysUpdate();
  216. #endif
  217. }
  218. else
  219. {
  220. bEnableSurfaceReflectors = false;
  221. ParentBrush = nullptr;
  222. if (!fromTick)
  223. {
  224. FString actorString = FString("NONE");
  225. FString actorClass = FString("NONE");
  226. if (GetOwner() != nullptr)
  227. {
  228. actorString = GetOwner()->GetName();
  229. UClass* ownerClass = GetOwner()->GetClass();
  230. if (ownerClass != nullptr)
  231. actorClass = ownerClass->GetName();
  232. }
  233. UE_LOG(LogAkAudio, Error, TEXT("UAkSurfaceReflectorSetComponent::InitializeParentBrush : Error. Actor %s, of type %s, has an AkSurfaceReflectorSetComponent attached (%s)."), *actorString, *actorClass, *UObject::GetName());
  234. UE_LOG(LogAkAudio, Error, TEXT("UAkSurfaceReflectorSetComponent requires to be attached to an actor inheriting from AVolume."));
  235. }
  236. }
  237. }
  238. void UAkSurfaceReflectorSetComponent::OnUnregister()
  239. {
  240. #if WITH_EDITOR
  241. if (!HasAnyFlags(RF_Transient))
  242. {
  243. DestroyTextVisualizers();
  244. }
  245. #endif
  246. RemoveSurfaceReflectorSet();
  247. Super::OnUnregister();
  248. }
  249. void UAkSurfaceReflectorSetComponent::UpdateAcousticProperties(TArray<FAkSurfacePoly> in_acousticSurfacePoly)
  250. {
  251. AcousticPolys = in_acousticSurfacePoly;
  252. if (ReverbDescriptor != nullptr && ParentBrush != nullptr)
  253. {
  254. ComputeAcousticPolySurfaceArea();
  255. DampingEstimationNeedsUpdate = true;
  256. }
  257. }
  258. void UAkSurfaceReflectorSetComponent::ComputeAcousticPolySurfaceArea()
  259. {
  260. int32 NumFaces = AcousticPolys.Num();
  261. int32 NumBrushFaces = ParentBrush->Nodes.Num();
  262. if (NumBrushFaces > NumFaces)
  263. {
  264. for (int i = 0; i < NumBrushFaces - NumFaces; ++i)
  265. {
  266. FAkSurfacePoly Surface;
  267. Surface.EnableSurface = bEnableSurfaceReflectors;
  268. AcousticPolys.Add(Surface);
  269. }
  270. }
  271. else if (NumBrushFaces < NumFaces)
  272. {
  273. AcousticPolys.RemoveAt(NumBrushFaces, NumFaces - NumBrushFaces);
  274. }
  275. const auto WorldScale = GetOwner()->ActorToWorld().GetScale3D();
  276. for (int32 NodeIdx = 0; NodeIdx < ParentBrush->Nodes.Num(); ++NodeIdx)
  277. {
  278. if (ParentBrush->Nodes[NodeIdx].NumVertices > 2)
  279. {
  280. TArray<FVector> ScaledVertices;
  281. const int32 VertStartIndex = ParentBrush->Nodes[NodeIdx].iVertPool;
  282. FVector CentroidPosition = FVector::ZeroVector;
  283. for (int32 VertIdx = 0; VertIdx < ParentBrush->Nodes[NodeIdx].NumVertices; ++VertIdx)
  284. {
  285. auto Vert = FVector(ParentBrush->Points[ParentBrush->Verts[VertStartIndex + VertIdx].pVertex]) * WorldScale;
  286. CentroidPosition += Vert;
  287. ScaledVertices.Emplace(Vert);
  288. }
  289. CentroidPosition /= (float)ParentBrush->Nodes[NodeIdx].NumVertices;
  290. double Area = 0.0f;
  291. for (int vIndex = 0; vIndex < ScaledVertices.Num() - 1; ++vIndex)
  292. {
  293. Area += FAkReverbDescriptor::TriangleArea(CentroidPosition, ScaledVertices[vIndex], ScaledVertices[vIndex + 1]);
  294. }
  295. Area += FAkReverbDescriptor::TriangleArea(CentroidPosition, ScaledVertices[ScaledVertices.Num() - 1], ScaledVertices[0]);
  296. AcousticPolys[NodeIdx].SetSurfaceArea(Area);
  297. }
  298. }
  299. }
  300. #if WITH_EDITOR
  301. TSet<int> UAkSurfaceReflectorSetComponent::GetSelectedFaceIndices() const
  302. {
  303. TSet<int> selectedFaceIndices;
  304. // Determine if we are in geometry edit mode.
  305. if (GLevelEditorModeTools().IsModeActive(FEditorModeID(TEXT("EM_Geometry"))))
  306. {
  307. // If we are in geometry mode, go through the list of geometry objects
  308. // and find our current brush and update its source data as it might have changed
  309. // in RecomputePoly
  310. if (ABrush* ownerBrush = Cast<ABrush>(GetOwner()))
  311. {
  312. FEdModeGeometry* GeomMode = (FEdModeGeometry*)GLevelEditorModeTools().GetActiveMode(FEditorModeID(TEXT("EM_Geometry")));
  313. FEdModeGeometry::TGeomObjectIterator GeomModeIt = GeomMode->GeomObjectItor();
  314. const float tolerance = 0.001f;
  315. for (; GeomModeIt; ++GeomModeIt)
  316. {
  317. FGeomObjectPtr Object = *GeomModeIt;
  318. if (Object->GetActualBrush() == ownerBrush)
  319. {
  320. // selectedGeometry is a list of selected geometry elements. They can be vertices, edges, or polys
  321. TArray<FGeomBase*> selectedGeometry = Object->SelectionOrder;
  322. for (FGeomBase* selection : selectedGeometry)
  323. {
  324. if (!selection->IsVertex())
  325. {
  326. // There is no way to distinguish an edge from a poly, and we are unable to downcast.
  327. // Check the normal and mid point against the normal and mid point of each face in our model.
  328. // If we find the corresponding face, add its index to the selectedFaceIndices list.
  329. for (int32 NodeIdx = 0; NodeIdx < ParentBrush->Nodes.Num() && NodeIdx < AcousticPolys.Num(); ++NodeIdx)
  330. {
  331. if (FMath::IsNearlyEqual((selection->GetNormal() - FPlane(ParentBrush->Nodes[NodeIdx].Plane)).Size(), 0.0f, tolerance)
  332. && FMath::IsNearlyEqual((selection->GetMid() - AcousticPolys[NodeIdx].MidPoint).Size(), 0.0f, tolerance))
  333. {
  334. selectedFaceIndices.Add(NodeIdx);
  335. break;
  336. }
  337. }
  338. }
  339. }
  340. break;
  341. }
  342. }
  343. }
  344. }
  345. return selectedFaceIndices;
  346. }
  347. void UAkSurfaceReflectorSetComponent::CacheAcousticProperties()
  348. {
  349. ensure(PreviousPolys.Num() == AcousticPolys.Num());
  350. for (int FaceIndex = 0; FaceIndex < PreviousPolys.Num(); ++FaceIndex)
  351. {
  352. PreviousPolys[FaceIndex].Texture = AcousticPolys[FaceIndex].Texture;
  353. PreviousPolys[FaceIndex].Occlusion = AcousticPolys[FaceIndex].Occlusion;
  354. PreviousPolys[FaceIndex].EnableSurface = AcousticPolys[FaceIndex].EnableSurface;
  355. }
  356. }
  357. void UAkSurfaceReflectorSetComponent::CacheLocalSpaceSurfaceGeometry()
  358. {
  359. PreviousPolys = AcousticPolys;
  360. }
  361. bool UAkSurfaceReflectorSetComponent::TexturesDiffer() const
  362. {
  363. if (AcousticPolys.Num() == 0)
  364. return false;
  365. UAkAcousticTexture* texture = AcousticPolys[0].Texture;
  366. for (const FAkSurfacePoly& Poly : AcousticPolys)
  367. {
  368. if (Poly.Texture != texture)
  369. return true;
  370. }
  371. return false;
  372. }
  373. void UAkSurfaceReflectorSetComponent::OnPropertyChanged(UObject* ObjectBeingModified, FPropertyChangedEvent& PropertyChangedEvent)
  374. {
  375. bool changeAffectsThis = false;
  376. if (AActor* actor = Cast<AActor>(ObjectBeingModified))
  377. {
  378. if (actor == GetOwner())
  379. {
  380. changeAffectsThis = true;
  381. }
  382. }
  383. if (USceneComponent* component = Cast<USceneComponent>(ObjectBeingModified))
  384. {
  385. if (component->GetOwner() == GetOwner())
  386. {
  387. changeAffectsThis = true;
  388. }
  389. }
  390. if (changeAffectsThis)
  391. {
  392. // The start of a UI interaction will trigger a EPropertyChangeType::Interactive.
  393. // This will be followed by a EPropertyChangeType::ValueSet at the end of the interaction.
  394. if (PropertyChangedEvent.ChangeType == EPropertyChangeType::Interactive)
  395. {
  396. UserInteractionInProgress = true;
  397. }
  398. if (UserInteractionInProgress && PropertyChangedEvent.ChangeType == EPropertyChangeType::ValueSet)
  399. {
  400. UserInteractionInProgress = false;
  401. }
  402. }
  403. }
  404. void UAkSurfaceReflectorSetComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
  405. {
  406. Super::PostEditChangeProperty(PropertyChangedEvent);
  407. InitializeParentBrush();
  408. if (ParentBrush != nullptr)
  409. {
  410. UpdatePolys();
  411. }
  412. if (AssociatedRoom && !Cast<UAkRoomComponent>(AssociatedRoom->GetComponentByClass(UAkRoomComponent::StaticClass())))
  413. {
  414. UE_LOG(LogAkAudio, Warning, TEXT("%s: The Surface Reflector Set's Associated Room is not of type UAkRoomComponent."), *GetOwner()->GetName());
  415. }
  416. const FName MemberPropertyName = (PropertyChangedEvent.MemberProperty != nullptr) ? PropertyChangedEvent.MemberProperty->GetFName() : NAME_None;
  417. if (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSurfaceReflectorSetComponent, AcousticPolys))
  418. {
  419. RegisterAllTextureParamCallbacks();
  420. DampingEstimationNeedsUpdate = true;
  421. }
  422. }
  423. void UAkSurfaceReflectorSetComponent::PostEditUndo()
  424. {
  425. OnRefreshDetails.ExecuteIfBound();
  426. Super::PostEditUndo();
  427. // After the undo operation has finished, re-populate the PreviousPolys array to the current state.
  428. CacheLocalSpaceSurfaceGeometry();
  429. }
  430. void UAkSurfaceReflectorSetComponent::PreEditUndo()
  431. {
  432. // Empty the previous polys such that any surface properties are correctly reverted.
  433. PreviousPolys.Empty();
  434. Super::PreEditUndo();
  435. }
  436. FText UAkSurfaceReflectorSetComponent::GetPolyText(int32 PolyIdx) const
  437. {
  438. if (PolyIdx >= AcousticPolys.Num())
  439. return FText();
  440. return AcousticPolys[PolyIdx].GetPolyText(bEnableSurfaceReflectors);
  441. }
  442. void UAkSurfaceReflectorSetComponent::UpdateText(bool Visible)
  443. {
  444. bool bReallyVisible = GetWorld() && GetWorld()->WorldType == EWorldType::Editor && Visible;
  445. if (GetOwner() != nullptr)
  446. {
  447. const AAkSpatialAudioVolume* SpatialAudioVolume = Cast<const AAkSpatialAudioVolume>(GetOwner());
  448. if (SpatialAudioVolume != nullptr && SpatialAudioVolume->FitToGeometry)
  449. bReallyVisible &= (!SpatialAudioVolume->IsDragging || SpatialAudioVolume->FitFailed);
  450. }
  451. for (int32 i = 0; i < TextVisualizers.Num(); i++)
  452. {
  453. if (TextVisualizers[i])
  454. {
  455. TextVisualizers[i]->SetText(GetPolyText(i));
  456. TextVisualizers[i]->SetVisibility(bReallyVisible);
  457. }
  458. }
  459. UpdateTextPositions();
  460. }
  461. void UAkSurfaceReflectorSetComponent::SurfacePropertiesChanged()
  462. {
  463. CacheAcousticProperties();
  464. UpdateText(GetOwner() && GetOwner()->IsSelected());
  465. RegisterAllTextureParamCallbacks();
  466. DampingEstimationNeedsUpdate = true;
  467. }
  468. void UAkSurfaceReflectorSetComponent::DestroyTextVisualizers()
  469. {
  470. for (int32 i = 0; i < TextVisualizers.Num(); i++)
  471. {
  472. if(TextVisualizers[i])
  473. TextVisualizers[i]->DestroyComponent();
  474. }
  475. TextVisualizers.Empty();
  476. }
  477. void UAkSurfaceReflectorSetComponent::SchedulePolysUpdate()
  478. {
  479. if (GetWorld()->ShouldTick())
  480. {
  481. PolysNeedUpdate = true;
  482. }
  483. else
  484. {
  485. if (ParentBrush && ParentBrush->Nodes.Num() != AcousticPolys.Num())
  486. {
  487. UpdatePolys();
  488. }
  489. }
  490. }
  491. void UAkSurfaceReflectorSetComponent::UpdatePolys()
  492. {
  493. if (!ParentBrush || HasAnyFlags(RF_Transient) || UserInteractionInProgress)
  494. {
  495. return;
  496. }
  497. const bool shouldRefreshDetails = AcousticPolys.Num() != ParentBrush->Nodes.Num();
  498. ComputeAcousticPolySurfaceArea();
  499. // Always recreate all text visualizers as indexes may have changed.
  500. DestroyTextVisualizers();
  501. UMaterialInterface* mat = Cast<UMaterialInterface>(FAkAudioStyle::GetAkForegroundTextMaterial());
  502. for (int32 i = 0; i < AcousticPolys.Num(); i++)
  503. {
  504. FString VizName = GetOwner()->GetName() + GetName() + TEXT("TextViz ") + FString::FromInt(i);
  505. if (AcousticPolys[i].EnableSurface)
  506. {
  507. int32 idx = TextVisualizers.Add(NewObject<UTextRenderComponent>(GetOuter(), *VizName));
  508. if (TextVisualizers[idx])
  509. {
  510. if (mat != nullptr)
  511. TextVisualizers[idx]->SetTextMaterial(mat);
  512. TextVisualizers[idx]->RegisterComponentWithWorld(GetWorld());
  513. TextVisualizers[idx]->AttachToComponent(this, FAttachmentTransformRules::KeepWorldTransform);
  514. TextVisualizers[idx]->bIsEditorOnly = true;
  515. TextVisualizers[idx]->bSelectable = false;
  516. TextVisualizers[idx]->bAlwaysRenderAsText = true;
  517. TextVisualizers[idx]->SetHorizontalAlignment(EHTA_Center);
  518. TextVisualizers[idx]->SetVerticalAlignment(EVRTA_TextCenter);
  519. }
  520. }
  521. else
  522. {
  523. TextVisualizers.Add(nullptr);
  524. }
  525. }
  526. UpdateEdgeMap();
  527. UpdateText(GetOwner() && GetOwner()->IsSelected());
  528. RegisterAllTextureParamCallbacks();
  529. DampingEstimationNeedsUpdate = true;
  530. PolysNeedUpdate = false;
  531. if (shouldRefreshDetails)
  532. OnRefreshDetails.ExecuteIfBound();
  533. }
  534. FUnrealFloatVector GetModelCenter(const UModel& Model)
  535. {
  536. FUnrealFloatVector Center(0.f);
  537. uint32 Count = 0;
  538. for (int32 NodeIndex = 0; NodeIndex < Model.Nodes.Num(); NodeIndex++)
  539. {
  540. const FBspNode& Node = Model.Nodes[NodeIndex];
  541. const uint32 NumVerts = (Node.NodeFlags & PF_TwoSided) ? Node.NumVertices / 2 : Node.NumVertices;
  542. for (uint32 VertexIndex = 0; VertexIndex < NumVerts; VertexIndex++)
  543. {
  544. const FVert& Vert = Model.Verts[Node.iVertPool + VertexIndex];
  545. const auto& Position = Model.Points[Vert.pVertex];
  546. Center += Position;
  547. Count++;
  548. }
  549. }
  550. if (Count > 0)
  551. {
  552. Center /= Count;
  553. }
  554. return Center;
  555. }
  556. void UAkSurfaceReflectorSetComponent::SortFaceEdges(int FaceIndex)
  557. {
  558. FAkSurfacePoly& Face = AcousticPolys[FaceIndex];
  559. if (Face.Edges.Num() < 2)
  560. return;
  561. for (int SortedPosition = 1; SortedPosition < Face.Edges.Num(); ++SortedPosition)
  562. {
  563. const FVector& PreviousV1 = Face.Edges[SortedPosition - 1].V1;
  564. for (int IndexToSwap = SortedPosition; IndexToSwap < Face.Edges.Num(); ++IndexToSwap)
  565. {
  566. const FVector& CurrentV0 = Face.Edges[IndexToSwap].V0;
  567. const FVector& CurrentV1 = Face.Edges[IndexToSwap].V1;
  568. if (PreviousV1.Equals(CurrentV0, AkSurfaceReflectorUtils::EQUALITY_THRESHOLD)
  569. || PreviousV1.Equals(CurrentV1, AkSurfaceReflectorUtils::EQUALITY_THRESHOLD))
  570. {
  571. Face.Edges.Swap(SortedPosition, IndexToSwap);
  572. if (PreviousV1.Equals(CurrentV1, AkSurfaceReflectorUtils::EQUALITY_THRESHOLD))
  573. {
  574. Face.Edges[SortedPosition].Invert();
  575. }
  576. break;
  577. }
  578. }
  579. }
  580. }
  581. void UAkSurfaceReflectorSetComponent::UpdateFaceNormals(int FaceIndex)
  582. {
  583. FAkSurfacePoly& Face = AcousticPolys[FaceIndex];
  584. FVector E0 = Face.Edges[0].GetUnitVector();
  585. FVector E1 = Face.Edges[1].GetUnitVector();
  586. const float AlmostParallel = 0.99f;
  587. if (FVector::DotProduct(E0, E1) >= AlmostParallel)
  588. return;
  589. Face.Normal = FVector::CrossProduct(E0, E1);
  590. Face.Normal.Normalize();
  591. if (ParentBrush != nullptr)
  592. {
  593. const FVector BrushCentre = FVector(GetModelCenter(*ParentBrush));
  594. FVector VToCentre = BrushCentre - Face.Edges[0].V0;
  595. VToCentre.Normalize();
  596. if (FVector::DotProduct(VToCentre, Face.Normal) > 0.0f)
  597. {
  598. // normal is pointing in wrong direction. Flip the ends of each Edge.
  599. for (int EdgeIndex = 0; EdgeIndex < Face.Edges.Num(); ++EdgeIndex)
  600. {
  601. Face.Edges[EdgeIndex].Invert();
  602. }
  603. Face.Normal *= -1.0f;
  604. Face.Normal.Normalize();
  605. }
  606. }
  607. }
  608. void UAkSurfaceReflectorSetComponent::UpdateEdgeMap()
  609. {
  610. EdgeMap.Empty();
  611. const AAkSpatialAudioVolume* SpatialAudioVolume = Cast<const AAkSpatialAudioVolume>(GetOwner());
  612. if (ParentBrush != nullptr && SpatialAudioVolume != nullptr)
  613. {
  614. for (int32 NodeIdx = 0; NodeIdx < ParentBrush->Nodes.Num() && NodeIdx < AcousticPolys.Num(); ++NodeIdx)
  615. {
  616. AcousticPolys[NodeIdx].ClearEdgeInfo();
  617. FVector PolyMidPoint(0, 0, 0);
  618. int32 NumVertices = ParentBrush->Nodes[NodeIdx].NumVertices;
  619. // from the unreal doc: If the node has zero vertices, it's only used for splitting and doesn't contain a polygon (this happens in the editor).
  620. if (NumVertices == 0)
  621. {
  622. AcousticPolys[NodeIdx].MidPoint = PolyMidPoint;
  623. continue;
  624. }
  625. FVector PolyWorldSpaceNormal(0, 0, 0);
  626. FAkSurfaceEdgeInfo EdgeInfo;
  627. FUnrealFloatPlane& Plane = ParentBrush->Nodes[NodeIdx].Plane;
  628. EdgeInfo.Normal = FVector(Plane.X, Plane.Y, Plane.Z);
  629. EdgeInfo.IsEnabled = AcousticPolys[NodeIdx].EnableSurface;
  630. int32 VertStartIndex = ParentBrush->Nodes[NodeIdx].iVertPool;
  631. FVert BrushVert0 = ParentBrush->Verts[VertStartIndex];
  632. FVert BrushVert1 = ParentBrush->Verts[VertStartIndex + 1];
  633. // Add edges to map for edges visualization
  634. for (int32 Idx0 = NumVertices - 1, Idx1 = 0;
  635. Idx1 < NumVertices;
  636. Idx0 = Idx1, Idx1++)
  637. {
  638. BrushVert0 = ParentBrush->Verts[VertStartIndex + Idx0];
  639. BrushVert1 = ParentBrush->Verts[VertStartIndex + Idx1];
  640. PolyMidPoint += FVector(ParentBrush->Points[BrushVert1.pVertex]);
  641. EdgeInfo.SetV0(FVector(ParentBrush->Points[BrushVert0.pVertex]));
  642. EdgeInfo.SetV1(FVector(ParentBrush->Points[BrushVert1.pVertex]));
  643. int64 EdgeHash = EdgeInfo.GetHash();
  644. FAkSurfaceEdgeInfo* Found = EdgeMap.Find(EdgeHash);
  645. if (Found)
  646. {
  647. const float DP = FVector::DotProduct(Found->Normal, EdgeInfo.Normal);
  648. if (FMath::IsNearlyEqual(DP, 1.0f, 0.00001f))
  649. Found->IsFlat = true;
  650. else
  651. Found->IsBoundary = !(Found->IsEnabled && EdgeInfo.IsEnabled);
  652. AcousticPolys[NodeIdx].Edges.Add(EdgeInfo.EdgeVerts);
  653. Found->IsEnabled |= EdgeInfo.IsEnabled;
  654. }
  655. else
  656. {
  657. EdgeMap.Add(EdgeHash, EdgeInfo);
  658. AcousticPolys[NodeIdx].Edges.Add(EdgeInfo.EdgeVerts);
  659. }
  660. }
  661. PolyMidPoint /= (float)NumVertices;
  662. AcousticPolys[NodeIdx].MidPoint = PolyMidPoint;
  663. SortFaceEdges(NodeIdx);
  664. // Non-uniform scaling of dimensions will skew the normals stored in the brush, so we need to recaluclate them here
  665. // taking scaling into account.
  666. UpdateFaceNormals(NodeIdx);
  667. }
  668. EdgeMapChanged();
  669. }
  670. CacheLocalSpaceSurfaceGeometry();
  671. }
  672. void UAkSurfaceReflectorSetComponent::EdgeMapChanged()
  673. {
  674. if (PreviousPolys.Num() <= 0)
  675. return;
  676. for (int FaceIndex = 0; FaceIndex < AcousticPolys.Num(); ++FaceIndex)
  677. {
  678. FAkSurfacePoly& Face = AcousticPolys[FaceIndex];
  679. if (Face.Edges.Num() == 0)
  680. continue;
  681. FVector ComponentNormal = Face.Normal;
  682. ComponentNormal.Normalize();
  683. const float Thresh = AkSurfaceReflectorUtils::EQUALITY_THRESHOLD;
  684. for (int OtherFaceIndex = 0; OtherFaceIndex < PreviousPolys.Num(); ++OtherFaceIndex)
  685. {
  686. FAkSurfacePoly& PreviousFace = PreviousPolys[OtherFaceIndex];
  687. if (!ComponentNormal.Equals(PreviousFace.Normal, Thresh))
  688. continue;
  689. int NumSharedEdges = 0;
  690. int EdgeIndex = 0;
  691. while (NumSharedEdges < 2 && EdgeIndex < Face.Edges.Num())
  692. {
  693. FAkSurfaceEdgeVerts Edge = Face.Edges[EdgeIndex];
  694. for (int OtherEdgeIndex = 0; OtherEdgeIndex < PreviousFace.Edges.Num(); ++OtherEdgeIndex)
  695. {
  696. const FAkSurfaceEdgeVerts& PreviousEdge = PreviousFace.Edges[OtherEdgeIndex];
  697. const float EdgeDP = FVector::DotProduct(Edge.GetUnitVector(), PreviousEdge.GetUnitVector());
  698. if (FMath::IsNearlyEqual(EdgeDP, 1.0f, Thresh) && (FAkSurfaceEdgeVerts::EdgesShareVertex(Edge, PreviousEdge)))
  699. {
  700. ++NumSharedEdges;
  701. break;
  702. }
  703. }
  704. ++EdgeIndex;
  705. }
  706. if (NumSharedEdges >= 2)
  707. {
  708. Face.Texture = PreviousFace.Texture;
  709. Face.Occlusion = PreviousFace.Occlusion;
  710. Face.EnableSurface = PreviousFace.EnableSurface;
  711. break;
  712. }
  713. }
  714. }
  715. }
  716. int UAkSurfaceReflectorSetComponent::ChooseAlignmentEdge(int FaceIndex) const
  717. {
  718. int EdgeChoice = 0;
  719. if (GCurrentLevelEditingViewportClient != nullptr
  720. && ParentBrush != nullptr
  721. && FaceIndex < TextVisualizers.Num()
  722. && FaceIndex < ParentBrush->Nodes.Num()
  723. && FaceIndex < AcousticPolys.Num())
  724. {
  725. FVector CamUp = UKismetMathLibrary::GetUpVector(GCurrentLevelEditingViewportClient->GetViewRotation());
  726. UTextRenderComponent* TextComp = TextVisualizers[FaceIndex];
  727. FVector Normal = AcousticPolys[FaceIndex].Normal;
  728. Normal.Normalize();
  729. const FAkSurfacePoly& Face = AcousticPolys[FaceIndex];
  730. FVector AlignmentV0 = FVector::ZeroVector;
  731. FVector AlignmentV1 = FVector::ZeroVector;
  732. for (int EdgeIndex = 0; EdgeIndex < Face.Edges.Num(); ++EdgeIndex)
  733. {
  734. AlignmentV0 = Face.Edges[EdgeIndex].V0;
  735. AlignmentV1 = Face.Edges[EdgeIndex].V1;
  736. FVector Tangent = AlignmentV1 - AlignmentV0;
  737. Tangent.Normalize();
  738. FVector Up = -FVector::CrossProduct(Tangent, Normal);
  739. Up.Normalize();
  740. float DP = FMath::Abs(FVector::DotProduct(CamUp, Up));
  741. const float DPDiffThresh = 0.1f;
  742. if (DP > AcousticPolys[FaceIndex].OptimalEdgeDP && FMath::Abs(DP - AcousticPolys[FaceIndex].OptimalEdgeDP) > DPDiffThresh)
  743. {
  744. AcousticPolys[FaceIndex].OptimalEdgeDP = DP;
  745. EdgeChoice = EdgeIndex;
  746. }
  747. }
  748. }
  749. return EdgeChoice;
  750. }
  751. FVector UAkSurfaceReflectorSetComponent::GetTextAnchorPosition(int FaceIndex, const FAkSurfaceEdgeInfo& AlignmentEdge, int AlignmentEdgeIndex) const
  752. {
  753. UTextRenderComponent* TextComp = TextVisualizers[FaceIndex];
  754. TextComp->SetWorldLocation(AlignmentEdge.V0());
  755. const FAkSurfacePoly& Face = AcousticPolys[FaceIndex];
  756. // Find the edge that connectes to the first vertex of the AlignmentEdge
  757. int ConnectedEdgeIndex = (AlignmentEdgeIndex - 1) < 0 ? Face.Edges.Num() - 1 : AlignmentEdgeIndex - 1;
  758. const FAkSurfaceEdgeVerts* ConnectedEdge = &Face.Edges[ConnectedEdgeIndex];
  759. if (!ConnectedEdge->V1.Equals(AlignmentEdge.V0(), AkSurfaceReflectorUtils::EQUALITY_THRESHOLD))
  760. {
  761. ConnectedEdgeIndex = (AlignmentEdgeIndex + 1) % Face.Edges.Num();
  762. ConnectedEdge = &Face.Edges[ConnectedEdgeIndex];
  763. if (!ConnectedEdge->V1.Equals(AlignmentEdge.V0(), AkSurfaceReflectorUtils::EQUALITY_THRESHOLD))
  764. return AlignmentEdge.V0();
  765. }
  766. const FVector NormedConnectedEdge = -ConnectedEdge->GetUnitVector();
  767. const FVector AlignmentEdgeUnitV = (AlignmentEdge.V1() - AlignmentEdge.V0()).GetSafeNormal();
  768. const float AlignmentCornerDP = FVector::DotProduct(NormedConnectedEdge, AlignmentEdgeUnitV);
  769. FVector Shift(0.0f);
  770. if (AlignmentCornerDP > 0.0f)
  771. {
  772. float ProjCornerV = FMath::Abs(FVector::DotProduct(NormedConnectedEdge, AlignmentEdgeUnitV));
  773. float MaxWidth = (AlignmentEdge.V1() - AlignmentEdge.V0()).Size() / 2.0f;
  774. Shift = ProjCornerV * MaxWidth * AlignmentEdgeUnitV;
  775. }
  776. return AlignmentEdge.V0() + Shift;
  777. }
  778. void UAkSurfaceReflectorSetComponent::SetTextScale(UTextRenderComponent* TextComp, int FaceIndex, int AlignmentEdgeIndex, const FVector& TextAnchorPosition, const FFacePlane& FacePlane, const FTransform& AttachTransform) const
  779. {
  780. const FAkSurfacePoly& Face = AcousticPolys[FaceIndex];
  781. if (Face.Edges.Num() == 0)
  782. return;
  783. float Scale = TextAlignmentHelpers::GetDistanceScaling(TextComp);
  784. bool IntersectionFound = true;
  785. // Look for intersections between the edges of the text visualizer and the edges of the face.
  786. // Scale down by the smallest amount until no more intersections are found.
  787. while (IntersectionFound)
  788. {
  789. TArray<FAkSurfaceEdgeInfo> TextEdges = TextAlignmentHelpers::GetTextEdges(*TextComp, TextAnchorPosition, FacePlane, Scale);
  790. float ScaleDown = 0.0f;
  791. float BisectionRatio;
  792. for (const FAkSurfaceEdgeInfo& TextEdge : TextEdges)
  793. {
  794. for (int EdgeIndex = 0; EdgeIndex < Face.Edges.Num(); ++EdgeIndex)
  795. {
  796. if (EdgeIndex != AlignmentEdgeIndex)
  797. {
  798. FVector BrushEdgeV0 = AttachTransform.TransformPosition(Face.Edges[EdgeIndex].V0);
  799. FVector BrushEdgeV1 = AttachTransform.TransformPosition(Face.Edges[EdgeIndex].V1);
  800. FAkSurfaceEdgeInfo brushEdge(BrushEdgeV0, BrushEdgeV1);
  801. FVector intersection = FVector::ZeroVector;
  802. TextAlignmentHelpers::GetTextEdgeBisection(TextEdge, brushEdge, FacePlane, BisectionRatio);
  803. if (BisectionRatio > ScaleDown && BisectionRatio < 1.0f)
  804. ScaleDown = BisectionRatio;
  805. }
  806. }
  807. }
  808. if (ScaleDown > 0.0f)
  809. Scale *= ScaleDown;
  810. else
  811. IntersectionFound = false;
  812. }
  813. TextComp->SetWorldScale3D(FVector(FMath::Max(1.0f, Scale)));
  814. }
  815. void UAkSurfaceReflectorSetComponent::AlignTextWithEdge(int FaceIndex) const
  816. {
  817. if (GCurrentLevelEditingViewportClient != nullptr
  818. && ParentBrush != nullptr
  819. && FaceIndex < TextVisualizers.Num()
  820. && FaceIndex < ParentBrush->Nodes.Num()
  821. && FaceIndex < AcousticPolys.Num())
  822. {
  823. USceneComponent* ParentComp = GetAttachParent();
  824. if (ParentComp != nullptr)
  825. {
  826. UTextRenderComponent* TextComp = TextVisualizers[FaceIndex];
  827. if (TextComp != nullptr)
  828. {
  829. const FAkSurfacePoly& Face = AcousticPolys[FaceIndex];
  830. if (Face.Edges.Num() == 0)
  831. return;
  832. const FTransform& AttachTransform = ParentComp->GetComponentTransform();
  833. const FRotator& Rotation = ParentComp->GetComponentRotation();
  834. int EdgeIndex = ChooseAlignmentEdge(FaceIndex);
  835. FVector TextAnchorPosition = AttachTransform.TransformPosition(GetTextAnchorPosition(FaceIndex, FAkSurfaceEdgeInfo(Face.Edges[EdgeIndex].V0, Face.Edges[EdgeIndex].V1), EdgeIndex));
  836. TextComp->SetWorldLocation(TextAnchorPosition);
  837. FVector AlignmentV0 = AttachTransform.TransformPosition(Face.Edges[EdgeIndex].V0);
  838. FVector AlignmentV1 = AttachTransform.TransformPosition(Face.Edges[EdgeIndex].V1);
  839. FVector MidPoint = AttachTransform.TransformPosition(Face.MidPoint);
  840. FVector Normal = Rotation.RotateVector(Face.Normal);
  841. Normal.Normalize();
  842. FVector Edge = AlignmentV1 - AlignmentV0;
  843. FVector Tangent = Edge;
  844. Tangent.Normalize();
  845. FVector CamToCentre = GCurrentLevelEditingViewportClient->GetViewLocation() - AlignmentV0 + Edge * 0.5f;
  846. FVector Up = TextAlignmentHelpers::DetermineUpVector(Tangent, Normal, CamToCentre);
  847. TextComp->SetWorldRotation(UKismetMathLibrary::MakeRotFromXZ(Normal, Up));
  848. TextAlignmentHelpers::SetTextAlignment(TextComp, FAkSurfaceEdgeInfo(AlignmentV0, AlignmentV1), MidPoint);
  849. FFacePlane FacePlane(AlignmentV0, TextComp->VerticalAlignment == EVRTA_TextBottom ? Up : -Up, Edge.GetSafeNormal());
  850. SetTextScale(TextComp, FaceIndex, EdgeIndex, TextAnchorPosition, FacePlane, AttachTransform);
  851. }
  852. }
  853. }
  854. }
  855. void UAkSurfaceReflectorSetComponent::UpdateTextPositions() const
  856. {
  857. const AAkSpatialAudioVolume* SpatialAudioVolume = Cast<const AAkSpatialAudioVolume>(GetOwner());
  858. if (ParentBrush != nullptr && SpatialAudioVolume != nullptr)
  859. {
  860. // For each text visualizer, find an appropriate edge on the face and align that visualizer with the edge.
  861. for (int32 NodeIdx = 0; NodeIdx < ParentBrush->Nodes.Num() && NodeIdx < TextVisualizers.Num(); ++NodeIdx)
  862. {
  863. UTextRenderComponent* TextComp = TextVisualizers[NodeIdx];
  864. if (TextComp != nullptr)
  865. {
  866. AlignTextWithEdge(NodeIdx);
  867. }
  868. }
  869. }
  870. }
  871. void UAkSurfaceReflectorSetComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
  872. {
  873. Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
  874. if (!ParentBrush)
  875. {
  876. InitializeParentBrush(true);
  877. }
  878. const bool bNumBrushNodesChanged = (ParentBrush && ParentBrush->Nodes.Num() != AcousticPolys.Num());
  879. if (PolysNeedUpdate || bNumBrushNodesChanged)
  880. {
  881. UpdatePolys();
  882. }
  883. if (GetOwner()->IsSelected() && !WasSelected)
  884. {
  885. WasSelected = true;
  886. UpdateText(true);
  887. }
  888. if (!GetOwner()->IsSelected() && WasSelected)
  889. {
  890. WasSelected = false;
  891. UpdateText(false);
  892. }
  893. }
  894. #endif // WITH_EDITOR
  895. bool UAkSurfaceReflectorSetComponent::MoveComponentImpl(
  896. const FVector& Delta,
  897. const FQuat& NewRotation,
  898. bool bSweep,
  899. FHitResult* Hit,
  900. EMoveComponentFlags MoveFlags,
  901. ETeleportType Teleport)
  902. {
  903. if (USceneComponent* Parent = GetAttachParent())
  904. if (AkComponentHelpers::DoesMovementRecenterChild(this, Parent, Delta))
  905. Super::MoveComponentImpl(Delta, NewRotation, bSweep, Hit, MoveFlags, Teleport);
  906. return false;
  907. }
  908. void UAkSurfaceReflectorSetComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport)
  909. {
  910. Super::OnUpdateTransform(UpdateTransformFlags, Teleport);
  911. UpdateSurfaceReflectorSet();
  912. #if WITH_EDITOR
  913. UpdateEdgeMap();
  914. UpdateText(GetOwner() && GetOwner()->IsSelected());
  915. #endif
  916. }
  917. void UAkSurfaceReflectorSetComponent::GetTexturesAndSurfaceAreas(TArray<FAkAcousticTextureParams>& textures, TArray<float>& surfaceAreas) const
  918. {
  919. const UAkSettings* AkSettings = GetDefault<UAkSettings>();
  920. if (AkSettings != nullptr)
  921. {
  922. if (AcousticPolys.Num() > 0)
  923. {
  924. for (const FAkSurfacePoly& Poly : AcousticPolys)
  925. {
  926. if (Poly.Texture && Poly.EnableSurface)
  927. {
  928. surfaceAreas.Add(Poly.GetSurfaceArea() / AkComponentHelpers::UnrealUnitsPerSquaredMeter(this));
  929. FAkAcousticTextureParams params;
  930. #if WITH_EDITOR
  931. // Get the most accurate absorption values from the list in the AkSettings
  932. auto ParamsFound = AkSettings->GetTextureParams(Poly.Texture->GetShortID());
  933. if (ParamsFound != nullptr)
  934. {
  935. params = *ParamsFound;
  936. }
  937. #else
  938. // Get the absorption values from the cooked data
  939. params.AbsorptionValues = FVector4(
  940. Poly.Texture->AcousticTextureCookedData.AbsorptionLow / 100.0f,
  941. Poly.Texture->AcousticTextureCookedData.AbsorptionMidLow / 100.0f,
  942. Poly.Texture->AcousticTextureCookedData.AbsorptionMidHigh / 100.0f,
  943. Poly.Texture->AcousticTextureCookedData.AbsorptionHigh / 100.0f
  944. );
  945. #endif
  946. textures.Add(params);
  947. }
  948. }
  949. }
  950. }
  951. }
  952. bool UAkSurfaceReflectorSetComponent::ShouldSendGeometry() const
  953. {
  954. if (GetAttachParent() == nullptr || ParentBrush == nullptr)
  955. return false;
  956. UAkRoomComponent* siblingRoom = AkComponentHelpers::GetChildComponentOfType<UAkRoomComponent>(*GetAttachParent());
  957. if (!bEnableSurfaceReflectors && !(siblingRoom && siblingRoom->bEnable))
  958. return false;
  959. return UAkAcousticTextureSetComponent::ShouldSendGeometry();
  960. }
  961. void UAkSurfaceReflectorSetComponent::SendSurfaceReflectorSet()
  962. {
  963. if (GetWorld() && GetWorld()->bIsTearingDown)
  964. return;
  965. FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
  966. if (AkAudioDevice && ShouldSendGeometry())
  967. {
  968. TArray<AkVertex> VertsToSend;
  969. TArray<AkAcousticSurface> SurfacesToSend;
  970. TArray<AkTriangle> TrianglesToSend;
  971. TArray< TSharedPtr< decltype(StringCast<ANSICHAR>(TEXT(""))) > > SurfaceNames;
  972. FString ParentName;
  973. #if WITH_EDITOR
  974. ParentName = GetOwner()->GetActorLabel();
  975. #else
  976. ParentName = GetOwner()->GetName();
  977. #endif
  978. // Some clarifications:
  979. // - All of the brush's vertices are held in the UModel->Verts array (elements of type FVert)
  980. // - FVert contains pVertex, which points to the UModel->Points array (actual coords of the point in actor space)
  981. // - Polygons are represented by the UModel->Nodes array (elements of type FBspNode).
  982. // - FBspNode contains iVertPool, which represents the index in the UModel->Verts at which the node's verts start
  983. // - FBspNode contains NumVertices, the number of vertices that compose this node.
  984. //
  985. // For more insight on how all of these tie together, look at UModel::BuildVertexBuffers().
  986. // A mapping from the unreal vertex index to the wwise vertex index.
  987. TArray<int32> UnrealToWwiseIndex;
  988. UnrealToWwiseIndex.Init(-1, ParentBrush->Points.Num());
  989. // A function to add unique vertices to the VertsToSend array.
  990. // UnrealToWwiseIndex keeps track of added vertices to avoid duplicates.
  991. // This function ensures that we only include vertices that are actually referenced by triangles.
  992. auto AddVertex = [&UnrealToWwiseIndex,&VertsToSend,this](int32 UnrealIdx)
  993. {
  994. int32 wwiseIdx = UnrealToWwiseIndex[UnrealIdx];
  995. if (wwiseIdx == -1)
  996. {
  997. wwiseIdx = VertsToSend.Num();
  998. UnrealToWwiseIndex[UnrealIdx] = wwiseIdx;
  999. const auto& VertexInActorSpace = ParentBrush->Points[UnrealIdx];
  1000. AkVertex akvtx;
  1001. akvtx.X = VertexInActorSpace.X;
  1002. akvtx.Y = VertexInActorSpace.Y;
  1003. akvtx.Z = VertexInActorSpace.Z;
  1004. VertsToSend.Add(akvtx);
  1005. }
  1006. check(wwiseIdx < (AkVertIdx)-1);
  1007. return (AkVertIdx)wwiseIdx;
  1008. };
  1009. for (int32 NodeIdx = 0; NodeIdx < ParentBrush->Nodes.Num(); ++NodeIdx)
  1010. {
  1011. if (AcousticPolys.Num() > NodeIdx)
  1012. {
  1013. FAkSurfacePoly AcousticSurface = AcousticPolys[NodeIdx];
  1014. if (ParentBrush->Nodes[NodeIdx].NumVertices > 2)
  1015. {
  1016. FString TriangleName;
  1017. if (AcousticSurface.Texture != nullptr)
  1018. {
  1019. TriangleName = ParentName + GetName() + FString(TEXT("_")) + AcousticSurface.Texture->GetName() + FString::FromInt(NodeIdx);
  1020. }
  1021. else
  1022. {
  1023. TriangleName = ParentName + GetName() + FString(TEXT("_")) + FString::FromInt(NodeIdx);
  1024. }
  1025. SurfaceNames.Add(MakeShareable(new decltype(StringCast<ANSICHAR>(TEXT("")))(*TriangleName)));
  1026. AkAcousticSurface NewSurface;
  1027. NewSurface.textureID = (AcousticSurface.Texture != nullptr && AcousticSurface.EnableSurface) ? FAkAudioDevice::Get()->GetShortIDFromString(AcousticSurface.Texture->GetName()) : 0;
  1028. if (bEnableSurfaceReflectors)
  1029. {
  1030. NewSurface.transmissionLoss = AcousticSurface.EnableSurface ? AcousticSurface.Occlusion : 0.f;
  1031. }
  1032. else
  1033. {
  1034. NewSurface.transmissionLoss = AcousticSurface.EnableSurface ? 1.f : 0.f;
  1035. }
  1036. NewSurface.strName = SurfaceNames.Last()->Get();
  1037. SurfacesToSend.Add(NewSurface);
  1038. int32 VertStartIndex = ParentBrush->Nodes[NodeIdx].iVertPool;
  1039. const FVert* Vert0 = &ParentBrush->Verts[VertStartIndex + 0];
  1040. const FVert* Vert1 = &ParentBrush->Verts[VertStartIndex + 1];
  1041. for (int32 VertexIdx = 2; VertexIdx < ParentBrush->Nodes[NodeIdx].NumVertices; ++VertexIdx)
  1042. {
  1043. const FVert* Vert2 = &ParentBrush->Verts[VertStartIndex + VertexIdx];
  1044. AkTriangle NewTriangle;
  1045. NewTriangle.point0 = AddVertex(Vert0->pVertex);
  1046. NewTriangle.point1 = AddVertex(Vert1->pVertex);
  1047. NewTriangle.point2 = AddVertex(Vert2->pVertex);
  1048. NewTriangle.surface = (AkSurfIdx)(SurfacesToSend.Num()-1);
  1049. TrianglesToSend.Add(NewTriangle);
  1050. Vert1 = Vert2;
  1051. }
  1052. }
  1053. }
  1054. }
  1055. if (TrianglesToSend.Num() > 0 && VertsToSend.Num() > 0)
  1056. {
  1057. AkGeometryParams params;
  1058. params.NumSurfaces = SurfacesToSend.Num();
  1059. params.NumTriangles = TrianglesToSend.Num();
  1060. params.NumVertices = VertsToSend.Num();
  1061. params.Surfaces = SurfacesToSend.GetData();
  1062. params.Triangles = TrianglesToSend.GetData();
  1063. params.Vertices = VertsToSend.GetData();
  1064. params.EnableDiffraction = bEnableSurfaceReflectors ? bEnableDiffraction : false;
  1065. params.EnableDiffractionOnBoundaryEdges = bEnableSurfaceReflectors ? bEnableDiffractionOnBoundaryEdges : false;
  1066. SendGeometryToWwise(params);
  1067. }
  1068. }
  1069. }
  1070. void UAkSurfaceReflectorSetComponent::RemoveSurfaceReflectorSet()
  1071. {
  1072. RemoveGeometryFromWwise();
  1073. }
  1074. void UAkSurfaceReflectorSetComponent::UpdateSurfaceReflectorSet()
  1075. {
  1076. AkRoomID roomID = AkRoomID();
  1077. if (AssociatedRoom)
  1078. {
  1079. UAkRoomComponent* room = Cast<UAkRoomComponent>(AssociatedRoom->GetComponentByClass(UAkRoomComponent::StaticClass()));
  1080. if (room != nullptr)
  1081. roomID = room->GetRoomID();
  1082. }
  1083. SendGeometryInstanceToWwise(GetOwner()->ActorToWorld().Rotator(), GetOwner()->GetActorLocation(), GetOwner()->ActorToWorld().GetScale3D(), roomID, bEnableSurfaceReflectors);
  1084. if (ReverbDescriptor != nullptr && ParentBrush != nullptr)
  1085. {
  1086. ComputeAcousticPolySurfaceArea();
  1087. DampingEstimationNeedsUpdate = true;
  1088. }
  1089. }
  1090. #if WITH_EDITOR
  1091. void UAkSurfaceReflectorSetComponent::HandleObjectsReplaced(const TMap<UObject*, UObject*>& ReplacementMap)
  1092. {
  1093. Super::HandleObjectsReplaced(ReplacementMap);
  1094. if (ReplacementMap.Contains(ParentBrush))
  1095. {
  1096. InitializeParentBrush();
  1097. UpdateSurfaceReflectorSet();
  1098. }
  1099. }
  1100. bool UAkSurfaceReflectorSetComponent::ContainsTexture(const FGuid& textureID)
  1101. {
  1102. for (const FAkSurfacePoly& Poly : AcousticPolys)
  1103. if (Poly.Texture != nullptr && Poly.Texture->AcousticTextureInfo.WwiseGuid == textureID)
  1104. return true;
  1105. return false;
  1106. }
  1107. void UAkSurfaceReflectorSetComponent::RegisterAllTextureParamCallbacks()
  1108. {
  1109. for (const FAkSurfacePoly& Poly : AcousticPolys)
  1110. if (Poly.Texture != nullptr && TextureDelegateHandles.Find(Poly.Texture->AcousticTextureInfo.WwiseGuid) == nullptr)
  1111. RegisterTextureParamChangeCallback(Poly.Texture->AcousticTextureInfo.WwiseGuid);
  1112. }
  1113. TWeakObjectPtr<UPhysicalMaterial> AssignPolygonTexturesFromSamples(const TArray<FVector>& Vertices, const TArray<FVector>& Points, const TArray<FVector>& Normals, const TArray< TWeakObjectPtr<UPhysicalMaterial> >& Materials, int Num)
  1114. {
  1115. const float kNormalAgreement = 0.866f; // ~30 degrees
  1116. TMap<TWeakObjectPtr<UPhysicalMaterial>, int> Votes;
  1117. const FVector* Vert0 = &Vertices[0];
  1118. const FVector* Vert1 = &Vertices[1];
  1119. for (int32 VertexIdx = 2; VertexIdx < Vertices.Num(); ++VertexIdx)
  1120. {
  1121. const FVector* Vert2 = &Vertices[VertexIdx];
  1122. FVector e0 = *Vert1 - *Vert0;
  1123. FVector e1 = *Vert2 - *Vert0;
  1124. float d00 = FVector::DotProduct(e0, e0);
  1125. float d01 = FVector::DotProduct(e0, e1);
  1126. float d10 = FVector::DotProduct(e1, e0);
  1127. float d11 = FVector::DotProduct(e1, e1);
  1128. float denom = d00 * d11 - d01 * d01;
  1129. // n defined such that the normal faces inwards.
  1130. FVector n = FVector::CrossProduct(e1, e0);
  1131. n.Normalize();
  1132. for (int i = 0; i < Num; ++i)
  1133. {
  1134. const FVector& pt = Points[i];
  1135. const FVector& norm = Normals[i];
  1136. // We want some amount of agreement between the hit normal and the triangle normal.
  1137. if (FVector::DotProduct(n, norm) < kNormalAgreement)
  1138. continue;
  1139. // Init tally to 0 if the normal points the right way.
  1140. int Tally = 0;
  1141. //project point on to triangle.
  1142. float proj = FVector::DotProduct(n, pt - *Vert0);
  1143. FVector pt_proj = pt - proj * n;
  1144. FVector vToPt = pt_proj - *Vert0;
  1145. float d20 = FVector::DotProduct(vToPt, e0);
  1146. float d21 = FVector::DotProduct(vToPt, e1);
  1147. // convert to barycentric coords to see if the point projects into the triangle.
  1148. float u = (d00 * d21 - d01 * d20) / denom;
  1149. if (u > 0.f && u < 1.f)
  1150. {
  1151. float v = (d11 * d20 - d01 * d21) / denom;
  1152. if (v > 0.f && v < 1.f)
  1153. {
  1154. if (u + v < 1.f)
  1155. {
  1156. // Assign another point to the surface if the point projects into the triangle
  1157. Tally++;
  1158. }
  1159. }
  1160. }
  1161. int* Count = Votes.Find(Materials[i]);
  1162. if (Count == nullptr)
  1163. {
  1164. Count = &Votes.Add(Materials[i]);
  1165. *Count = 0;
  1166. }
  1167. if (Count != nullptr)
  1168. {
  1169. *Count += Tally;
  1170. }
  1171. }
  1172. Vert1 = Vert2;
  1173. }
  1174. // Tally the votes
  1175. if (Votes.Num() > 0)
  1176. {
  1177. auto MaxVotes = *Votes.begin();
  1178. auto it = Votes.begin();
  1179. ++it;
  1180. while (it != Votes.end())
  1181. {
  1182. if (it->Value > MaxVotes.Value)
  1183. MaxVotes = *it;
  1184. ++it;
  1185. }
  1186. // Return the material with the max number of points.
  1187. return MaxVotes.Key;
  1188. }
  1189. return nullptr;
  1190. }
  1191. void UAkSurfaceReflectorSetComponent::AssignAcousticTexturesFromSamples(const TArray<FVector>& Points, const TArray<FVector>& Normals, const TArray< TWeakObjectPtr<class UPhysicalMaterial> >& Materials, int Num)
  1192. {
  1193. check(Points.Num() == Materials.Num());
  1194. FTransform ToWorld = GetOwner()->ActorToWorld();
  1195. for (int32 NodeIdx = 0; NodeIdx < ParentBrush->Nodes.Num(); ++NodeIdx)
  1196. {
  1197. AcousticPolys[NodeIdx].EnableSurface = false;
  1198. if (ParentBrush->Nodes[NodeIdx].NumVertices > 2)
  1199. {
  1200. TArray<FVector> WorldVertices;
  1201. const int32 VertStartIndex = ParentBrush->Nodes[NodeIdx].iVertPool;
  1202. for (int32 VertIdx = 0; VertIdx < ParentBrush->Nodes[NodeIdx].NumVertices; ++VertIdx)
  1203. {
  1204. WorldVertices.Emplace(ToWorld.TransformPosition(FVector(ParentBrush->Points[ParentBrush->Verts[VertStartIndex + VertIdx].pVertex])));
  1205. }
  1206. TWeakObjectPtr<UPhysicalMaterial> Material = AssignPolygonTexturesFromSamples(WorldVertices, Points, Normals, Materials, Num);
  1207. if (Material.IsValid())
  1208. {
  1209. GetDefault<UAkSettings>()->GetAssociatedAcousticTexture(Material.Get(), AcousticPolys[NodeIdx].Texture);
  1210. GetDefault<UAkSettings>()->GetAssociatedOcclusionValue(Material.Get(), AcousticPolys[NodeIdx].Occlusion);
  1211. AcousticPolys[NodeIdx].EnableSurface = true;
  1212. }
  1213. else
  1214. {
  1215. AcousticPolys[NodeIdx].Texture = GetDefault<UAkSettings>()->DefaultAcousticTexture.LoadSynchronous();
  1216. AcousticPolys[NodeIdx].Occlusion = GetDefault<UAkSettings>()->DefaultTransmissionLoss;
  1217. AcousticPolys[NodeIdx].EnableSurface = true;
  1218. }
  1219. }
  1220. if (AcousticPolys[NodeIdx].Texture != nullptr)
  1221. RegisterTextureParamChangeCallback(AcousticPolys[NodeIdx].Texture->AcousticTextureInfo.WwiseGuid);
  1222. }
  1223. OnRefreshDetails.ExecuteIfBound();
  1224. SurfacePropertiesChanged();
  1225. // Update text visualizers.
  1226. SchedulePolysUpdate();
  1227. }
  1228. #endif