void UBuoyancyForceComponent::InitializeComponent() { Super::InitializeComponent(); //UE_LOG(LogTemp, Warning, TEXT("We're initializing...")); //Store the world ref. World = GetWorld(); // If no OceanManager is defined, auto-detect if (!OceanManager) { for (TActorIterator<AOceanManager> ActorItr(World); ActorItr; ++ActorItr) { OceanManager = Cast<AOceanManager>(*ActorItr); break; } } TestPointRadius = FMath::Abs(TestPointRadius); UPrimitiveComponent* BasePrimComp = Cast<UPrimitiveComponent>(GetAttachParent()); if (BasePrimComp) { ApplyUprightConstraint(BasePrimComp); //Store the initial damping values. _baseLinearDamping = BasePrimComp->GetLinearDamping(); _baseAngularDamping = BasePrimComp->GetAngularDamping(); } }
USceneComponent* FComponentEditorUtils::FindClosestParentInList(UActorComponent* ChildComponent, const TArray<UActorComponent*>& ComponentList) { USceneComponent* ClosestParentComponent = nullptr; for (auto Component : ComponentList) { auto ChildAsScene = Cast<USceneComponent>(ChildComponent); auto SceneComponent = Cast<USceneComponent>(Component); if (ChildAsScene && SceneComponent) { // Check to see if any parent is also in the list USceneComponent* Parent = ChildAsScene->GetAttachParent(); while (Parent != nullptr) { if (ComponentList.Contains(Parent)) { ClosestParentComponent = SceneComponent; break; } Parent = Parent->GetAttachParent(); } } } return ClosestParentComponent; }
void UPhysicsSpringComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); if (UPrimitiveComponent* BasePrimComp = Cast<UPrimitiveComponent>(GetAttachParent())) { if (bIsActive) { const FVector SpringStart = ComponentToWorld.GetLocation(); const FVector SpringDesiredEnd = SpringPositionFromLength(SpringLengthAtRest); float CollisionTime = 1.f; UPrimitiveComponent* CollideWith = GetSpringCollision(SpringStart, SpringDesiredEnd, CollisionTime); CurrentEndPoint = FMath::Lerp(SpringStart, SpringDesiredEnd, CollisionTime); if(CollideWith) { const float Mass = BasePrimComp->GetMass(); float NewSpringCompression; const FVector WorldForce = ComputeNewSpringCompressionAndForce(CurrentEndPoint, DeltaTime, NewSpringCompression); BasePrimComp->AddForceAtLocation(WorldForce*Mass, SpringStart, GetAttachSocketName()); SpringCompression = NewSpringCompression; } UpdateAttachedPosition(); } } }
bool UPostProcessComponent::EncompassesPoint(FVector Point, float SphereRadius/*=0.f*/, float* OutDistanceToPoint) { UShapeComponent* ParentShape = Cast<UShapeComponent>(GetAttachParent()); if (ParentShape != nullptr) { #if WITH_PHYSX FVector ClosestPoint; float Distance = ParentShape->GetDistanceToCollision(Point, ClosestPoint); #else FBoxSphereBounds Bounds = ParentShape->CalcBounds(ParentShape->ComponentToWorld); float Distance = 0; if (ParentShape->IsA<USphereComponent>()) { const FSphere& Sphere = Bounds.GetSphere(); const FVector& Dist = Sphere.Center - Point; Distance = FMath::Max(0.0f, Dist.Size() - Sphere.W); } else // UBox or UCapsule shape (approx). { Distance = FMath::Sqrt(Bounds.GetBox().ComputeSquaredDistanceToPoint(Point)); } #endif if (OutDistanceToPoint) { *OutDistanceToPoint = Distance; } return Distance >= 0.f && Distance <= SphereRadius; } if (OutDistanceToPoint != nullptr) { *OutDistanceToPoint = 0; } return true; }
void UInfiniteSystemComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); // If disabled or we are not attached to a parent component, return. if (!bIsActive || !GetAttachParent() || !World) return; FVector CamLoc; FRotator CamRot; FVector PawnLoc; FVector NewLoc; #if WITH_EDITOR if (GIsEditor) { if (!UpdateInEditor) return; TArray<FVector> viewLocations = GetWorld()->ViewLocationsRenderedLastFrame; if (viewLocations.Num() != 0) { CamLoc = viewLocations[0]; } //FEditorViewportClient* client = (FEditorViewportClient*)GEditor->GetActiveViewport()->GetClient(); //CamLoc = client->GetViewLocation(); //CamRot = client->GetViewRotation(); if (FollowMethod == LookAtLocation || FollowMethod == FollowCamera) { NewLoc = CamLoc; NewLoc = NewLoc.GridSnap(GridSnapSize); NewLoc.Z = GetAttachParent()->GetComponentLocation().Z; GetAttachParent()->SetWorldLocation(NewLoc); } else { GetAttachParent()->SetRelativeLocation(FVector(0, 0, 0)); //Reset location } float Distance = FMath::Abs(CamLoc.Z - GetAttachParent()->GetComponentLocation().Z); if (ScaleByDistance && Distance > ScaleStartDistance) { Distance = Distance - ScaleStartDistance; Distance = FMath::Max(Distance, 0.f); float DistScale = Distance / ScaleDistanceFactor; DistScale = FMath::Clamp(DistScale, ScaleMin, ScaleMax); GetAttachParent()->SetRelativeScale3D(FVector(DistScale, DistScale, 1)); } else if (ScaleByDistance) { GetAttachParent()->SetRelativeScale3D(FVector(ScaleMin, ScaleMin, 1)); } else { GetAttachParent()->SetRelativeScale3D(FVector(1, 1, 1)); } // if (ScaleByDistance && FMath::Abs(CamLoc.Z - AttachParent->GetComponentLocation().Z) > ScaleStartDistance) // { // float DistScale = FMath::Abs(CamLoc.Z - AttachParent->GetComponentLocation().Z) / ScaleDistanceFactor; // DistScale = FMath::Clamp(DistScale, ScaleMin, ScaleMax); // AttachParent->SetRelativeScale3D(FVector(DistScale, DistScale, 1)); //Scale only on x & y axis // } // else if (!ScaleByDistance) // { // AttachParent->SetRelativeScale3D(FVector(1, 1, 1)); //Reset scale // } return; } #endif if (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE) { if (!GEngine || !GEngine->GetFirstLocalPlayerController(World)) return; GEngine->GetFirstLocalPlayerController(World)->PlayerCameraManager->GetCameraViewPoint(CamLoc, CamRot); if (GEngine->GetFirstLocalPlayerController(World)->GetPawn()) //null check { PawnLoc = GEngine->GetFirstLocalPlayerController(World)->GetPawn()->GetActorLocation(); } else { PawnLoc = GetAttachParent()->GetComponentLocation(); } } switch (FollowMethod) { case LookAtLocation: if (!FMath::SegmentPlaneIntersection(CamLoc, CamLoc + CamRot.Vector() * MaxLookAtDistance, FPlane(GetAttachParent()->GetComponentLocation(), FVector(0, 0, 1)), NewLoc)) { NewLoc = CamLoc + CamRot.Vector() * MaxLookAtDistance; } break; case FollowCamera: NewLoc = CamLoc; break; case FollowPawn: NewLoc = PawnLoc; break; default: break; }; //UE_LOG(LogTemp, Warning, TEXT("Camera Z Distance from Plane: %f"), FMath::Abs(CamLoc.Z - AttachParent->GetComponentLocation().Z)); float Distance = FMath::Abs(CamLoc.Z - GetAttachParent()->GetComponentLocation().Z); if (ScaleByDistance && Distance > ScaleStartDistance) { Distance = Distance - ScaleStartDistance; Distance = FMath::Max(Distance, 0.f); float DistScale = Distance / ScaleDistanceFactor; DistScale = FMath::Clamp(DistScale, ScaleMin, ScaleMax); GetAttachParent()->SetRelativeScale3D(FVector(DistScale, DistScale, 1)); } else if (ScaleByDistance) { GetAttachParent()->SetRelativeScale3D(FVector(ScaleMin, ScaleMin, 1)); } else { GetAttachParent()->SetRelativeScale3D(FVector(1, 1, 1)); } if (FollowMethod == Stationary) return; NewLoc = NewLoc.GridSnap(GridSnapSize); NewLoc.Z = GetAttachParent()->GetComponentLocation().Z; GetAttachParent()->SetWorldLocation(NewLoc); }
void UBuoyancyForceComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); // If disabled or we are not attached to a parent component, return. if (!bIsActive || !GetAttachParent()) return; if (!OceanManager) return; UPrimitiveComponent* BasePrimComp = Cast<UPrimitiveComponent>(GetAttachParent()); if (!BasePrimComp) return; if (!BasePrimComp->IsSimulatingPhysics()) { if (!SnapToSurfaceIfNoPhysics) return; UE_LOG(LogTemp, Warning, TEXT("Running in no physics mode..")); float waveHeight = OceanManager->GetWaveHeightValue(BasePrimComp->GetComponentLocation(), World, true, TwoGerstnerIterations).Z; BasePrimComp->SetWorldLocation(FVector(BasePrimComp->GetComponentLocation().X, BasePrimComp->GetComponentLocation().Y, waveHeight)); return; } //Get gravity float Gravity = BasePrimComp->GetPhysicsVolume()->GetGravityZ(); //--------------- If Skeletal --------------- USkeletalMeshComponent* SkeletalComp = Cast<USkeletalMeshComponent>(GetAttachParent()); if (SkeletalComp && ApplyForceToBones) { TArray<FName> BoneNames; SkeletalComp->GetBoneNames(BoneNames); for (int32 Itr = 0; Itr < BoneNames.Num(); Itr++) { FBodyInstance* BI = SkeletalComp->GetBodyInstance(BoneNames[Itr], false); if (BI && BI->IsValidBodyInstance() && BI->bEnableGravity) //Buoyancy doesn't exist without gravity { bool isUnderwater = false; //FVector worldBoneLoc = SkeletalComp->GetBoneLocation(BoneNames[Itr]); FVector worldBoneLoc = BI->GetCOMPosition(); //Use center of mass of the bone's physics body instead of bone's location FVector waveHeight = OceanManager->GetWaveHeightValue(worldBoneLoc, World, true, TwoGerstnerIterations); float BoneDensity = MeshDensity; float BoneTestRadius = FMath::Abs(TestPointRadius); float SignedBoneRadius = FMath::Sign(Gravity) * TestPointRadius; //Direction of radius (test radius is actually a Z offset, should probably rename it!). Just in case we need an upside down world. //Get density & radius from the override array, if available. for (int pointIndex = 0; pointIndex < BoneOverride.Num(); pointIndex++) { FStructBoneOverride Override = BoneOverride[pointIndex]; if (Override.BoneName.IsEqual(BoneNames[Itr])) { BoneDensity = Override.Density; BoneTestRadius = FMath::Abs(Override.TestRadius); SignedBoneRadius = FMath::Sign(Gravity) * BoneTestRadius; } } //If test point radius is below water surface, add buoyancy force. if (waveHeight.Z > (worldBoneLoc.Z + SignedBoneRadius)) { isUnderwater = true; float DepthMultiplier = (waveHeight.Z - (worldBoneLoc.Z + SignedBoneRadius)) / (BoneTestRadius * 2); DepthMultiplier = FMath::Clamp(DepthMultiplier, 0.f, 1.f); float Mass = SkeletalComp->CalculateMass(BoneNames[Itr]); //Mass of this specific bone's physics body /** * -------- * Buoyancy force formula: (Volume(Mass / Density) * Fluid Density * -Gravity) / Total Points * Depth Multiplier * -------- */ float BuoyancyForceZ = Mass / BoneDensity * FluidDensity * -Gravity * DepthMultiplier; //Velocity damping. FVector DampingForce = -BI->GetUnrealWorldVelocity() * VelocityDamper * Mass * DepthMultiplier; //Experimental xy wave force if (EnableWaveForces) { float waveVelocity = FMath::Clamp(BI->GetUnrealWorldVelocity().Z, -20.f, 150.f) * (1 - DepthMultiplier); DampingForce += FVector(OceanManager->GlobalWaveDirection.X, OceanManager->GlobalWaveDirection.Y, 0) * Mass * waveVelocity * WaveForceMultiplier; } //Add force to this bone BI->AddForce(FVector(DampingForce.X, DampingForce.Y, DampingForce.Z + BuoyancyForceZ)); //BasePrimComp->AddForceAtLocation(FVector(DampingForce.X, DampingForce.Y, DampingForce.Z + BuoyancyForceZ), worldBoneLoc, BoneNames[Itr]); } //Apply fluid damping & clamp velocity if (isUnderwater) { BI->SetLinearVelocity(-BI->GetUnrealWorldVelocity() * (FluidLinearDamping / 10), true); BI->SetAngularVelocity(-BI->GetUnrealWorldAngularVelocity() * (FluidAngularDamping / 10), true); //Clamp the velocity to MaxUnderwaterVelocity if (ClampMaxVelocity && BI->GetUnrealWorldVelocity().Size() > MaxUnderwaterVelocity) { FVector Velocity = BI->GetUnrealWorldVelocity().GetSafeNormal() * MaxUnderwaterVelocity; BI->SetLinearVelocity(Velocity, false); } } if (DrawDebugPoints) { FColor DebugColor = FLinearColor(0.8, 0.7, 0.2, 0.8).ToRGBE(); if (isUnderwater) { DebugColor = FLinearColor(0, 0.2, 0.7, 0.8).ToRGBE(); } //Blue color underwater, yellow out of watter DrawDebugSphere(World, worldBoneLoc, BoneTestRadius, 8, DebugColor); } } } return; } //-------------------------------------------------------- float TotalPoints = TestPoints.Num(); if (TotalPoints < 1) return; int PointsUnderWater = 0; for (int pointIndex = 0; pointIndex < TotalPoints; pointIndex++) { if (!TestPoints.IsValidIndex(pointIndex)) return; //Array size changed during runtime bool isUnderwater = false; FVector testPoint = TestPoints[pointIndex]; FVector worldTestPoint = BasePrimComp->GetComponentTransform().TransformPosition(testPoint); FVector waveHeight = OceanManager->GetWaveHeightValue(worldTestPoint, World, !EnableWaveForces, TwoGerstnerIterations); //Direction of radius (test radius is actually a Z offset, should probably rename it!). Just in case we need an upside down world. float SignedRadius = FMath::Sign(BasePrimComp->GetPhysicsVolume()->GetGravityZ()) * TestPointRadius; //If test point radius is below water surface, add buoyancy force. if (waveHeight.Z > (worldTestPoint.Z + SignedRadius) && BasePrimComp->IsGravityEnabled()) //Buoyancy doesn't exist without gravity { PointsUnderWater++; isUnderwater = true; float DepthMultiplier = (waveHeight.Z - (worldTestPoint.Z + SignedRadius)) / (TestPointRadius * 2); DepthMultiplier = FMath::Clamp(DepthMultiplier, 0.f, 1.f); //If we have a point density override, use the overridden value instead of MeshDensity float PointDensity = PointDensityOverride.IsValidIndex(pointIndex) ? PointDensityOverride[pointIndex] : MeshDensity; /** * -------- * Buoyancy force formula: (Volume(Mass / Density) * Fluid Density * -Gravity) / Total Points * Depth Multiplier * -------- */ float BuoyancyForceZ = BasePrimComp->GetMass() / PointDensity * FluidDensity * -Gravity / TotalPoints * DepthMultiplier; //Experimental velocity damping using VelocityAtPoint. FVector DampingForce = -GetUnrealVelocityAtPoint(BasePrimComp, worldTestPoint) * VelocityDamper * BasePrimComp->GetMass() * DepthMultiplier; //Experimental xy wave force if (EnableWaveForces) { DampingForce += BasePrimComp->GetMass() * FVector2D(waveHeight.X, waveHeight.Y).Size() * FVector(OceanManager->GlobalWaveDirection.X, OceanManager->GlobalWaveDirection.Y, 0) * WaveForceMultiplier / TotalPoints; //float waveVelocity = FMath::Clamp(GetUnrealVelocityAtPoint(BasePrimComp, worldTestPoint).Z, -20.f, 150.f) * (1 - DepthMultiplier); //DampingForce += OceanManager->GlobalWaveDirection * BasePrimComp->GetMass() * waveVelocity * WaveForceMultiplier / TotalPoints; } //Add force for this test point BasePrimComp->AddForceAtLocation(FVector(DampingForce.X, DampingForce.Y, DampingForce.Z + BuoyancyForceZ), worldTestPoint); } if (DrawDebugPoints) { FColor DebugColor = FLinearColor(0.8, 0.7, 0.2, 0.8).ToRGBE(); if (isUnderwater) { DebugColor = FLinearColor(0, 0.2, 0.7, 0.8).ToRGBE(); } //Blue color underwater, yellow out of watter DrawDebugSphere(World, worldTestPoint, TestPointRadius, 8, DebugColor); } } //Clamp the velocity to MaxUnderwaterVelocity if there is any point underwater if (ClampMaxVelocity && PointsUnderWater > 0 && BasePrimComp->GetPhysicsLinearVelocity().Size() > MaxUnderwaterVelocity) { FVector Velocity = BasePrimComp->GetPhysicsLinearVelocity().GetSafeNormal() * MaxUnderwaterVelocity; BasePrimComp->SetPhysicsLinearVelocity(Velocity); } //Update damping based on number of underwater test points BasePrimComp->SetLinearDamping(_baseLinearDamping + FluidLinearDamping / TotalPoints * PointsUnderWater); BasePrimComp->SetAngularDamping(_baseAngularDamping + FluidAngularDamping / TotalPoints * PointsUnderWater); }