AkGeometryComponent.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229
  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 "AkGeometryComponent.h"
  16. #include "AkAcousticTexture.h"
  17. #include "AkAudioDevice.h"
  18. #include "AkComponentHelpers.h"
  19. #include "AkReverbDescriptor.h"
  20. #include "AkRoomComponent.h"
  21. #include "AkSettings.h"
  22. #include "WwiseUEFeatures.h"
  23. #if AK_USE_PHYSX
  24. #include "PhysXPublic.h"
  25. #endif
  26. #if AK_USE_CHAOS
  27. #include "ChaosLog.h"
  28. #include "Chaos/CollisionConvexMesh.h"
  29. #include "Chaos/Convex.h"
  30. #endif
  31. #if WITH_EDITOR
  32. #include "Editor.h"
  33. #endif
  34. #include "RawIndexBuffer.h"
  35. #include "StaticMeshResources.h"
  36. #include "Components/StaticMeshComponent.h"
  37. #include "Engine/GameEngine.h"
  38. #include "Engine/Polys.h"
  39. #include "Engine/StaticMesh.h"
  40. #include "PhysicsEngine/BodySetup.h"
  41. #include "UObject/Object.h"
  42. static const float kVertexNear = 0.0001;
  43. UAkGeometryComponent::UAkGeometryComponent(const class FObjectInitializer& ObjectInitializer) :
  44. Super(ObjectInitializer)
  45. {
  46. // Property initialization
  47. bWantsOnUpdateTransform = true;
  48. MeshType = AkMeshType::CollisionMesh;
  49. LOD = 0;
  50. CollisionMeshSurfaceOverride.AcousticTexture = nullptr;
  51. CollisionMeshSurfaceOverride.bEnableOcclusionOverride = false;
  52. CollisionMeshSurfaceOverride.OcclusionValue = 1.f;
  53. WeldingThreshold = 0.001;
  54. bWasAddedByRoom = 0;
  55. bEnableDiffraction = 1;
  56. bEnableDiffractionOnBoundaryEdges = 0;
  57. #if WITH_EDITOR
  58. PrimaryComponentTick.bCanEverTick = true;
  59. bTickInEditor = true;
  60. #endif
  61. }
  62. void UAkGeometryComponent::OnComponentDestroyed(bool bDestroyingHierarchy)
  63. {
  64. Super::OnComponentDestroyed(bDestroyingHierarchy);
  65. RemoveGeometry();
  66. StaticMeshSurfaceOverride.Empty();
  67. #if WITH_EDITOR
  68. check(!OnMeshMaterialChangedHandle.IsValid());
  69. #endif
  70. }
  71. void UAkGeometryComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport)
  72. {
  73. Super::OnUpdateTransform(UpdateTransformFlags, Teleport);
  74. UpdateGeometry();
  75. if (ReverbDescriptor != nullptr)
  76. {
  77. DampingEstimationNeedsUpdate = true;
  78. }
  79. }
  80. bool UAkGeometryComponent::MoveComponentImpl(
  81. const FVector & Delta,
  82. const FQuat & NewRotation,
  83. bool bSweep,
  84. FHitResult * Hit,
  85. EMoveComponentFlags MoveFlags,
  86. ETeleportType Teleport)
  87. {
  88. if (AkComponentHelpers::DoesMovementRecenterChild(this, Parent, Delta))
  89. Super::MoveComponentImpl(Delta, NewRotation, bSweep, Hit, MoveFlags, Teleport);
  90. return false;
  91. }
  92. void UAkGeometryComponent::BeginPlay()
  93. {
  94. Super::BeginPlay();
  95. if (!IsBeingDestroyed())
  96. {
  97. #if WITH_EDITOR
  98. if (AkComponentHelpers::ShouldDeferBeginPlay(this))
  99. bRequiresDeferredBeginPlay = true;
  100. else
  101. BeginPlayInternal();
  102. #else
  103. BeginPlayInternal();
  104. #endif
  105. }
  106. }
  107. void UAkGeometryComponent::BeginPlayInternal()
  108. {
  109. if (Parent == nullptr)
  110. InitializeParent();
  111. if (GeometryData.Vertices.Num() == 0)
  112. ConvertMesh();
  113. for (int PosIndex = 0; PosIndex < GeometryData.Surfaces.Num(); ++PosIndex)
  114. {
  115. // set geometry surface names and update textures
  116. FString OwnerName;
  117. #if WITH_EDITOR
  118. OwnerName = GetOwner()->GetActorLabel();
  119. #else
  120. OwnerName = GetOwner()->GetName();
  121. #endif
  122. GeometryData.Surfaces[PosIndex].Name = OwnerName + GetName() + FString::FromInt(PosIndex);
  123. UPhysicalMaterial* physMat = GeometryData.ToOverrideAcousticTexture[PosIndex];
  124. if (physMat)
  125. {
  126. UAkAcousticTexture* acousticTexture = nullptr;
  127. if (GetDefault<UAkSettings>()->GetAssociatedAcousticTexture(physMat, acousticTexture))
  128. {
  129. if (acousticTexture)
  130. GeometryData.Surfaces[PosIndex].Texture = acousticTexture->GetShortID();
  131. }
  132. }
  133. physMat = GeometryData.ToOverrideOcclusion[PosIndex];
  134. if (physMat)
  135. {
  136. float occlusionValue = 1.f;
  137. if (GetDefault<UAkSettings>()->GetAssociatedOcclusionValue(physMat, occlusionValue))
  138. {
  139. GeometryData.Surfaces[PosIndex].Occlusion = occlusionValue;
  140. }
  141. }
  142. }
  143. SendGeometry();
  144. UpdateGeometry();
  145. DampingEstimationNeedsUpdate = true;
  146. }
  147. void UAkGeometryComponent::OnRegister()
  148. {
  149. Super::OnRegister();
  150. SetRelativeTransform(FTransform::Identity);
  151. InitializeParent();
  152. #if WITH_EDITOR
  153. OnMeshMaterialChangedHandle = FCoreUObjectDelegates::OnObjectPropertyChanged.AddLambda([this](UObject* Object, FPropertyChangedEvent& PropertyChangedEvent)
  154. {
  155. if (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UMeshComponent, OverrideMaterials) &&
  156. Parent != nullptr &&
  157. Parent == Object &&
  158. MeshType == AkMeshType::StaticMesh
  159. )
  160. {
  161. UpdateStaticMeshOverride();
  162. }
  163. });
  164. if (Parent != nullptr)
  165. {
  166. if (MeshType == AkMeshType::StaticMesh)
  167. {
  168. UStaticMeshComponent* MeshParent = Cast<UStaticMeshComponent>(Parent);
  169. if (MeshParent != nullptr)
  170. CalculateSurfaceArea(MeshParent);
  171. }
  172. DampingEstimationNeedsUpdate = true;
  173. }
  174. if (AssociatedRoom != nullptr)
  175. {
  176. UAkRoomComponent* room = Cast<UAkRoomComponent>(AssociatedRoom->GetComponentByClass(UAkRoomComponent::StaticClass()));
  177. if (room != nullptr)
  178. {
  179. UE_LOG(LogAkAudio, Warning, TEXT("AkGeometryComponent %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());
  180. }
  181. }
  182. #endif
  183. }
  184. void UAkGeometryComponent::OnUnregister()
  185. {
  186. #if WITH_EDITOR
  187. FCoreUObjectDelegates::OnObjectPropertyChanged.Remove(OnMeshMaterialChangedHandle);
  188. OnMeshMaterialChangedHandle.Reset();
  189. #endif
  190. Parent = nullptr;
  191. Super::OnUnregister();
  192. }
  193. void UAkGeometryComponent::InitializeParent()
  194. {
  195. USceneComponent* SceneParent = GetAttachParent();
  196. if (SceneParent != nullptr)
  197. {
  198. Parent = Cast<UPrimitiveComponent>(SceneParent);
  199. if (!Parent)
  200. {
  201. FString actorString = FString("NONE");
  202. if (GetOwner() != nullptr)
  203. actorString = GetOwner()->GetName();
  204. FString parentName = SceneParent->GetName();
  205. FString parentClass = SceneParent->GetClass()->GetName();
  206. UE_LOG(LogAkAudio, Error,
  207. TEXT("On actor %s, there is a UAkGeometryComponent (%s) attached to parent of type %s (%s).")
  208. , *actorString, *GetName(), *parentClass, *parentName);
  209. if (MeshType == AkMeshType::StaticMesh)
  210. {
  211. UE_LOG(LogAkAudio, Error, TEXT("When MeshType is set to Static Mesh, UAkGeometryComponent requires to be nested under a component inheriting from UStaticMeshComponent."));
  212. }
  213. else
  214. {
  215. UE_LOG(LogAkAudio, Error, TEXT("When MeshType is set to Simple Collision, UAkGeometryComponent requires to be nested under a component inheriting from UPrimitiveComponent."));
  216. }
  217. return;
  218. }
  219. if (MeshType == AkMeshType::StaticMesh)
  220. {
  221. UStaticMeshComponent* MeshParent = Cast<UStaticMeshComponent>(SceneParent);
  222. if (MeshParent != nullptr)
  223. {
  224. bool fillMaterialKeys = true;
  225. #if WITH_EDITOR
  226. // Fill the materials in the StaticMeshSurfaceOverride map only when there is no ongoing transaction (e.g. a user changing a property in the details panel).
  227. if (GetOwner() != nullptr && GetOwner()->CurrentTransactionAnnotation != nullptr)
  228. {
  229. fillMaterialKeys = false;
  230. }
  231. #endif
  232. if (fillMaterialKeys)
  233. {
  234. UpdateMeshAndArchetype(MeshParent);
  235. }
  236. }
  237. else
  238. {
  239. FString actorString = FString("NONE");
  240. if (GetOwner() != nullptr)
  241. actorString = GetOwner()->GetName();
  242. FString parentName = SceneParent->GetName();
  243. FString parentClass = SceneParent->GetClass()->GetName();
  244. UE_LOG(LogAkAudio, Warning,
  245. TEXT("On actor %s, there is a UAkGeometryComponent (%s) attached to parent of type %s (%s).")
  246. , *actorString, *GetName(), *parentClass, *parentName);
  247. UE_LOG(LogAkAudio, Warning, TEXT("When MeshType is set to Static Mesh, UAkGeometryComponent requires to be nested under a component inheriting from UStaticMeshComponent. Reverting to Simple Collision."));
  248. MeshType = AkMeshType::CollisionMesh;
  249. // If we're in the Blueprint editor, update the Archetype object as well.
  250. UWorld* World = GetWorld();
  251. if (World != nullptr && World->WorldType == EWorldType::EditorPreview
  252. && CreationMethod == EComponentCreationMethod::SimpleConstructionScript)
  253. {
  254. UAkGeometryComponent* Archetype = Cast<UAkGeometryComponent>(GetArchetype());
  255. if (Archetype != nullptr)
  256. Archetype->MeshType = AkMeshType::CollisionMesh;
  257. }
  258. }
  259. }
  260. }
  261. }
  262. void UAkGeometryComponent::CalculateSurfaceArea(UStaticMeshComponent* StaticMeshComponent)
  263. {
  264. SurfaceAreas.Empty();
  265. UStaticMesh* mesh = StaticMeshComponent->GetStaticMesh();
  266. #if UE_4_27_OR_LATER
  267. if (mesh == nullptr || !mesh->GetRenderData())
  268. return;
  269. #else
  270. if (mesh == nullptr || !mesh->RenderData)
  271. return;
  272. #endif
  273. const FStaticMeshLODResources& RenderMesh = mesh->GetLODForExport(LOD);
  274. FIndexArrayView RawIndices = RenderMesh.IndexBuffer.GetArrayView();
  275. if (RawIndices.Num() == 0)
  276. return;
  277. const int32 PolygonsCount = RenderMesh.Sections.Num();
  278. double SurfaceArea = 0.0;
  279. const auto WorldScale = StaticMeshComponent->GetOwner()->ActorToWorld().GetScale3D();
  280. for (int32 PolygonsIndex = 0; PolygonsIndex < PolygonsCount; ++PolygonsIndex)
  281. {
  282. const FStaticMeshSection& Polygons = RenderMesh.Sections[PolygonsIndex];
  283. const uint32 TriangleCount = Polygons.NumTriangles;
  284. for (uint32 TriangleIndex = 0; TriangleIndex < TriangleCount; ++TriangleIndex)
  285. {
  286. const uint32 RawVertIndex0 = RawIndices[Polygons.FirstIndex + ((TriangleIndex * 3) + 0)];
  287. const uint32 RawVertIndex1 = RawIndices[Polygons.FirstIndex + ((TriangleIndex * 3) + 1)];
  288. const uint32 RawVertIndex2 = RawIndices[Polygons.FirstIndex + ((TriangleIndex * 3) + 2)];
  289. // Scale to world space to ensure proper area
  290. auto ScaledP0 = WorldScale * FVector(RenderMesh.VertexBuffers.PositionVertexBuffer.VertexPosition(RawVertIndex0).GridSnap(WeldingThreshold));
  291. auto ScaledP1 = WorldScale * FVector(RenderMesh.VertexBuffers.PositionVertexBuffer.VertexPosition(RawVertIndex1).GridSnap(WeldingThreshold));
  292. auto ScaledP2 = WorldScale * FVector(RenderMesh.VertexBuffers.PositionVertexBuffer.VertexPosition(RawVertIndex2).GridSnap(WeldingThreshold));
  293. SurfaceArea += FAkReverbDescriptor::TriangleArea(ScaledP0, ScaledP1, ScaledP2);
  294. }
  295. SurfaceAreas.Add(PolygonsIndex, SurfaceArea);
  296. }
  297. }
  298. bool AddVertsForEdge(const FPositionVertexBuffer& Positions, TArray<int32>& UniqueVerts, int32 P0UnrealIdx, int32 P0UniqueIdx, int32 P1UnrealIdx, int32 P1UniqueIdx, TArray< TPair<int32, float> > & VertsOnEdge, float WeldingThreshold)
  299. {
  300. auto p0 = Positions.VertexPosition(P0UnrealIdx).GridSnap(WeldingThreshold);
  301. auto p1 = Positions.VertexPosition(P1UnrealIdx).GridSnap(WeldingThreshold);
  302. FUnrealFloatVector Dir;
  303. float Length;
  304. (p1 - p0).ToDirectionAndLength(Dir, Length);
  305. if (Length <= FLT_MIN)
  306. return false;
  307. for (int32 i = 0; i < UniqueVerts.Num(); i++)
  308. {
  309. const int32 UnrealVertIdx = UniqueVerts[i];
  310. auto p = Positions.VertexPosition(UnrealVertIdx).GridSnap(WeldingThreshold);
  311. float Dot = FUnrealFloatVector::DotProduct(p - p0, Dir);
  312. const float RelLength = Dot / Length;
  313. if (RelLength > kVertexNear && RelLength < 1.f + kVertexNear)
  314. {
  315. FUnrealFloatVector PtOnLine = p0 + Dot * Dir;
  316. FUnrealFloatVector Diff = PtOnLine - p;
  317. const float RelDiff = Diff.GetAbsMax() / Length;
  318. if (RelDiff < kVertexNear)
  319. {
  320. VertsOnEdge.Emplace(i, Dot);
  321. }
  322. }
  323. }
  324. // VertsOnEdge should contain p1 but not p0
  325. check(VertsOnEdge.Num() > 0);
  326. VertsOnEdge.Sort([](const TPair<int32, float>& One, const TPair<int32, float>& Two)
  327. {
  328. return One.Value < Two.Value;
  329. });
  330. return true;
  331. }
  332. void DetermineVertsToWeld(TArray<int32>& VertRemap, TArray<int32>& UniqueVerts, const FStaticMeshLODResources& RenderMesh, float WeldingThreshold)
  333. {
  334. const int32 VertexCount = RenderMesh.VertexBuffers.PositionVertexBuffer.GetNumVertices();
  335. // Maps unreal verts to reduced list of verts
  336. VertRemap.Empty(VertexCount);
  337. VertRemap.AddUninitialized(VertexCount);
  338. // List of Unreal Verts to keep
  339. UniqueVerts.Empty(VertexCount);
  340. // Combine matching verts using hashed search to maintain good performance
  341. TMap<FUnrealFloatVector, int32> HashedVerts;
  342. for (int32 a = 0; a < VertexCount; a++)
  343. {
  344. auto PositionA = RenderMesh.VertexBuffers.PositionVertexBuffer.VertexPosition(a).GridSnap(WeldingThreshold);
  345. const int32* FoundIndex = HashedVerts.Find(PositionA);
  346. if (!FoundIndex)
  347. {
  348. int32 NewIndex = UniqueVerts.Add(a);
  349. VertRemap[a] = NewIndex;
  350. HashedVerts.Add(PositionA, NewIndex);
  351. }
  352. else
  353. {
  354. VertRemap[a] = *FoundIndex;
  355. }
  356. }
  357. }
  358. void UAkGeometryComponent::ConvertMesh()
  359. {
  360. if (!(Parent && IsValid(Parent)))
  361. return;
  362. const UAkSettings* AkSettings = GetDefault<UAkSettings>();
  363. switch (MeshType)
  364. {
  365. case AkMeshType::StaticMesh:
  366. {
  367. UStaticMeshComponent* MeshParent = Cast<UStaticMeshComponent>(Parent);
  368. if (MeshParent != nullptr)
  369. ConvertStaticMesh(MeshParent, AkSettings);
  370. break;
  371. }
  372. case AkMeshType::CollisionMesh:
  373. {
  374. ConvertCollisionMesh(Parent, AkSettings);
  375. break;
  376. }
  377. }
  378. }
  379. void UAkGeometryComponent::ConvertStaticMesh(UStaticMeshComponent* StaticMeshComponent, const UAkSettings* AkSettings)
  380. {
  381. UStaticMesh* mesh = StaticMeshComponent->GetStaticMesh();
  382. if (!(mesh && IsValid(mesh)))
  383. return;
  384. if (LOD > mesh->GetNumLODs() - 1)
  385. LOD = mesh->GetNumLODs() - 1;
  386. #if UE_4_27_OR_LATER
  387. if (!mesh->GetRenderData())
  388. return;
  389. #else
  390. if (!mesh->RenderData)
  391. return;
  392. #endif
  393. const FStaticMeshLODResources& RenderMesh = mesh->GetLODForExport(LOD);
  394. FIndexArrayView RawIndices = RenderMesh.IndexBuffer.GetArrayView();
  395. if (RawIndices.Num() == 0)
  396. return;
  397. GeometryData.Clear();
  398. TArray<int32> VertRemap;
  399. TArray<int32> UniqueVerts;
  400. DetermineVertsToWeld(VertRemap, UniqueVerts, RenderMesh, WeldingThreshold);
  401. for (int PosIndex = 0; PosIndex < UniqueVerts.Num(); ++PosIndex)
  402. {
  403. const int32 UnrealPosIndex = UniqueVerts[PosIndex];
  404. auto VertexInActorSpace = RenderMesh.VertexBuffers.PositionVertexBuffer.VertexPosition(UnrealPosIndex);
  405. GeometryData.Vertices.Add(FVector(VertexInActorSpace));
  406. }
  407. UpdateMeshAndArchetype(StaticMeshComponent);
  408. CalculateSurfaceArea(StaticMeshComponent);
  409. const int32 PolygonsCount = RenderMesh.Sections.Num();
  410. for (int32 PolygonsIndex = 0; PolygonsIndex < PolygonsCount; ++PolygonsIndex)
  411. {
  412. const FStaticMeshSection& Polygons = RenderMesh.Sections[PolygonsIndex];
  413. FAkAcousticSurface Surface;
  414. UPhysicalMaterial* physMatTexture = nullptr;
  415. UPhysicalMaterial* physMatOcclusion = nullptr;
  416. FAkGeometrySurfaceOverride surfaceOverride;
  417. UMaterialInterface* Material = StaticMeshComponent->GetMaterial(Polygons.MaterialIndex);
  418. if (Material)
  419. {
  420. UPhysicalMaterial* physicalMaterial = Material->GetPhysicalMaterial();
  421. if (StaticMeshSurfaceOverride.Contains(Material))
  422. surfaceOverride = StaticMeshSurfaceOverride[Material];
  423. if (!surfaceOverride.AcousticTexture)
  424. physMatTexture = physicalMaterial;
  425. if (!surfaceOverride.bEnableOcclusionOverride)
  426. physMatOcclusion = physicalMaterial;
  427. }
  428. if (surfaceOverride.AcousticTexture)
  429. Surface.Texture = surfaceOverride.AcousticTexture->GetShortID();
  430. if (surfaceOverride.bEnableOcclusionOverride)
  431. Surface.Occlusion = surfaceOverride.OcclusionValue;
  432. GeometryData.Surfaces.Add(Surface);
  433. GeometryData.ToOverrideAcousticTexture.Add(physMatTexture);
  434. GeometryData.ToOverrideOcclusion.Add(physMatOcclusion);
  435. AkSurfIdx surfIdx = (AkSurfIdx)(GeometryData.Surfaces.Num() - 1);
  436. TArray< TPair<int32, float> > Edge0, Edge1, Edge2;
  437. const uint32 TriangleCount = Polygons.NumTriangles;
  438. for (uint32 TriangleIndex = 0; TriangleIndex < TriangleCount; ++TriangleIndex)
  439. {
  440. uint32 RawVertIndex0 = RawIndices[Polygons.FirstIndex + ((TriangleIndex * 3) + 0)];
  441. uint32 UniqueVertIndex0 = VertRemap[RawVertIndex0];
  442. uint32 RawVertIndex1 = RawIndices[Polygons.FirstIndex + ((TriangleIndex * 3) + 1)];
  443. uint32 UniqueVertIndex1 = VertRemap[RawVertIndex1];
  444. uint32 RawVertIndex2 = RawIndices[Polygons.FirstIndex + ((TriangleIndex * 3) + 2)];
  445. uint32 UniqueVertIndex2 = VertRemap[RawVertIndex2];
  446. Edge0.Empty(8);
  447. bool succeeded = AddVertsForEdge(RenderMesh.VertexBuffers.PositionVertexBuffer, UniqueVerts, RawVertIndex0, UniqueVertIndex0, RawVertIndex1, UniqueVertIndex1, Edge0, WeldingThreshold);
  448. if (!succeeded)
  449. {
  450. UE_LOG(LogAkAudio, Warning, TEXT("%s: UAkGeometryComponent::ConvertStaticMesh Vertex IDs %i and %i are too close resulting in a triangle with an area of 0. The triangle will be skipped."), *GetOwner()->GetName(), RawVertIndex0, RawVertIndex1);
  451. continue;
  452. }
  453. Edge1.Empty(8);
  454. succeeded = AddVertsForEdge(RenderMesh.VertexBuffers.PositionVertexBuffer, UniqueVerts, RawVertIndex1, UniqueVertIndex1, RawVertIndex2, UniqueVertIndex2, Edge1, WeldingThreshold);
  455. if (!succeeded)
  456. {
  457. UE_LOG(LogAkAudio, Warning, TEXT("%s: UAkGeometryComponent::ConvertStaticMesh Vertex IDs %i and %i are too close resulting in a triangle with an area of 0. The triangle will be skipped."), *GetOwner()->GetName(), RawVertIndex1, RawVertIndex2);
  458. continue;
  459. }
  460. Edge2.Empty(8);
  461. succeeded = AddVertsForEdge(RenderMesh.VertexBuffers.PositionVertexBuffer, UniqueVerts, RawVertIndex2, UniqueVertIndex2, RawVertIndex0, UniqueVertIndex0, Edge2, WeldingThreshold);
  462. if (!succeeded)
  463. {
  464. UE_LOG(LogAkAudio, Warning, TEXT("%s: UAkGeometryComponent::ConvertStaticMesh Vertex IDs %i and %i are too close resulting in a triangle with an area of 0. The triangle will be skipped."), *GetOwner()->GetName(), RawVertIndex2, RawVertIndex0);
  465. continue;
  466. }
  467. FAkTriangle triangle;
  468. triangle.Surface = surfIdx;
  469. bool bDone = false;
  470. do
  471. {
  472. int32 v0, v1, v2;
  473. if (Edge0.Num() > 1)
  474. {
  475. v1 = Edge0.Pop().Key;
  476. v0 = Edge0.Last().Key;
  477. v2 = Edge1[0].Key;
  478. }
  479. else if (Edge1.Num() > 1)
  480. {
  481. v1 = Edge1.Pop().Key;
  482. v0 = Edge1.Last().Key;
  483. v2 = Edge2[0].Key;
  484. }
  485. else if (Edge2.Num() > 1)
  486. {
  487. v1 = Edge2.Pop().Key;
  488. v0 = Edge2.Last().Key;
  489. v2 = Edge0[0].Key;
  490. }
  491. else
  492. {
  493. v0 = Edge0[0].Key;
  494. v1 = Edge1[0].Key;
  495. v2 = Edge2[0].Key;
  496. bDone = true;
  497. }
  498. triangle.Point0 = (AkVertIdx)v0;
  499. triangle.Point1 = (AkVertIdx)v1;
  500. triangle.Point2 = (AkVertIdx)v2;
  501. if (triangle.Point0 != triangle.Point1 &&
  502. triangle.Point1 != triangle.Point2 &&
  503. triangle.Point2 != triangle.Point0)
  504. GeometryData.Triangles.Add(triangle);
  505. } while (!bDone);
  506. }
  507. if (SurfaceAreas.Contains(PolygonsIndex))
  508. surfaceOverride.SetSurfaceArea(SurfaceAreas[PolygonsIndex]);
  509. }
  510. }
  511. struct VertexIndexByAngle
  512. {
  513. AkVertIdx Index;
  514. float Angle;
  515. };
  516. #if AK_USE_PHYSX
  517. void ConvertConvexMeshToGeometryData(AkSurfIdx surfIdx, const FKConvexElem& convexHull, FAkGeometryData* GeometryData)
  518. {
  519. physx::PxConvexMesh* convexMesh = convexHull.GetConvexMesh();
  520. AkVertIdx initialVertIdx = GeometryData->Vertices.Num();
  521. if (convexMesh != nullptr)
  522. {
  523. const PxVec3* vertices = convexMesh->getVertices();
  524. uint32 numVerts = (uint32)convexMesh->getNbVertices();
  525. for (uint32 vertIdx = 0; vertIdx < numVerts; ++vertIdx)
  526. {
  527. FVector akvtx;
  528. akvtx.X = vertices[vertIdx].x;
  529. akvtx.Y = vertices[vertIdx].y;
  530. akvtx.Z = vertices[vertIdx].z;
  531. GeometryData->Vertices.Add(akvtx);
  532. }
  533. const physx::PxU8* indexBuf = convexMesh->getIndexBuffer();
  534. uint32 numPolys = (uint32)convexMesh->getNbPolygons();
  535. for (uint32 polyIdx = 0; polyIdx < numPolys; polyIdx++)
  536. {
  537. PxHullPolygon polyData;
  538. convexMesh->getPolygonData(polyIdx, polyData);
  539. // order the vertices of the polygon
  540. uint32 numVertsInPoly = (uint32)polyData.mNbVerts;
  541. uint32 vertIdxOffset = (uint32)polyData.mIndexBase;
  542. TArray<VertexIndexByAngle> orderedIndexes;
  543. // first element is first vertex index
  544. AkVertIdx firstVertIdx = (AkVertIdx)indexBuf[vertIdxOffset];
  545. orderedIndexes.Add(VertexIndexByAngle{ firstVertIdx, 0 });
  546. // get the center of the polygon
  547. FVector center(0, 0, 0);
  548. for (uint32 polyVertIdx = 0; polyVertIdx < numVertsInPoly; ++polyVertIdx)
  549. {
  550. auto vertIdx = indexBuf[vertIdxOffset + polyVertIdx];
  551. center.X += vertices[vertIdx].x;
  552. center.Y += vertices[vertIdx].y;
  553. center.Z += vertices[vertIdx].z;
  554. }
  555. center.X /= numVertsInPoly;
  556. center.Y /= numVertsInPoly;
  557. center.Z /= numVertsInPoly;
  558. // get the vector from center to the first vertex
  559. FVector v0;
  560. v0.X = vertices[firstVertIdx].x - center.X;
  561. v0.Y = vertices[firstVertIdx].y - center.Y;
  562. v0.Z = vertices[firstVertIdx].z - center.Z;
  563. v0.Normalize();
  564. // get the normal of the plane
  565. FVector n;
  566. n.X = polyData.mPlane[0];
  567. n.Y = polyData.mPlane[1];
  568. n.Z = polyData.mPlane[2];
  569. n.Normalize();
  570. // find the angles between v0 and the other vertices of the polygon
  571. for (uint32 polyVertIdx = 1; polyVertIdx < numVertsInPoly; polyVertIdx++)
  572. {
  573. // get the vector from center to the current vertex
  574. AkVertIdx vertIdx = (AkVertIdx)indexBuf[vertIdxOffset + polyVertIdx];
  575. FVector v1;
  576. v1.X = vertices[vertIdx].x - center.X;
  577. v1.Y = vertices[vertIdx].y - center.Y;
  578. v1.Z = vertices[vertIdx].z - center.Z;
  579. v1.Normalize();
  580. // get the angle between v0 and v1
  581. // to do so, we need the dot product and the determinant respectively proportional to cos and sin of the angle.
  582. // atan2(sin, cos) will give us the angle
  583. float dot = FVector::DotProduct(v0, v1);
  584. // the determinant of two 3D vectors in the same plane can be found with the dot product of the normal with the result of
  585. // a cross product between the vectors
  586. float det = FVector::DotProduct(n, FVector::CrossProduct(v0, v1));
  587. float angle = (float)atan2(det, dot);
  588. orderedIndexes.Add(VertexIndexByAngle{ vertIdx, angle });
  589. }
  590. orderedIndexes.Sort();
  591. // fan triangulation
  592. for (uint32 vertIdx = 1; vertIdx < numVertsInPoly - 1; ++vertIdx)
  593. {
  594. FAkTriangle tri;
  595. tri.Point0 = (AkVertIdx)orderedIndexes[0].Index + initialVertIdx;
  596. tri.Point1 = (AkVertIdx)orderedIndexes[vertIdx].Index + initialVertIdx;
  597. tri.Point2 = (AkVertIdx)orderedIndexes[vertIdx + 1].Index + initialVertIdx;
  598. tri.Surface = surfIdx;
  599. GeometryData->Triangles.Add(tri);
  600. }
  601. }
  602. }
  603. else
  604. {
  605. // bounding box
  606. GeometryData->AddBox(surfIdx,
  607. convexHull.ElemBox.GetCenter(),
  608. convexHull.ElemBox.GetExtent(),
  609. convexHull.GetTransform().Rotator());
  610. }
  611. }
  612. #endif
  613. bool operator<(const VertexIndexByAngle& lhs, const VertexIndexByAngle& rhs)
  614. {
  615. return lhs.Angle < rhs.Angle;
  616. }
  617. void UAkGeometryComponent::ConvertCollisionMesh(UPrimitiveComponent* PrimitiveComponent, const UAkSettings* AkSettings)
  618. {
  619. UBodySetup* bodySetup = PrimitiveComponent->GetBodySetup();
  620. if (!(bodySetup && IsValid(bodySetup)))
  621. return;
  622. GeometryData.Clear();
  623. FAkAcousticSurface Surface;
  624. UPhysicalMaterial* physicalMaterial = bodySetup->GetPhysMaterial();
  625. UPhysicalMaterial* physMatTexture = nullptr;
  626. UPhysicalMaterial* physMatOcclusion = nullptr;
  627. FAkGeometrySurfaceOverride surfaceOverride = CollisionMeshSurfaceOverride;
  628. if (surfaceOverride.AcousticTexture)
  629. Surface.Texture = surfaceOverride.AcousticTexture->GetShortID();
  630. else
  631. physMatTexture = physicalMaterial;
  632. if (surfaceOverride.bEnableOcclusionOverride)
  633. Surface.Occlusion = surfaceOverride.OcclusionValue;
  634. else
  635. physMatOcclusion = physicalMaterial;
  636. GeometryData.ToOverrideAcousticTexture.Add(physMatTexture);
  637. GeometryData.ToOverrideOcclusion.Add(physMatOcclusion);
  638. GeometryData.Surfaces.Add(Surface);
  639. AkSurfIdx surfIdx = (AkSurfIdx)(GeometryData.Surfaces.Num() - 1);
  640. int32 numBoxes = bodySetup->AggGeom.BoxElems.Num();
  641. for (int32 i = 0; i < numBoxes; i++)
  642. {
  643. FKBoxElem box = bodySetup->AggGeom.BoxElems[i];
  644. FVector extent;
  645. extent.X = box.X / 2;
  646. extent.Y = box.Y / 2;
  647. extent.Z = box.Z / 2;
  648. if ((extent.Z == 0.0f && (extent.X == 0.0f || extent.Y == 0.0f))
  649. || (extent.Y == 0.0f && (extent.X == 0.0f || extent.Z == 0.0f))
  650. || (extent.X == 0.0f && (extent.Y == 0.0f || extent.Z == 0.0f)))
  651. {
  652. UE_LOG(LogAkAudio, Warning, TEXT("%s: UAkGeometryComponent::ConvertCollisionMesh: Unable to add box geometry for box index %i as the box contains no triangles. The box will be skipped."), *GetOwner()->GetName(), i);
  653. continue;
  654. }
  655. GeometryData.AddBox(surfIdx, box.Center, extent, box.Rotation);
  656. }
  657. const int sides = 16;
  658. int32 numSpheres = bodySetup->AggGeom.SphereElems.Num();
  659. for (int32 i = 0; i < numSpheres; i++)
  660. {
  661. FKSphereElem sphere = bodySetup->AggGeom.SphereElems[i];
  662. GeometryData.AddSphere(surfIdx, sphere.Center, sphere.Radius, sides, sides / 2);
  663. }
  664. int32 numCapsules = bodySetup->AggGeom.SphylElems.Num();
  665. for (int32 i = 0; i < numCapsules; i++)
  666. {
  667. FKSphylElem capsule = bodySetup->AggGeom.SphylElems[i];
  668. FVector X = capsule.GetTransform().GetUnitAxis(EAxis::X);
  669. FVector Y = capsule.GetTransform().GetUnitAxis(EAxis::Y);
  670. FVector Z = capsule.GetTransform().GetUnitAxis(EAxis::Z);
  671. GeometryData.AddCapsule(surfIdx, capsule.Center, X, Y, Z, capsule.Radius, capsule.Length / 2, sides / 2);
  672. }
  673. int32 numConvexElems = bodySetup->AggGeom.ConvexElems.Num();
  674. for (int32 i = 0; i < numConvexElems; i++)
  675. {
  676. FKConvexElem& convexElem = bodySetup->AggGeom.ConvexElems[i];
  677. int32 numVertices = convexElem.VertexData.Num();
  678. if (numVertices == 0)
  679. continue;
  680. #if AK_USE_CHAOS
  681. // will compute IndexData if it is empty
  682. convexElem.ComputeChaosConvexIndices(false);
  683. #endif
  684. int32 numTriangles = convexElem.IndexData.Num() / 3;
  685. if (numTriangles == 0)
  686. {
  687. #if AK_USE_PHYSX
  688. ConvertConvexMeshToGeometryData(surfIdx, convexElem, &GeometryData);
  689. #endif
  690. continue;
  691. }
  692. int32 vertexOffset = GeometryData.Vertices.Num();
  693. for (int32 vertIdx = 0; vertIdx < numVertices; ++vertIdx)
  694. {
  695. GeometryData.Vertices.Add(convexElem.GetTransform().TransformPosition(convexElem.VertexData[vertIdx]));
  696. }
  697. for (int32 triIdx = 0; triIdx < numTriangles; ++triIdx)
  698. {
  699. FAkTriangle tri;
  700. tri.Point0 = vertexOffset + convexElem.IndexData[3 * triIdx];
  701. tri.Point1 = vertexOffset + convexElem.IndexData[3 * triIdx + 1];
  702. tri.Point2 = vertexOffset + convexElem.IndexData[3 * triIdx + 2];
  703. tri.Surface = surfIdx;
  704. GeometryData.Triangles.Add(tri);
  705. }
  706. }
  707. }
  708. void UAkGeometryComponent::SendGeometry()
  709. {
  710. FAkAudioDevice* AkAudioDevice = FAkAudioDevice::Get();
  711. if (AkAudioDevice && ShouldSendGeometry())
  712. {
  713. if (GeometryData.Triangles.Num() > 0 && GeometryData.Vertices.Num() > 0)
  714. {
  715. AkGeometryParams params;
  716. params.NumSurfaces = GeometryData.Surfaces.Num();
  717. params.NumTriangles = GeometryData.Triangles.Num();
  718. params.NumVertices = GeometryData.Vertices.Num();
  719. TArray<AkAcousticSurface> Surfaces;
  720. TArray< TSharedPtr< decltype(StringCast<ANSICHAR>(TEXT(""))) > > SurfaceNames;
  721. Surfaces.SetNum(params.NumSurfaces);
  722. SurfaceNames.SetNum(params.NumSurfaces);
  723. if (params.NumSurfaces)
  724. {
  725. for (int i = 0; i < params.NumSurfaces; ++i)
  726. {
  727. Surfaces[i].transmissionLoss = GeometryData.Surfaces[i].Occlusion;
  728. Surfaces[i].strName = nullptr;
  729. if (!GeometryData.Surfaces[i].Name.IsEmpty())
  730. {
  731. SurfaceNames[i] = MakeShareable(new decltype(StringCast<ANSICHAR>(TEXT("")))(*GeometryData.Surfaces[i].Name));
  732. Surfaces[i].strName = SurfaceNames[i].Get()->Get();
  733. }
  734. Surfaces[i].textureID = GeometryData.Surfaces[i].Texture;
  735. }
  736. }
  737. params.Surfaces = Surfaces.GetData();
  738. TUniquePtr<AkTriangle[]> Triangles = MakeUnique<AkTriangle[]>(params.NumTriangles);// temp triangle buffer
  739. for (int i = 0; i < params.NumTriangles; ++i)
  740. {
  741. Triangles[i].point0 = GeometryData.Triangles[i].Point0;
  742. Triangles[i].point1 = GeometryData.Triangles[i].Point1;
  743. Triangles[i].point2 = GeometryData.Triangles[i].Point2;
  744. Triangles[i].surface = GeometryData.Triangles[i].Surface;
  745. }
  746. params.Triangles = Triangles.Get();
  747. TUniquePtr<AkVertex[]> Vertices = MakeUnique<AkVertex[]>(params.NumVertices); // temp vertex buffer
  748. for (int i = 0; i < params.NumVertices; ++i)
  749. {
  750. Vertices[i].X = GeometryData.Vertices[i].X;
  751. Vertices[i].Y = GeometryData.Vertices[i].Y;
  752. Vertices[i].Z = GeometryData.Vertices[i].Z;
  753. }
  754. params.Vertices = Vertices.Get();
  755. params.EnableDiffraction = bEnableDiffraction;
  756. params.EnableDiffractionOnBoundaryEdges = bEnableDiffractionOnBoundaryEdges;
  757. SendGeometryToWwise(params);
  758. }
  759. else
  760. {
  761. UE_LOG(LogAkAudio, Warning, TEXT("%s: UAkGeometryComponent::SendGeometry() Geometry Data is empty. Nothing was sent to Spatial Audio."), *GetOwner()->GetName());
  762. }
  763. }
  764. }
  765. void UAkGeometryComponent::RemoveGeometry()
  766. {
  767. RemoveGeometryFromWwise();
  768. }
  769. void UAkGeometryComponent::UpdateGeometry()
  770. {
  771. if (Parent)
  772. {
  773. AkRoomID roomID = AkRoomID();
  774. if (AssociatedRoom)
  775. {
  776. UAkRoomComponent* room = Cast<UAkRoomComponent>(AssociatedRoom->GetComponentByClass(UAkRoomComponent::StaticClass()));
  777. if (room != nullptr)
  778. roomID = room->GetRoomID();
  779. }
  780. SendGeometryInstanceToWwise(Parent->GetComponentRotation(), Parent->GetComponentLocation(), Parent->GetComponentTransform().GetScale3D(), roomID, !bWasAddedByRoom);
  781. }
  782. }
  783. void UAkGeometryComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
  784. {
  785. Super::EndPlay(EndPlayReason);
  786. RemoveGeometry();
  787. }
  788. float UAkGeometryComponent::GetSurfaceAreaSquaredMeters(const int& surfaceIndex) const
  789. {
  790. if (SurfaceAreas.Contains(surfaceIndex))
  791. return SurfaceAreas[surfaceIndex] / AkComponentHelpers::UnrealUnitsPerSquaredMeter(Parent);
  792. return 0.0f;
  793. }
  794. #if WITH_EDITOR
  795. void UAkGeometryComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
  796. {
  797. Super::PostEditChangeProperty(PropertyChangedEvent);
  798. if (AkComponentHelpers::IsGameWorldBlueprintComponent(this) || IsBeingDestroyed())
  799. return;
  800. if (AssociatedRoom && !Cast<UAkRoomComponent>(AssociatedRoom->GetComponentByClass(UAkRoomComponent::StaticClass())))
  801. {
  802. UE_LOG(LogAkAudio, Warning, TEXT("%s: The Associated Room is not of type UAkRoomComponent."), *GetOwner()->GetName());
  803. }
  804. const FName memberPropertyName = (PropertyChangedEvent.MemberProperty != nullptr) ? PropertyChangedEvent.MemberProperty->GetFName() : NAME_None;
  805. const FName PropertyName = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None;
  806. if (memberPropertyName == GET_MEMBER_NAME_CHECKED(UAkGeometryComponent, MeshType))
  807. {
  808. if (Parent != nullptr && MeshType == AkMeshType::StaticMesh)
  809. {
  810. UStaticMeshComponent* MeshParent = Cast<UStaticMeshComponent>(Parent);
  811. if (MeshParent == nullptr)
  812. {
  813. FString actorString = FString("NONE");
  814. if (GetOwner() != nullptr)
  815. actorString = GetOwner()->GetName();
  816. FString parentName = Parent->GetName();
  817. FString parentClass = Parent->GetClass()->GetName();
  818. UE_LOG(LogAkAudio, Warning,
  819. TEXT("On actor %s, there is a UAkGeometryComponent (%s) attached to parent of type %s (%s).")
  820. , *actorString, *GetName(), *parentClass, *parentName);
  821. UE_LOG(LogAkAudio, Warning, TEXT("When MeshType is set to Static Mesh, UAkGeometryComponent requires to be nested under a component inheriting from UStaticMeshComponent. Reverting to Simple Collision."));
  822. MeshType = AkMeshType::CollisionMesh;
  823. }
  824. else
  825. {
  826. UpdateStaticMeshOverride();
  827. }
  828. }
  829. UnregisterTextureParamChangeCallbacks();
  830. RegisterAllTextureParamCallbacks();
  831. }
  832. else if ( (memberPropertyName == GET_MEMBER_NAME_CHECKED(UAkGeometryComponent, StaticMeshSurfaceOverride) && MeshType == AkMeshType::StaticMesh)
  833. || (memberPropertyName == GET_MEMBER_NAME_CHECKED(UAkGeometryComponent, CollisionMeshSurfaceOverride) && MeshType == AkMeshType::CollisionMesh))
  834. {
  835. UnregisterTextureParamChangeCallbacks();
  836. RegisterAllTextureParamCallbacks();
  837. DampingEstimationNeedsUpdate = true;
  838. }
  839. if (MeshType == AkMeshType::StaticMesh &&
  840. memberPropertyName == GET_MEMBER_NAME_CHECKED(UAkGeometryComponent, WeldingThreshold) &&
  841. PropertyChangedEvent.ChangeType == EPropertyChangeType::ValueSet)
  842. {
  843. ConvertMesh();
  844. SendGeometry();
  845. UpdateGeometry();
  846. }
  847. else if (memberPropertyName == GET_MEMBER_NAME_CHECKED(UAkGeometryComponent, bEnableDiffraction) ||
  848. memberPropertyName == GET_MEMBER_NAME_CHECKED(UAkGeometryComponent, bEnableDiffractionOnBoundaryEdges))
  849. {
  850. SendGeometry();
  851. UpdateGeometry();
  852. }
  853. }
  854. void UAkGeometryComponent::PostEditUndo()
  855. {
  856. OnRefreshDetails.ExecuteIfBound();
  857. Super::PostEditUndo();
  858. }
  859. void UAkGeometryComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
  860. {
  861. Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
  862. if (bRequiresDeferredBeginPlay)
  863. {
  864. BeginPlayInternal();
  865. bRequiresDeferredBeginPlay = false;
  866. }
  867. if (MeshType == AkMeshType::StaticMesh)
  868. {
  869. if (IsValid(Parent) && !Parent->IsBeingDestroyed())
  870. {
  871. UStaticMeshComponent* MeshParent = Cast<UStaticMeshComponent>(Parent);
  872. if (MeshParent != nullptr && StaticMeshSurfaceOverride.Num() != MeshParent->GetNumMaterials())
  873. UpdateMeshAndArchetype(MeshParent);
  874. }
  875. if (bMeshMaterialChanged)
  876. {
  877. OnRefreshDetails.ExecuteIfBound();
  878. bMeshMaterialChanged = false;
  879. }
  880. }
  881. }
  882. #endif
  883. void UAkGeometryComponent::UpdateStaticMeshOverride()
  884. {
  885. UStaticMeshComponent* MeshParent = Cast<UStaticMeshComponent>(Parent);
  886. if (MeshParent != nullptr)
  887. {
  888. UpdateMeshAndArchetype(MeshParent);
  889. }
  890. }
  891. void UAkGeometryComponent::UpdateMeshAndArchetype(UStaticMeshComponent* StaticMeshComponent)
  892. {
  893. _UpdateStaticMeshOverride(StaticMeshComponent);
  894. // If we're in the Blueprint editor, update the Archetype object as well.
  895. // (The archetype object is the object that's edited when properties are changed in the Blueprint editor details inspector.
  896. // This is a separate object from the objects shown in the Blueprint editor viewport.)
  897. UWorld* World = GetWorld();
  898. if (World != nullptr && World->WorldType == EWorldType::EditorPreview
  899. && CreationMethod == EComponentCreationMethod::SimpleConstructionScript)
  900. {
  901. UAkGeometryComponent* Archetype = Cast<UAkGeometryComponent>(GetArchetype());
  902. if (Archetype != nullptr)
  903. Archetype->_UpdateStaticMeshOverride(StaticMeshComponent);
  904. }
  905. }
  906. void UAkGeometryComponent::_UpdateStaticMeshOverride(UStaticMeshComponent* StaticMeshComponent)
  907. {
  908. auto ToRemove = StaticMeshSurfaceOverride;
  909. int numMaterials = StaticMeshComponent->GetNumMaterials();
  910. for (int i = 0; i < numMaterials; i++)
  911. {
  912. UMaterialInterface* material = StaticMeshComponent->GetMaterial(i);
  913. if (StaticMeshSurfaceOverride.Contains(material))
  914. ToRemove.Remove(material);
  915. else
  916. {
  917. FAkGeometrySurfaceOverride surfaceOverride;
  918. if (PreviousStaticMeshSurfaceOverride.Contains(material))
  919. surfaceOverride = PreviousStaticMeshSurfaceOverride[material];
  920. StaticMeshSurfaceOverride.Add(material, surfaceOverride);
  921. }
  922. }
  923. #if WITH_EDITORONLY_DATA
  924. if (ToRemove.Num() > 0)
  925. bMeshMaterialChanged = true;
  926. #endif
  927. for (auto& elemToRemove : ToRemove)
  928. StaticMeshSurfaceOverride.Remove(elemToRemove.Key);
  929. ToRemove.Empty();
  930. PreviousStaticMeshSurfaceOverride.Empty();
  931. PreviousStaticMeshSurfaceOverride = StaticMeshSurfaceOverride;
  932. }
  933. void UAkGeometryComponent::Serialize(FArchive& Ar)
  934. {
  935. #if WITH_EDITORONLY_DATA
  936. UWorld* World = GetWorld();
  937. if (Ar.IsSaving() && World != nullptr && !World->IsGameWorld())
  938. ConvertMesh();
  939. #endif
  940. Super::Serialize(Ar);
  941. }
  942. void UAkGeometryComponent::GetTexturesAndSurfaceAreas(TArray<FAkAcousticTextureParams>& textures, TArray<float>& surfaceAreas) const
  943. {
  944. textures.Empty();
  945. surfaceAreas.Empty();
  946. const UAkSettings* AkSettings = GetDefault<UAkSettings>();
  947. if (AkSettings != nullptr)
  948. {
  949. if (MeshType == AkMeshType::CollisionMesh)
  950. {
  951. if (CollisionMeshSurfaceOverride.AcousticTexture != nullptr)
  952. {
  953. #if WITH_EDITOR
  954. // Get the most accurate absorption values from the list in the AkSettings
  955. const FAkAcousticTextureParams* params = AkSettings->GetTextureParams(CollisionMeshSurfaceOverride.AcousticTexture->GetShortID());
  956. if (params != nullptr)
  957. {
  958. textures.Add(*params);
  959. surfaceAreas.Add(1.0f); // When there is only 1 acoustic texture, surface area magnitude is not important.
  960. }
  961. #else
  962. // Get the absorption values from the cooked data
  963. FAkAcousticTextureParams params;
  964. params.AbsorptionValues = FVector4(
  965. CollisionMeshSurfaceOverride.AcousticTexture->AcousticTextureCookedData.AbsorptionLow / 100.0f,
  966. CollisionMeshSurfaceOverride.AcousticTexture->AcousticTextureCookedData.AbsorptionMidLow / 100.0f,
  967. CollisionMeshSurfaceOverride.AcousticTexture->AcousticTextureCookedData.AbsorptionMidHigh / 100.0f,
  968. CollisionMeshSurfaceOverride.AcousticTexture->AcousticTextureCookedData.AbsorptionHigh / 100.0f
  969. );
  970. textures.Add(params);
  971. surfaceAreas.Add(1.0f); // When there is only 1 acoustic texture, surface area magnitude is not important.
  972. #endif
  973. }
  974. }
  975. else
  976. {
  977. if (StaticMeshSurfaceOverride.Num() > 0)
  978. {
  979. int surfIdx = 0;
  980. float surfaceArea = 0.0f;
  981. for (auto it = StaticMeshSurfaceOverride.CreateConstIterator(); it; ++it)
  982. {
  983. surfaceArea = GetSurfaceAreaSquaredMeters(surfIdx);
  984. surfaceAreas.Add(surfaceArea);
  985. FAkAcousticTextureParams params;
  986. FAkGeometrySurfaceOverride surface = it.Value();
  987. if (surface.AcousticTexture != nullptr)
  988. {
  989. #if WITH_EDITOR
  990. // Get the most accurate absorption values from the list in the AkSettings
  991. const FAkAcousticTextureParams* paramsFound = AkSettings->GetTextureParams(surface.AcousticTexture->GetShortID());
  992. if (paramsFound != nullptr)
  993. {
  994. params = *paramsFound;
  995. }
  996. #else
  997. params.AbsorptionValues = FVector4(
  998. surface.AcousticTexture->AcousticTextureCookedData.AbsorptionLow / 100.0f,
  999. surface.AcousticTexture->AcousticTextureCookedData.AbsorptionMidLow / 100.0f,
  1000. surface.AcousticTexture->AcousticTextureCookedData.AbsorptionMidHigh / 100.0f,
  1001. surface.AcousticTexture->AcousticTextureCookedData.AbsorptionHigh / 100.0f
  1002. );
  1003. #endif
  1004. }
  1005. textures.Add(params);
  1006. ++surfIdx;
  1007. }
  1008. }
  1009. }
  1010. }
  1011. }
  1012. #if WITH_EDITOR
  1013. void UAkGeometryComponent::HandleObjectsReplaced(const TMap<UObject*, UObject*>& ReplacementMap)
  1014. {
  1015. Super::HandleObjectsReplaced(ReplacementMap);
  1016. if (ReplacementMap.Contains(Parent))
  1017. {
  1018. InitializeParent();
  1019. if (Parent != nullptr)
  1020. {
  1021. if (MeshType == AkMeshType::StaticMesh)
  1022. {
  1023. UStaticMeshComponent* MeshParent = Cast<UStaticMeshComponent>(Parent);
  1024. if (MeshParent != nullptr)
  1025. CalculateSurfaceArea(MeshParent);
  1026. }
  1027. DampingEstimationNeedsUpdate = true;
  1028. }
  1029. }
  1030. }
  1031. bool UAkGeometryComponent::ContainsTexture(const FGuid& textureID)
  1032. {
  1033. if (MeshType == AkMeshType::CollisionMesh)
  1034. {
  1035. if (CollisionMeshSurfaceOverride.AcousticTexture != nullptr)
  1036. return CollisionMeshSurfaceOverride.AcousticTexture->AcousticTextureInfo.WwiseGuid == textureID;
  1037. }
  1038. else
  1039. {
  1040. for (auto it = StaticMeshSurfaceOverride.CreateIterator(); it; ++it)
  1041. {
  1042. if (it.Value().AcousticTexture != nullptr)
  1043. {
  1044. if (it.Value().AcousticTexture->AcousticTextureInfo.WwiseGuid == textureID)
  1045. return true;
  1046. }
  1047. }
  1048. }
  1049. return false;
  1050. }
  1051. void UAkGeometryComponent::RegisterAllTextureParamCallbacks()
  1052. {
  1053. if (MeshType == AkMeshType::CollisionMesh)
  1054. {
  1055. if (CollisionMeshSurfaceOverride.AcousticTexture != nullptr)
  1056. RegisterTextureParamChangeCallback(CollisionMeshSurfaceOverride.AcousticTexture->AcousticTextureInfo.WwiseGuid);
  1057. }
  1058. else
  1059. {
  1060. for (auto it = StaticMeshSurfaceOverride.CreateIterator(); it; ++it)
  1061. {
  1062. if (it.Value().AcousticTexture != nullptr)
  1063. {
  1064. RegisterTextureParamChangeCallback(it.Value().AcousticTexture->AcousticTextureInfo.WwiseGuid);
  1065. }
  1066. }
  1067. }
  1068. }
  1069. #endif