Advertisement
Guest User

Untitled

a guest
May 27th, 2014
723
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.30 KB | None | 0 0
  1. diff --git a/Engine/Plugins/Runtime/CableComponent/CableComponent.uplugin b/Engine/Plugins/Runtime/CableComponent/CableComponent.uplugin
  2. index eb42d2d..99508ab 100644
  3. --- a/Engine/Plugins/Runtime/CableComponent/CableComponent.uplugin
  4. +++ b/Engine/Plugins/Runtime/CableComponent/CableComponent.uplugin
  5. @@ -3,9 +3,9 @@
  6.  
  7. "FriendlyName" : "CableComponent Plugin",
  8. "Version" : 1,
  9. - "VersionName" : "1.0",
  10. - "CreatedBy" : "Epic Games, Inc.",
  11. - "CreatedByURL" : "http://epicgames.com",
  12. + "VersionName" : "1.1",
  13. + "CreatedBy" : "Epic Games, Inc.; Vitaly Varivdin",
  14. + "CreatedByURL" : "http://epicgames.com; vitaly.varivdin@gmail.com",
  15. "MinEngineVersion" : 1579795,
  16. "Description" : "A simulated cable component.",
  17. "CategoryPath" : "Programming Rendering.Plugins",
  18. diff --git a/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Classes/CableComponent.h b/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Classes/CableComponent.h
  19. index 169daea..1352243 100644
  20. --- a/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Classes/CableComponent.h
  21. +++ b/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Classes/CableComponent.h
  22. @@ -4,24 +4,87 @@
  23.  
  24. #include "CableComponent.generated.h"
  25.  
  26. +UENUM()
  27. +namespace ECableParticleState
  28. +{
  29. + enum Type
  30. + {
  31. + Free,
  32. + Fixed,
  33. + Attached
  34. + };
  35. +}
  36. +
  37. /** Struct containing information about a point along the cable */
  38. +USTRUCT()
  39. struct FCableParticle
  40. {
  41. + GENERATED_USTRUCT_BODY()
  42. +
  43. FCableParticle()
  44. - : bFree(true)
  45. - , Position(0,0,0)
  46. - , OldPosition(0,0,0)
  47. + : State(ECableParticleState::Free),
  48. + Position(0, 0, 0),
  49. + OldPosition(0, 0, 0),
  50. + Acceleration(0, 0, 0),
  51. + Mass(1.0f),
  52. + InverseMass(1.0f)
  53. {}
  54.  
  55. - /** If this point is free (simulating) or fixed to something */
  56. - bool bFree;
  57. + UPROPERTY(EditAnywhere, Category = "Particle")
  58. + TEnumAsByte<ECableParticleState::Type> State;
  59. +
  60. /** Current position of point */
  61. + UPROPERTY(EditAnywhere, Category = "Particle")
  62. FVector Position;
  63. /** Position of point on previous iteration */
  64. + UPROPERTY(EditAnywhere, Category = "Particle")
  65. FVector OldPosition;
  66. + /** Acceleration. Accumulated each tick */
  67. + UPROPERTY(EditAnywhere, Category = "Particle")
  68. + FVector Acceleration;
  69. +
  70. + /** Mass of the particle */
  71. + UPROPERTY(EditAnywhere, Category = "Particle")
  72. + float Mass;
  73. + UPROPERTY(EditAnywhere, Category = "Particle")
  74. + float InverseMass;
  75. +
  76. + /** Defines actor component if particle is attached to object */
  77. + UPROPERTY(EditAnywhere, Category = "Particle")
  78. + FComponentReference AttachedTo;
  79. +
  80. + void VerletIntegrate(float InSubstepTime, const FVector& Gravity);
  81. +
  82. + void ApplyForce(FVector Force);
  83. +};
  84. +
  85. +USTRUCT()
  86. +struct FCableParticlesConstraint
  87. +{
  88. + GENERATED_USTRUCT_BODY()
  89. +
  90. + FCableParticlesConstraint()
  91. + : RestLength(50.0f),
  92. + BreakLengthFactor(1.2f),
  93. + BreakLength(60.0f),
  94. + Stiffness(1.0f)
  95. + {}
  96. +
  97. + FCableParticle* ParticleA;
  98. + FCableParticle* ParticleB;
  99. +
  100. + UPROPERTY(EditAnywhere, Category = "Constraint")
  101. + float RestLength;
  102. + UPROPERTY(EditAnywhere, Category = "Constraint")
  103. + float BreakLengthFactor;
  104. + UPROPERTY(EditAnywhere, Category = "Constraint")
  105. + float BreakLength;
  106. + UPROPERTY(EditAnywhere, Category = "Constraint")
  107. + float Stiffness;
  108. +
  109. + void Solve();
  110. };
  111.  
  112. -/** Component that allows you to specify custom triangle mesh geometry */
  113. UCLASS(hidecategories=(Object, LOD, Physics, Collision, Activation, "Components|Activation"), editinlinenew, meta=(BlueprintSpawnableComponent), ClassGroup=Rendering)
  114. class UCableComponent : public UMeshComponent
  115. {
  116. @@ -47,31 +110,31 @@ public:
  117. virtual int32 GetNumMaterials() const OVERRIDE;
  118. // End UMeshComponent interface.
  119.  
  120. -
  121. - /** Actor or Component that the end of the cable should be attached to */
  122. - UPROPERTY(EditAnywhere, Category="Cable")
  123. - FComponentReference AttachEndTo;
  124. -
  125. - /** End location of cable, relative to AttachEndTo if specified, otherwise relative to cable component. */
  126. - UPROPERTY(EditAnywhere, Category="Cable")
  127. - FVector EndLocation;
  128. + /** Simulation properties */
  129.  
  130. /** Rest length of the cable */
  131. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cable", meta=(ClampMin = "0.0", UIMin = "0.0", UIMax = "1000.0"))
  132. float CableLength;
  133.  
  134. /** How many segments the cable has */
  135. - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Cable", meta=(ClampMin = "1", UIMin = "1", UIMax = "20"))
  136. + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Cable", meta=(ClampMin = "1", UIMin = "1", UIMax = "50"))
  137. int32 NumSegments;
  138.  
  139. - /** Controls the simulation substep time for the cable */
  140. - UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadOnly, Category="Cable", meta=(ClampMin = "0.005", UIMin = "0.005", UIMax = "0.1"))
  141. - float SubstepTime;
  142. + UPROPERTY(EditAnywhere, Category="Cable", meta=(ClampMin = "0.0", UIMin = "0.0", UIMax = "100.0"))
  143. + float ParticleMass;
  144. +
  145. + UPROPERTY(EditAnywhere, Category="Cable", meta=(ClampMin = "0.0", UIMin = "0.1", UIMax = "1.0"))
  146. + float ConstraintStiffness;
  147.  
  148. /** The number of solver iterations controls how 'stiff' the cable is */
  149. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cable", meta=(ClampMin = "1", ClampMax = "8"))
  150. int32 SolverIterations;
  151.  
  152. + /** Controls the simulation substep time for the cable */
  153. + UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadOnly, Category = "Cable", meta = (ClampMin = "0.005", UIMin = "0.005", UIMax = "0.1"))
  154. + float SubstepTime;
  155. +
  156. + /** Rendering properties */
  157.  
  158. /** How wide the cable geometry is */
  159. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cable Rendering", meta=(ClampMin = "0.01", UIMin = "0.01", UIMax = "50.0"))
  160. @@ -87,18 +150,23 @@ public:
  161.  
  162. private:
  163.  
  164. - /** Solve the cable spring constraints */
  165. - void SolveConstraints();
  166. - /** Integrate cable point positions */
  167. - void VerletIntegrate(float SubstepTime, const FVector& Gravity);
  168. /** Perform a simulation substep */
  169. void PerformSubstep(float SubstepTime, const FVector& Gravity);
  170. /** Get start and end position for the cable */
  171. - void GetEndPositions(FVector& OutStartPosition, FVector& OutEndPosition);
  172. + FVector GetStartPosition();
  173. /** Amount of time 'left over' from last tick */
  174. float TimeRemainder;
  175. +
  176. /** Array of cable particles */
  177. - TArray<FCableParticle> Particles;
  178. + UPROPERTY(EditAnywhere, Category = "Cable")
  179. + TArray<FCableParticle> Particles;
  180. + /** Array of particle constraints */
  181. + UPROPERTY(EditAnywhere, Category = "Cable")
  182. + TArray<FCableParticlesConstraint> Constraints;
  183. +
  184. + /** Stored particle states for restoring before renegeration.
  185. + * Allows to change particle state in editor. There might be a better way i guess. */
  186. + TMap<int, ECableParticleState::Type> States;
  187.  
  188.  
  189. friend class FCableSceneProxy;
  190. diff --git a/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Private/CableComponent.cpp b/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Private/CableComponent.cpp
  191. index 0d2df89..3d15135 100644
  192. --- a/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Private/CableComponent.cpp
  193. +++ b/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Private/CableComponent.cpp
  194. @@ -312,27 +312,77 @@ private:
  195. float TileMaterial;
  196. };
  197.  
  198. +void FCableParticle::VerletIntegrate(float InSubstepTime, const FVector& Gravity)
  199. +{
  200. + const float SubstepTimeSqr = InSubstepTime * InSubstepTime;
  201. +
  202. + if(State != ECableParticleState::Fixed)
  203. + {
  204. + ApplyForce(Mass * Gravity);
  205. +
  206. + const FVector Vel = Position - OldPosition;
  207. + const FVector NewPosition = Position + Vel + (Acceleration * SubstepTimeSqr);
  208. +
  209. + OldPosition = Position;
  210. + Position = NewPosition;
  211. + Acceleration = FVector(0, 0, 0);
  212. + }
  213. +}
  214.  
  215. +void FCableParticle::ApplyForce(FVector Force)
  216. +{
  217. + if(State != ECableParticleState::Fixed)
  218. + {
  219. + // Acceleration += 1 / Mass * Force;
  220. + Acceleration += Force / Mass;
  221. + }
  222. +}
  223. +
  224. +void FCableParticlesConstraint::Solve()
  225. +{
  226. + // Find current vector between particles
  227. + FVector Delta = ParticleB->Position - ParticleA->Position;
  228. +
  229. + float CurrentDistance = Delta.Size();
  230. + float ErrorFactor = (CurrentDistance - RestLength) / CurrentDistance;
  231. +
  232. + float ScalarA = (ParticleA->InverseMass / (ParticleA->InverseMass + ParticleB->InverseMass)) * Stiffness;
  233. + float ScalarB = Stiffness - ScalarA;
  234. +
  235. + // Only move free or attached particles to satisfy constraints
  236. + if(ParticleA->State != ECableParticleState::Fixed)
  237. + {
  238. + ParticleA->Position += ScalarA * ErrorFactor * Delta;
  239. + }
  240. +
  241. + if(ParticleB->State != ECableParticleState::Fixed)
  242. + {
  243. + ParticleB->Position -= ScalarB * ErrorFactor * Delta;
  244. + }
  245. +}
  246.  
  247. //////////////////////////////////////////////////////////////////////////
  248.  
  249. -UCableComponent::UCableComponent( const FPostConstructInitializeProperties& PCIP )
  250. - : Super( PCIP )
  251. +UCableComponent::UCableComponent(const FPostConstructInitializeProperties& PCIP)
  252. + : Super(PCIP)
  253. {
  254. PrimaryComponentTick.bCanEverTick = true;
  255. bTickInEditor = true;
  256. bAutoActivate = true;
  257.  
  258. - CableWidth = 10.f;
  259. - NumSegments = 10;
  260. - NumSides = 4;
  261. - EndLocation = FVector(0,0,0);
  262. CableLength = 100.f;
  263. + NumSegments = 10;
  264. + ParticleMass = 1.0f;
  265. + ConstraintStiffness = 0.5f;
  266. SubstepTime = 0.02f;
  267. SolverIterations = 1;
  268. +
  269. + CableWidth = 10.f;
  270. + NumSides = 4;
  271. TileMaterial = 1.f;
  272.  
  273. - SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName);
  274. + SetCollisionProfileName(UCollisionProfile::BlockAll_ProfileName);
  275. }
  276.  
  277. FPrimitiveSceneProxy* UCableComponent::CreateSceneProxy()
  278. @@ -349,137 +399,143 @@ void UCableComponent::OnRegister()
  279. {
  280. Super::OnRegister();
  281.  
  282. - const int32 NumParticles = NumSegments+1;
  283. + // Save states before regenerating
  284. + for(int32 ParticleIdx = 0; ParticleIdx < Particles.Num(); ParticleIdx++)
  285. + {
  286. + States.Add(ParticleIdx, Particles[ParticleIdx].State);
  287. + }
  288. +
  289. + const int32 NumParticles = NumSegments + 1;
  290. + const int32 NumConstraints = NumSegments;
  291.  
  292. Particles.Reset();
  293. Particles.AddUninitialized(NumParticles);
  294.  
  295. - FVector CableStart, CableEnd;
  296. - GetEndPositions(CableStart, CableEnd);
  297. -
  298. - const FVector Delta = CableEnd - CableStart;
  299. + Constraints.Reset();
  300. + Constraints.AddUninitialized(NumSegments);
  301.  
  302. - for(int32 ParticleIdx=0; ParticleIdx<NumParticles; ParticleIdx++)
  303. - {
  304. - FCableParticle& Particle = Particles[ParticleIdx];
  305. + FVector CableStart = GetStartPosition();
  306.  
  307. - const float Alpha = (float)ParticleIdx/(float)NumSegments;
  308. - const FVector InitialPosition = CableStart + (Alpha * Delta);
  309. + FVector Delta = -FVector::UpVector;
  310.  
  311. - Particle.Position = InitialPosition;
  312. - Particle.OldPosition = InitialPosition;
  313. + for(int32 ParticleIdx = 0; ParticleIdx < NumParticles; ParticleIdx++)
  314. + {
  315. + const float Alpha = (float)ParticleIdx / (float)NumParticles;
  316. + const FVector InitialPosition = CableStart + Delta * (Alpha * CableLength);
  317.  
  318. - // fix particles at ends
  319. - if(ParticleIdx == 0 || ParticleIdx == NumParticles-1)
  320. + FCableParticle& Particle = Particles[ParticleIdx];
  321. +
  322. + // Resotre state
  323. + if(States.Contains(ParticleIdx))
  324. {
  325. - Particle.bFree = false;
  326. + Particle.State = States[ParticleIdx];
  327. }
  328. else
  329. {
  330. - Particle.bFree = true;
  331. + Particle.State = ECableParticleState::Free;
  332. }
  333. - }
  334. -}
  335.  
  336. -void UCableComponent::VerletIntegrate(float InSubstepTime, const FVector& Gravity)
  337. -{
  338. - const int32 NumParticles = NumSegments+1;
  339. - const float SubstepTimeSqr = InSubstepTime * InSubstepTime;
  340. + Particle.Position = InitialPosition;
  341. + Particle.OldPosition = InitialPosition;
  342. + Particle.Acceleration = FVector(0,0,0);
  343. + Particle.Mass = ParticleMass;
  344. + Particle.InverseMass = 1 / Particle.Mass;
  345. + Particle.AttachedTo.OtherActor = 0;
  346. + }
  347.  
  348. - for(int32 ParticleIdx=0; ParticleIdx<NumParticles; ParticleIdx++)
  349. + for(int32 ConstraintIdx = 0; ConstraintIdx < NumConstraints; ConstraintIdx++)
  350. {
  351. - FCableParticle& Particle = Particles[ParticleIdx];
  352. - if(Particle.bFree)
  353. - {
  354. - const FVector Vel = Particle.Position - Particle.OldPosition;
  355. - const FVector NewPosition = Particle.Position + Vel + (SubstepTimeSqr * Gravity);
  356. + FCableParticlesConstraint& Constraint = Constraints[ConstraintIdx];
  357.  
  358. - Particle.OldPosition = Particle.Position;
  359. - Particle.Position = NewPosition;
  360. - }
  361. + Constraint.ParticleA = &Particles[ConstraintIdx];
  362. + Constraint.ParticleB = &Particles[ConstraintIdx + 1];
  363. + Constraint.RestLength = CableLength / NumConstraints;
  364. + Constraint.BreakLength = Constraint.RestLength * Constraint.BreakLengthFactor;
  365. + Constraint.Stiffness = ConstraintStiffness;
  366. }
  367. +
  368. + // Fix start particle
  369. + Particles[0].State = ECableParticleState::Fixed;
  370. + //Particles.Last().State = ECableParticleState::Fixed;
  371. }
  372.  
  373. -/** Solve a single distance constraint between a pair of particles */
  374. -static void SolveDistanceConstraint(FCableParticle& ParticleA, FCableParticle& ParticleB, float DesiredDistance)
  375. +void UCableComponent::PerformSubstep(float InSubstepTime, const FVector& Gravity)
  376. {
  377. - // Find current vector between particles
  378. - FVector Delta = ParticleB.Position - ParticleA.Position;
  379. - //
  380. - float CurrentDistance = Delta.Size();
  381. - float ErrorFactor = (CurrentDistance - DesiredDistance)/CurrentDistance;
  382. + const int32 NumParticles = Particles.Num();
  383. + const int32 NumConstraints = Constraints.Num();
  384.  
  385. - // Only move free particles to satisfy constraints
  386. - if(ParticleA.bFree && ParticleB.bFree)
  387. + // Perform verlet integration on every particle
  388. + for(int32 ParticleIdx = 0; ParticleIdx < NumParticles; ParticleIdx++)
  389. {
  390. - ParticleA.Position += ErrorFactor * 0.5f * Delta;
  391. - ParticleB.Position -= ErrorFactor * 0.5f * Delta;
  392. + Particles[ParticleIdx].VerletIntegrate(InSubstepTime, Gravity);
  393. }
  394. - else if(ParticleA.bFree)
  395. - {
  396. - ParticleA.Position += ErrorFactor * Delta;
  397. - }
  398. - else if(ParticleB.bFree)
  399. - {
  400. - ParticleB.Position -= ErrorFactor * Delta;
  401. - }
  402. -}
  403. -
  404. -void UCableComponent::SolveConstraints()
  405. -{
  406. - const float SegmentLength = CableLength/(float)NumSegments;
  407.  
  408. - // For each iteration..
  409. - for(int32 IterationIdx=0; IterationIdx<SolverIterations; IterationIdx++)
  410. + // Solve distance constraint between particles for each iteration
  411. + for(int32 IterationIdx = 0; IterationIdx < SolverIterations; IterationIdx++)
  412. {
  413. - // For each segment..
  414. - for(int32 SegIdx=0; SegIdx<NumSegments; SegIdx++)
  415. + for(int32 ConstraintIdx = 0; ConstraintIdx < NumConstraints; ConstraintIdx++)
  416. {
  417. - FCableParticle& ParticleA = Particles[SegIdx];
  418. - FCableParticle& ParticleB = Particles[SegIdx+1];
  419. - // Solve for this pair of particles
  420. - SolveDistanceConstraint(ParticleA, ParticleB, SegmentLength);
  421. + Constraints[ConstraintIdx].Solve();
  422. }
  423. }
  424. }
  425.  
  426. -void UCableComponent::PerformSubstep(float InSubstepTime, const FVector& Gravity)
  427. +FVector UCableComponent::GetStartPosition()
  428. {
  429. - VerletIntegrate(InSubstepTime, Gravity);
  430. - SolveConstraints();
  431. + // Start position is just component position
  432. + return GetComponentLocation();
  433. }
  434.  
  435. -void UCableComponent::GetEndPositions(FVector& OutStartPosition, FVector& OutEndPosition)
  436. +void UCableComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
  437. {
  438. - // Start position is just component position
  439. - OutStartPosition = GetComponentLocation();
  440. + Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
  441.  
  442. - // See if we want to attach the other end to some other component
  443. - USceneComponent* EndComponent = AttachEndTo.GetComponent(GetOwner());
  444. - if(EndComponent == NULL)
  445. + for(int32 ParticleIdx = 0; ParticleIdx < Particles.Num(); ParticleIdx++)
  446. {
  447. - EndComponent = this;
  448. - }
  449. + FCableParticle& Particle = Particles[ParticleIdx];
  450.  
  451. - OutEndPosition = EndComponent->ComponentToWorld.TransformPosition(EndLocation);
  452. -}
  453. + switch(Particle.State)
  454. + {
  455. + case ECableParticleState::Free:
  456. + DrawDebugPoint(GetWorld(), Particle.Position, 10.0f, FColor::Green);
  457. + break;
  458. + case ECableParticleState::Fixed:
  459. + DrawDebugPoint(GetWorld(), Particle.Position, 10.0f, FColor::Red);
  460.  
  461. -void UCableComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
  462. -{
  463. - Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
  464. + if(Particle.AttachedTo.OtherActor->IsValidLowLevel())
  465. + {
  466. + Particle.Position = Particle.AttachedTo.GetComponent(GetOwner())->GetComponentLocation();
  467. + }
  468. +
  469. + break;
  470. + case ECableParticleState::Attached:
  471. + DrawDebugPoint(GetWorld(), Particle.Position, 10.0f, FColor::Blue);
  472. +
  473. + if(Particle.AttachedTo.OtherActor->IsValidLowLevel())
  474. + {
  475. + Particle.AttachedTo.GetComponent(GetOwner())->SetWorldLocation(Particle.Position);
  476. +
  477. + UPrimitiveComponent* Primitive = Particle.AttachedTo.OtherActor->FindComponentByClass<UPrimitiveComponent>();
  478. +
  479. + if(Primitive)
  480. + {
  481. + Particle.Mass = ParticleMass + Primitive->GetMass();
  482. + Particle.InverseMass = 1 / Particle.Mass;
  483. + }
  484. + }
  485. +
  486. + break;
  487. + }
  488. + }
  489.  
  490. const FVector Gravity = FVector(0, 0, GetWorld()->GetGravityZ());
  491.  
  492. // Update end points
  493. - FVector CableStart, CableEnd;
  494. - GetEndPositions(CableStart, CableEnd);
  495. + FVector CableStart = GetStartPosition();
  496.  
  497. FCableParticle& StartParticle = Particles[0];
  498. StartParticle.Position = StartParticle.OldPosition = CableStart;
  499. -
  500. - FCableParticle& EndParticle = Particles[NumSegments];
  501. - EndParticle.Position = EndParticle.OldPosition = CableEnd;
  502. -
  503. +
  504. // Ensure a non-zero substep
  505. float UseSubstep = FMath::Max(SubstepTime, 0.005f);
  506.  
  507. @@ -506,9 +562,9 @@ void UCableComponent::SendRenderDynamicData_Concurrent()
  508. FCableDynamicData* DynamicData = new FCableDynamicData;
  509.  
  510. // Transform current positions from particles into component-space array
  511. - int32 NumPoints = NumSegments+1;
  512. + int32 NumPoints = Particles.Num();
  513. DynamicData->CablePoints.AddUninitialized(NumPoints);
  514. - for(int32 PointIdx=0; PointIdx<NumPoints; PointIdx++)
  515. + for(int32 PointIdx = 0; PointIdx < NumPoints; PointIdx++)
  516. {
  517. DynamicData->CablePoints[PointIdx] = ComponentToWorld.InverseTransformPosition(Particles[PointIdx].Position);
  518. }
  519. @@ -528,7 +584,8 @@ FBoxSphereBounds UCableComponent::CalcBounds(const FTransform & LocalToWorld) co
  520. {
  521. // Calculate bounding box of cable points
  522. FBox CableBox(0);
  523. - for(int32 ParticleIdx=0; ParticleIdx<Particles.Num(); ParticleIdx++)
  524. +
  525. + for(int32 ParticleIdx = 0; ParticleIdx < Particles.Num(); ParticleIdx++)
  526. {
  527. const FCableParticle& Particle = Particles[ParticleIdx];
  528. CableBox += Particle.Position;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement