bool FKConvexElem::HullFromPlanes(const TArray<FPlane>& InPlanes, const TArray<FVector>& SnapVerts) { // Start by clearing this convex. Reset(); float TotalPolyArea = 0; for(int32 i=0; i<InPlanes.Num(); i++) { FPoly Polygon; Polygon.Normal = InPlanes[i]; FVector AxisX, AxisY; Polygon.Normal.FindBestAxisVectors(AxisX,AxisY); const FVector Base = InPlanes[i] * InPlanes[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<InPlanes.Num(); j++) { if(i != j) { if(!Polygon.Split(-FVector(InPlanes[j]), InPlanes[j] * InPlanes[j].W)) { Polygon.Vertices.Empty(); break; } } } // Do nothing if poly was completely clipped away. if(Polygon.Vertices.Num() > 0) { TotalPolyArea += Polygon.Area(); // Add vertices of polygon to convex primitive. for(int32 j=0; j<Polygon.Vertices.Num(); j++) { // We try and snap the vert to on of the ones supplied. int32 NearestVert = INDEX_NONE; float NearestDistSqr = BIG_NUMBER; for(int32 k=0; k<SnapVerts.Num(); k++) { const float DistSquared = (Polygon.Vertices[j] - SnapVerts[k]).SizeSquared(); if( DistSquared < NearestDistSqr ) { NearestVert = k; NearestDistSqr = DistSquared; } } // If we have found a suitably close vertex, use that if( NearestVert != INDEX_NONE && NearestDistSqr < LOCAL_EPS ) { const FVector localVert = SnapVerts[NearestVert]; AddVertexIfNotPresent(VertexData, localVert); } else { const FVector localVert = Polygon.Vertices[j]; AddVertexIfNotPresent(VertexData, localVert); } } } } // If the collision volume isn't closed, return an error so the model can be discarded if(TotalPolyArea < 0.001f) { UE_LOG(LogPhysics, Log, TEXT("Total Polygon Area invalid: %f"), TotalPolyArea ); return false; } // We need at least 4 vertices to make a convex hull with non-zero volume. // We shouldn't have the same vertex multiple times (using AddVertexIfNotPresent above) if(VertexData.Num() < 4) { return true; } // Check that not all vertices lie on a line (ie. find plane) // Again, this should be a non-zero vector because we shouldn't have duplicate verts. bool bFound = false; FVector Dir2, Dir1; Dir1 = VertexData[1] - VertexData[0]; Dir1.Normalize(); for(int32 i=2; i<VertexData.Num() && !bFound; i++) { Dir2 = VertexData[i] - VertexData[0]; Dir2.Normalize(); // If line are non-parallel, this vertex forms our plane if((Dir1 | Dir2) < (1.f - LOCAL_EPS)) { bFound = true; } } if(!bFound) { return true; } // Now we check that not all vertices lie on a plane, by checking at least one lies off the plane we have formed. FVector Normal = Dir1 ^ Dir2; Normal.Normalize(); const FPlane Plane(VertexData[0], Normal); bFound = false; for(int32 i=2; i<VertexData.Num() ; i++) { if(Plane.PlaneDot(VertexData[i]) > LOCAL_EPS) { bFound = true; break; } } // If we did not find a vert off the line - discard this hull. if(!bFound) { return true; } // calc bounding box of verts UpdateElemBox(); // We can continue adding primitives (mesh is not horribly broken) return true; }