// // Build an FPoly representing an "infinite" plane (which exceeds the maximum // dimensions of the world in all directions) for a particular Bsp node. // FPoly FBSPOps::BuildInfiniteFPoly( UModel* Model, int32 iNode ) { FBspNode &Node = Model->Nodes [iNode ]; FBspSurf &Poly = Model->Surfs [Node.iSurf ]; FVector Base = Poly.Plane * Poly.Plane.W; FVector Normal = Poly.Plane; FVector Axis1,Axis2; // Find two non-problematic axis vectors. Normal.FindBestAxisVectors( Axis1, Axis2 ); // Set up the FPoly. FPoly EdPoly; EdPoly.Init(); EdPoly.Normal = Normal; EdPoly.Base = Base; new(EdPoly.Vertices) FVector(Base + Axis1*WORLD_MAX + Axis2*WORLD_MAX); new(EdPoly.Vertices) FVector(Base - Axis1*WORLD_MAX + Axis2*WORLD_MAX); new(EdPoly.Vertices) FVector(Base - Axis1*WORLD_MAX - Axis2*WORLD_MAX); new(EdPoly.Vertices) FVector(Base + Axis1*WORLD_MAX - Axis2*WORLD_MAX); return EdPoly; }
int32 FPoly::Triangulate( ABrush* InOwnerBrush, TArray<FPoly>& OutTriangles ) { #if WITH_EDITOR if( Vertices.Num() < 3 ) { return 0; } FClipSMPolygon Polygon(0); for( int32 v = 0 ; v < Vertices.Num() ; ++v ) { FClipSMVertex vtx; vtx.Pos = Vertices[v]; // Init other data so that VertsAreEqual won't compare garbage vtx.TangentX = FVector::ZeroVector; vtx.TangentY = FVector::ZeroVector; vtx.TangentZ = FVector::ZeroVector; vtx.Color = FColor(0, 0, 0); for( int32 uvIndex=0; uvIndex<ARRAY_COUNT(vtx.UVs); ++uvIndex ) { vtx.UVs[uvIndex] = FVector2D(0.f, 0.f); } Polygon.Vertices.Add( vtx ); } Polygon.FaceNormal = Normal; // Attempt to triangulate this polygon TArray<FClipSMTriangle> Triangles; if( TriangulatePoly( Triangles, Polygon ) ) { // Create a set of FPolys from the triangles OutTriangles.Empty(); FPoly TrianglePoly; for( int32 p = 0 ; p < Triangles.Num() ; ++p ) { FClipSMTriangle* tri = &(Triangles[p]); TrianglePoly.Init(); TrianglePoly.Base = tri->Vertices[0].Pos; TrianglePoly.Vertices.Add( tri->Vertices[0].Pos ); TrianglePoly.Vertices.Add( tri->Vertices[1].Pos ); TrianglePoly.Vertices.Add( tri->Vertices[2].Pos ); if( TrianglePoly.Finalize( InOwnerBrush, 0 ) == 0 ) { OutTriangles.Add( TrianglePoly ); } } } #endif return OutTriangles.Num(); }
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; }