void UBodySetup::RescaleSimpleCollision( FVector BuildScale ) { if( BuildScale3D != BuildScale ) { // Back out the old scale when applying the new scale const FVector ScaleMultiplier3D = (BuildScale / BuildScale3D); for (int32 i = 0; i < AggGeom.ConvexElems.Num(); i++) { FKConvexElem* ConvexElem = &(AggGeom.ConvexElems[i]); FTransform ConvexTrans = ConvexElem->GetTransform(); FVector ConvexLoc = ConvexTrans.GetLocation(); ConvexLoc *= ScaleMultiplier3D; ConvexTrans.SetLocation(ConvexLoc); ConvexElem->SetTransform(ConvexTrans); TArray<FVector>& Vertices = ConvexElem->VertexData; for (int32 VertIndex = 0; VertIndex < Vertices.Num(); ++VertIndex) { Vertices[VertIndex] *= ScaleMultiplier3D; } ConvexElem->UpdateElemBox(); } // @todo Deal with non-vector properties by just applying the max value for the time being const float ScaleMultiplier = ScaleMultiplier3D.GetMax(); for (int32 i = 0; i < AggGeom.SphereElems.Num(); i++) { FKSphereElem* SphereElem = &(AggGeom.SphereElems[i]); SphereElem->Center *= ScaleMultiplier3D; SphereElem->Radius *= ScaleMultiplier; } for (int32 i = 0; i < AggGeom.BoxElems.Num(); i++) { FKBoxElem* BoxElem = &(AggGeom.BoxElems[i]); BoxElem->Center *= ScaleMultiplier3D; BoxElem->X *= ScaleMultiplier3D.X; BoxElem->Y *= ScaleMultiplier3D.Y; BoxElem->Z *= ScaleMultiplier3D.Z; } for (int32 i = 0; i < AggGeom.SphylElems.Num(); i++) { FKSphylElem* SphylElem = &(AggGeom.SphylElems[i]); SphylElem->Center *= ScaleMultiplier3D; SphylElem->Radius *= ScaleMultiplier; SphylElem->Length *= ScaleMultiplier; } BuildScale3D = BuildScale; } }
float UKismetMathLibrary::GetMaxElement(FVector A) { return A.GetMax(); }
float AGameObject::HitBoundsSphericalRadius() { FVector extents = hitBox->GetScaledBoxExtent(); return extents.GetMax(); }
// Called every frame void ASpacePartioner::Tick( float DeltaTime ) { Super::Tick( DeltaTime ); //check(bInitialized); //check(bDrawDebugInfo); if (bInitialized && bDrawDebugInfo) { int level = 0; float max; float offsetMax; float offset; FVector maxExtent; FVector center; FVector tempForCoercion; FBoxCenterAndExtent OldBounds = FBoxCenterAndExtent(); int nodeCount = 0; int elementCount = 0; // Go through the nodes of the octree for (FSimpleOctree::TConstIterator<> NodeIt(*OctreeData); NodeIt.HasPendingNodes(); NodeIt.Advance()) { const FSimpleOctree::FNode& CurrentNode = NodeIt.GetCurrentNode(); const FOctreeNodeContext& CurrentContext = NodeIt.GetCurrentContext(); const FBoxCenterAndExtent& CurrentBounds = CurrentContext.Bounds; nodeCount++; FOREACH_OCTREE_CHILD_NODE(ChildRef) { if (CurrentNode.HasChild(ChildRef)) { NodeIt.PushChild(ChildRef); } } // If the extents have changed then we have moved a level. if (!OldBounds.Extent.Equals(CurrentBounds.Extent)) { level++; } OldBounds = CurrentBounds; // UE_LOG(LogTemp, Log, TEXT("Level: %d"), level); // Draw Node Bounds tempForCoercion = CurrentBounds.Extent; max = tempForCoercion.GetMax(); center = CurrentBounds.Center; // UE_LOG(LogTemp, Log, TEXT("center before: %s"), *center.ToString()); // To understand the math here check out the constructors in FOctreeNodeContext // Offset nodes that are not the root bounds if (!OctreeData->GetRootBounds().Extent.Equals(CurrentBounds.Extent)) { for (int i = 1; i < level; i++) { // Calculate offset offsetMax = max / (1.0f + (1.0f / FOctreeNodeContext::LoosenessDenominator)); offset = max - offsetMax; max = offsetMax; // Calculate Center Offset if (center.X > 0) { center.X = center.X + offset; } else { center.X = center.X - offset; } if (center.Y > 0) { center.Y = center.Y + offset; } else { center.Y = center.Y - offset; } if (center.Z > 0) { center.Z = center.Z + offset; } else { center.Z = center.Z - offset; } } } UE_LOG(LogTemp, Log, TEXT("max: %f"), max); // UE_LOG(LogTemp, Log, TEXT("center of nodes: %s"), *center.ToString()); maxExtent = FVector(max, max, max); // UE_LOG(LogTemp, Log, TEXT("Extent of nodes: %s"), *tempForCoercion.ToString()); DrawDebugBox(GetWorld(), center, maxExtent, FColor().Blue, false, 0.0f); DrawDebugSphere(GetWorld(), center + maxExtent, 4.0f, 12, FColor().Green, false, 0.0f); DrawDebugSphere(GetWorld(), center - maxExtent, 4.0f, 12, FColor().Red, false, 0.0f); for (FSimpleOctree::ElementConstIt ElementIt(CurrentNode.GetElementIt()); ElementIt; ++ElementIt) { const FOctreeElement& Sample = *ElementIt; // Draw debug boxes around elements max = Sample.BoxSphereBounds.BoxExtent.GetMax(); maxExtent = FVector(max, max, max); center = Sample.MyActor->GetActorLocation(); DrawDebugBox(GetWorld(), center, maxExtent, FColor().Blue, false, 0.0f); DrawDebugSphere(GetWorld(), center + maxExtent, 4.0f, 12, FColor().White, false, 0.0f); DrawDebugSphere(GetWorld(), center - maxExtent, 4.0f, 12, FColor().White, false, 0.0f); elementCount++; } } // UE_LOG(LogTemp, Log, TEXT("Node Count: %d, Element Count: %d"), nodeCount, elementCount); }
// This algorithm taken from Ritter, 1990 // This one seems to do well with asymmetric input. static void CalcBoundingSphere(const FRawMesh& RawMesh, FSphere& sphere, FVector& LimitVec) { if(RawMesh.VertexPositions.Num() == 0) return; FBox Box; // First, find AABB, remembering furthest points in each dir. Box.Min = RawMesh.VertexPositions[0] * LimitVec; Box.Max = Box.Min; FIntVector minIx, maxIx; // Extreme points. minIx = FIntVector::ZeroValue; maxIx = FIntVector::ZeroValue; for(uint32 i=1; i<(uint32)RawMesh.VertexPositions.Num(); i++) { FVector p = RawMesh.VertexPositions[i] * LimitVec; // X // if(p.X < Box.Min.X) { Box.Min.X = p.X; minIx.X = i; } else if(p.X > Box.Max.X) { Box.Max.X = p.X; maxIx.X = i; } // Y // if(p.Y < Box.Min.Y) { Box.Min.Y = p.Y; minIx.Y = i; } else if(p.Y > Box.Max.Y) { Box.Max.Y = p.Y; maxIx.Y = i; } // Z // if(p.Z < Box.Min.Z) { Box.Min.Z = p.Z; minIx.Z = i; } else if(p.Z > Box.Max.Z) { Box.Max.Z = p.Z; maxIx.Z = i; } } const FVector Extremes[3]={ (RawMesh.VertexPositions[maxIx.X] - RawMesh.VertexPositions[minIx.X]) * LimitVec, (RawMesh.VertexPositions[maxIx.Y] - RawMesh.VertexPositions[minIx.Y]) * LimitVec, (RawMesh.VertexPositions[maxIx.Z] - RawMesh.VertexPositions[minIx.Z]) * LimitVec }; // Now find extreme points furthest apart, and initial center and radius of sphere. float d2 = 0.f; for(int32 i=0; i<3; i++) { const float tmpd2 = Extremes[i].SizeSquared(); if(tmpd2 > d2) { d2 = tmpd2; sphere.Center = (RawMesh.VertexPositions[minIx(i)] + (0.5f * Extremes[i])) * LimitVec; sphere.W = 0.f; } } const FVector Extents = FVector(Extremes[0].X, Extremes[1].Y, Extremes[2].Z); // radius and radius squared float r = 0.5f * Extents.GetMax(); float r2 = FMath::Square(r); // Now check each point lies within this sphere. If not - expand it a bit. for(uint32 i=0; i<(uint32)RawMesh.VertexPositions.Num(); i++) { const FVector cToP = (RawMesh.VertexPositions[i] * LimitVec) - sphere.Center; const float pr2 = cToP.SizeSquared(); // If this point is outside our current bounding sphere's radius if(pr2 > r2) { // ..expand radius just enough to include this point. const float pr = FMath::Sqrt(pr2); r = 0.5f * (r + pr); r2 = FMath::Square(r); sphere.Center += ((pr-r)/pr * cToP); } } sphere.W = r; }