示例#1
0
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 );
    }
}
示例#2
0
/**
 * Creates a model from the triangles in a static mesh.
 */
void CreateModelFromStaticMesh(UModel* Model,AStaticMeshActor* StaticMeshActor)
{
#if TODO_STATICMESH
    UStaticMesh*	StaticMesh = StaticMeshActor->StaticMeshComponent->StaticMesh;
    FMatrix			ActorToWorld = StaticMeshActor->ActorToWorld().ToMatrixWithScale();

    Model->Polys->Element.Empty();

    const FStaticMeshTriangle* RawTriangleData = (FStaticMeshTriangle*) StaticMesh->LODModels[0].RawTriangles.Lock(LOCK_READ_ONLY);
    if(StaticMesh->LODModels[0].RawTriangles.GetElementCount())
    {
        for(int32 TriangleIndex = 0; TriangleIndex < StaticMesh->LODModels[0].RawTriangles.GetElementCount(); TriangleIndex++)
        {
            const FStaticMeshTriangle&	Triangle	= RawTriangleData[TriangleIndex];
            FPoly*						Polygon		= new(Model->Polys->Element) FPoly;

            Polygon->Init();
            Polygon->iLink = Polygon - Model->Polys->Element.GetData();
            Polygon->Material = StaticMesh->LODModels[0].Elements[Triangle.MaterialIndex].Material;
            Polygon->PolyFlags = PF_DefaultFlags;
            Polygon->SmoothingMask = Triangle.SmoothingMask;

            new(Polygon->Vertices) FVector(ActorToWorld.TransformPosition(Triangle.Vertices[2]));
            new(Polygon->Vertices) FVector(ActorToWorld.TransformPosition(Triangle.Vertices[1]));
            new(Polygon->Vertices) FVector(ActorToWorld.TransformPosition(Triangle.Vertices[0]));

            Polygon->CalcNormal(1);
            Polygon->Finalize(NULL,0);
            FTexCoordsToVectors(Polygon->Vertices[2],FVector(Triangle.UVs[0][0].X * UModel::GetGlobalBSPTexelScale(),Triangle.UVs[0][0].Y * UModel::GetGlobalBSPTexelScale(),1),
                                Polygon->Vertices[1],FVector(Triangle.UVs[1][0].X * UModel::GetGlobalBSPTexelScale(),Triangle.UVs[1][0].Y * UModel::GetGlobalBSPTexelScale(),1),
                                Polygon->Vertices[0],FVector(Triangle.UVs[2][0].X * UModel::GetGlobalBSPTexelScale(),Triangle.UVs[2][0].Y * UModel::GetGlobalBSPTexelScale(),1),
                                &Polygon->Base,&Polygon->TextureU,&Polygon->TextureV);
        }
    }
    StaticMesh->LODModels[0].RawTriangles.Unlock();

    Model->Linked = 1;
    FBSPOps::bspValidateBrush(Model,0,1);
    Model->BuildBound();
#endif // #if TODO_STATICMESH
}
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;
}