int32 GenerateSphylAsSimpleCollision(UStaticMesh* StaticMesh) { if (!PromptToRemoveExistingCollision(StaticMesh)) { return INDEX_NONE; } UBodySetup* bs = StaticMesh->BodySetup; // Calculate bounding box. FRawMesh RawMesh; FStaticMeshSourceModel& SrcModel = StaticMesh->SourceModels[0]; SrcModel.RawMeshBulkData->LoadRawMesh(RawMesh); FSphere sphere; float length; FRotator rotation; FVector unitVec = bs->BuildScale3D; CalcBoundingSphyl(RawMesh, sphere, length, rotation, unitVec); // Dont use if radius is zero. if (sphere.W <= 0.f) { FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Prompt_10", "Could not create geometry.")); return INDEX_NONE; } // If height is zero, then a sphere would be better (should we just create one instead?) if (length <= 0.f) { length = SMALL_NUMBER; } bs->Modify(); // Create new GUID bs->InvalidatePhysicsData(); FKSphylElem SphylElem; SphylElem.Center = sphere.Center; SphylElem.Orientation = rotation.Quaternion(); SphylElem.Radius = sphere.W; SphylElem.Length = length; bs->AggGeom.SphylElems.Add(SphylElem); // refresh collision change back to staticmesh components RefreshCollisionChange(StaticMesh); // Mark staticmesh as dirty, to help make sure it gets saved. StaticMesh->MarkPackageDirty(); StaticMesh->bCustomizedCollision = true; //mark the static mesh for collision customization return bs->AggGeom.SphylElems.Num() - 1; }
int32 GenerateSphereAsSimpleCollision(UStaticMesh* StaticMesh) { if (!PromptToRemoveExistingCollision(StaticMesh)) { return INDEX_NONE; } UBodySetup* bs = StaticMesh->BodySetup; // Calculate bounding sphere. FRawMesh RawMesh; FStaticMeshSourceModel& SrcModel = StaticMesh->SourceModels[0]; SrcModel.RawMeshBulkData->LoadRawMesh(RawMesh); FSphere bSphere, bSphere2, bestSphere; FVector unitVec = bs->BuildScale3D; CalcBoundingSphere(RawMesh, bSphere, unitVec); CalcBoundingSphere2(RawMesh, bSphere2, unitVec); if(bSphere.W < bSphere2.W) bestSphere = bSphere; else bestSphere = bSphere2; // Dont use if radius is zero. if(bestSphere.W <= 0.f) { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Prompt_10", "Could not create geometry.") ); return INDEX_NONE; } bs->Modify(); // Create new GUID bs->InvalidatePhysicsData(); FKSphereElem SphereElem; SphereElem.Center = bestSphere.Center; SphereElem.Radius = bestSphere.W; bs->AggGeom.SphereElems.Add(SphereElem); // refresh collision change back to staticmesh components RefreshCollisionChange(StaticMesh); // Mark staticmesh as dirty, to help make sure it gets saved. StaticMesh->MarkPackageDirty(); StaticMesh->bCustomizedCollision = true; //mark the static mesh for collision customization return bs->AggGeom.SphereElems.Num() - 1; }
int32 GenerateBoxAsSimpleCollision(UStaticMesh* StaticMesh) { if (!PromptToRemoveExistingCollision(StaticMesh)) { return INDEX_NONE; } UBodySetup* bs = StaticMesh->BodySetup; // Calculate bounding Box. FRawMesh RawMesh; FStaticMeshSourceModel& SrcModel = StaticMesh->SourceModels[0]; SrcModel.RawMeshBulkData->LoadRawMesh(RawMesh); FVector unitVec = bs->BuildScale3D; FVector Center, Extents; CalcBoundingBox(RawMesh, Center, Extents, unitVec); bs->Modify(); // Create new GUID bs->InvalidatePhysicsData(); FKBoxElem BoxElem; BoxElem.Center = Center; BoxElem.X = Extents.X * 2.0f; BoxElem.Y = Extents.Y * 2.0f; BoxElem.Z = Extents.Z * 2.0f; bs->AggGeom.BoxElems.Add(BoxElem); // refresh collision change back to staticmesh components RefreshCollisionChange(StaticMesh); // Mark staticmesh as dirty, to help make sure it gets saved. StaticMesh->MarkPackageDirty(); StaticMesh->bCustomizedCollision = true; //mark the static mesh for collision customization return bs->AggGeom.BoxElems.Num() - 1; }
int32 GenerateKDopAsSimpleCollision(UStaticMesh* StaticMesh, const TArray<FVector> &Dirs) { // Make sure rendering is done - so we are not changing data being used by collision drawing. FlushRenderingCommands(); if (!PromptToRemoveExistingCollision(StaticMesh)) { return INDEX_NONE; } UBodySetup* bs = StaticMesh->BodySetup; // Do k- specific stuff. int32 kCount = Dirs.Num(); TArray<float> maxDist; for(int32 i=0; i<kCount; i++) maxDist.Add(-MY_FLTMAX); // Construct temporary UModel for kdop creation. We keep no refs to it, so it can be GC'd. auto TempModel = NewObject<UModel>(); TempModel->Initialize(nullptr, 1); // For each vertex, project along each kdop direction, to find the max in that direction. const FStaticMeshLODResources& RenderData = StaticMesh->RenderData->LODResources[0]; for(int32 i=0; i<RenderData.GetNumVertices(); i++) { for(int32 j=0; j<kCount; j++) { float dist = RenderData.PositionVertexBuffer.VertexPosition(i) | Dirs[j]; maxDist[j] = FMath::Max(dist, maxDist[j]); } } // Inflate kdop to ensure it is no degenerate const float MinSize = 0.1f; for(int32 i=0; i<kCount; i++) { maxDist[i] += MinSize; } // Now we have the planes of the kdop, we work out the face polygons. TArray<FPlane> planes; for(int32 i=0; i<kCount; i++) planes.Add( FPlane(Dirs[i], maxDist[i]) ); for(int32 i=0; i<planes.Num(); i++) { FPoly* Polygon = new(TempModel->Polys->Element) FPoly(); FVector Base, AxisX, AxisY; Polygon->Init(); Polygon->Normal = planes[i]; Polygon->Normal.FindBestAxisVectors(AxisX,AxisY); Base = planes[i] * planes[i].W; new(Polygon->Vertices) FVector(Base + AxisX * HALF_WORLD_MAX + AxisY * HALF_WORLD_MAX); new(Polygon->Vertices) FVector(Base + AxisX * HALF_WORLD_MAX - AxisY * HALF_WORLD_MAX); new(Polygon->Vertices) FVector(Base - AxisX * HALF_WORLD_MAX - AxisY * HALF_WORLD_MAX); new(Polygon->Vertices) FVector(Base - AxisX * HALF_WORLD_MAX + AxisY * HALF_WORLD_MAX); for(int32 j=0; j<planes.Num(); j++) { if(i != j) { if(!Polygon->Split(-FVector(planes[j]), planes[j] * planes[j].W)) { Polygon->Vertices.Empty(); break; } } } if(Polygon->Vertices.Num() < 3) { // If poly resulted in no verts, remove from array TempModel->Polys->Element.RemoveAt(TempModel->Polys->Element.Num()-1); } else { // Other stuff... Polygon->iLink = i; Polygon->CalcNormal(1); } } if(TempModel->Polys->Element.Num() < 4) { TempModel = NULL; return INDEX_NONE; } // Build bounding box. TempModel->BuildBound(); // Build BSP for the brush. FBSPOps::bspBuild(TempModel,FBSPOps::BSP_Good,15,70,1,0); FBSPOps::bspRefresh(TempModel,1); FBSPOps::bspBuildBounds(TempModel); bs->Modify(); bs->CreateFromModel(TempModel, false); // create all body instances RefreshCollisionChange(StaticMesh); // Mark staticmesh as dirty, to help make sure it gets saved. StaticMesh->MarkPackageDirty(); return bs->AggGeom.ConvexElems.Num() - 1; }