void DecomposeUCXMesh( const TArray<FVector>& CollisionVertices, const TArray<int32>& CollisionFaceIdx, UBodySetup* BodySetup ) { // We keep no ref to this Model, so it will be GC'd at some point after the import. auto TempModel = NewObject<UModel>(); TempModel->Initialize(nullptr, 1); FMeshConnectivityBuilder ConnectivityBuilder; // Send triangles to connectivity builder for(int32 x = 0; x < CollisionFaceIdx.Num(); x += 3) { const FVector &VertexA = CollisionVertices[ CollisionFaceIdx[x + 2] ]; const FVector &VertexB = CollisionVertices[ CollisionFaceIdx[x + 1] ]; const FVector &VertexC = CollisionVertices[ CollisionFaceIdx[x + 0] ]; ConnectivityBuilder.AddTriangle( VertexA, VertexB, VertexC ); } ConnectivityBuilder.CreateConnectivityGroups(); // For each valid group build BSP and extract convex hulls for ( int32 i=0; i<ConnectivityBuilder.Groups.Num(); i++ ) { const FMeshConnectivityGroup &Group = ConnectivityBuilder.Groups[ i ]; // TODO: add some BSP friendly checks here // e.g. if group triangles form a closed mesh // Generate polygons from group triangles TempModel->Polys->Element.Empty(); for ( int32 j=0; j<Group.Triangles.Num(); j++ ) { const FMeshConnectivityTriangle &Triangle = ConnectivityBuilder.Triangles[ Group.Triangles[j] ]; FPoly* Poly = new( TempModel->Polys->Element ) FPoly(); Poly->Init(); Poly->iLink = j / 3; // Add vertices new( Poly->Vertices ) FVector( ConnectivityBuilder.Vertices[ Triangle.Vertices[0] ].Position ); new( Poly->Vertices ) FVector( ConnectivityBuilder.Vertices[ Triangle.Vertices[1] ].Position ); new( Poly->Vertices ) FVector( ConnectivityBuilder.Vertices[ Triangle.Vertices[2] ].Position ); // Update polygon normal Poly->CalcNormal(1); } // 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 ); // Convert collision model into a collection of convex hulls. // Generated convex hulls will be added to existing ones BodySetup->CreateFromModel( TempModel, false ); } }
Mesh2::Mesh2(const char * filename) { // read the mesh int nt,nv,nbe; int ok=load(filename); if(ok) { ifstream f(filename); if(!f) {cerr << "Mesh2::Mesh2 Erreur openning " << filename<<endl;exit(1);} if(verbosity) cout << " Read On file \"" <<filename<<"\""<< endl; f >> nv >> nt >> nbe ; this->set(nv,nt,nbe); if(verbosity) cout << " -- Nb of Vertex " << nv << " " << " Nb of Triangles " << nt << " , Nb of border edges " << nbe << endl; assert(f.good() && nt && nv) ; for (int i=0;i<nv;i++) { f >> this->vertices[i]; assert(f.good()); } mes=0; for (int i=0;i<nt;i++) { this->t(i).Read1(f,this->vertices,nv); mes += t(i).mesure(); } mesb=0.; for (int i=0;i<nbe;i++) { this->be(i).Read1(f,this->vertices,nv); mesb += be(i).mesure(); } } BuildBound(); BuildAdj(); Buildbnormalv(); BuildjElementConteningVertex(); if(verbosity) cout << " - mesh mesure = " << mes << " border mesure: " << mesb << endl; }
Mesh2::Mesh2(FILE *f) { GRead(f); assert( (nt >= 0 || nbe>=0) && nv>0) ; BuildBound(); if(verbosity>1) cout << " -- End of read: mesure = " << mes << " border mesure " << mesb << endl; if(nt > 0){ BuildAdj(); Buildbnormalv(); BuildjElementConteningVertex(); } if(verbosity>1) cout << " -- Mesh2 (File *), d "<< 2 << ", n Tet " << nt << ", n Vtx " << nv << " n Bord " << nbe << endl; }
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; }