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;
}
Esempio n. 2
0
	void AddConvexElemsToRigidActor_AssumesLocked() const
	{
		float ContactOffsetFactor, MaxContactOffset;
		GetContactOffsetParams(ContactOffsetFactor, MaxContactOffset);

		for (int32 i = 0; i < BodySetup->AggGeom.ConvexElems.Num(); i++)
		{
			const FKConvexElem& ConvexElem = BodySetup->AggGeom.ConvexElems[i];

			if (ConvexElem.ConvexMesh)
			{
				PxTransform PLocalPose;
				bool bUseNegX = CalcMeshNegScaleCompensation(Scale3D, PLocalPose);

				PxConvexMeshGeometry PConvexGeom;
				PConvexGeom.convexMesh = bUseNegX ? ConvexElem.ConvexMeshNegX : ConvexElem.ConvexMesh;
				PConvexGeom.scale.scale = U2PVector(Scale3DAbs * ConvexElem.GetTransform().GetScale3D().GetAbs());
				FTransform ConvexTransform = ConvexElem.GetTransform();
				if (ConvexTransform.GetScale3D().X < 0 || ConvexTransform.GetScale3D().Y < 0 || ConvexTransform.GetScale3D().Z < 0)
				{
					UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: [%s] ConvexElem[%d] has negative scale. Not currently supported"), *GetPathNameSafe(BodySetup->GetOuter()), i);
				}
				if (ConvexTransform.IsValid())
				{
					PxTransform PElementTransform = U2PTransform(ConvexTransform * RelativeTM);
					PLocalPose.q *= PElementTransform.q;
					PLocalPose.p = PElementTransform.p;
					PLocalPose.p.x *= Scale3D.X;
					PLocalPose.p.y *= Scale3D.Y;
					PLocalPose.p.z *= Scale3D.Z;

					if (PConvexGeom.isValid())
					{
						PxVec3 PBoundsExtents = PConvexGeom.convexMesh->getLocalBounds().getExtents();

						ensure(PLocalPose.isValid());
						{
							const float ContactOffset = FMath::Min(MaxContactOffset, ContactOffsetFactor * PBoundsExtents.minElement());
							AttachShape_AssumesLocked(PConvexGeom, PLocalPose, ContactOffset);
						}
					}
					else
					{
						UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: [%s] ConvexElem[%d] invalid"), *GetPathNameSafe(BodySetup->GetOuter()), i);
					}
				}
				else
				{
					UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: [%s] ConvexElem[%d] has invalid transform"), *GetPathNameSafe(BodySetup->GetOuter()), i);
				}
			}
			else
			{
				UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: ConvexElem is missing ConvexMesh (%d: %s)"), i, *BodySetup->GetPathName());
			}
		}
	}
Esempio n. 3
0
	void AddSphylsToRigidActor_AssumesLocked() const
	{
		float ContactOffsetFactor, MaxContactOffset;
		GetContactOffsetParams(ContactOffsetFactor, MaxContactOffset);

		float ScaleRadius = FMath::Max(Scale3DAbs.X, Scale3DAbs.Y);
		float ScaleLength = Scale3DAbs.Z;

		for (int32 i = 0; i < BodySetup->AggGeom.SphylElems.Num(); i++)
		{
			const FKSphylElem& SphylElem = BodySetup->AggGeom.SphylElems[i];

			// this is a bit confusing since radius and height is scaled
			// first apply the scale first 
			float Radius = FMath::Max(SphylElem.Radius * ScaleRadius, 0.1f);
			float Length = SphylElem.Length + SphylElem.Radius * 2.f;
			float HalfLength = Length * ScaleLength * 0.5f;
			Radius = FMath::Clamp(Radius, 0.1f, HalfLength);	//radius is capped by half length
			float HalfHeight = HalfLength - Radius;
			HalfHeight = FMath::Max(0.1f, HalfHeight);

			PxCapsuleGeometry PCapsuleGeom;
			PCapsuleGeom.halfHeight = HalfHeight;
			PCapsuleGeom.radius = Radius;

			if (PCapsuleGeom.isValid())
			{
				// The stored sphyl transform assumes the sphyl axis is down Z. In PhysX, it points down X, so we twiddle the matrix a bit here (swap X and Z and negate Y).
				PxTransform PLocalPose(U2PVector(RelativeTM.TransformPosition(SphylElem.Center)), U2PQuat(SphylElem.Orientation) * U2PSphylBasis);
				PLocalPose.p.x *= Scale3D.X;
				PLocalPose.p.y *= Scale3D.Y;
				PLocalPose.p.z *= Scale3D.Z;

				ensure(PLocalPose.isValid());
				{
					const float ContactOffset = FMath::Min(MaxContactOffset, ContactOffsetFactor * PCapsuleGeom.radius);
					AttachShape_AssumesLocked(PCapsuleGeom, PLocalPose, ContactOffset);
				}
			}
			else
			{
				UE_LOG(LogPhysics, Warning, TEXT("AddSphylsToRigidActor: [%s] SphylElems[%d] invalid"), *GetPathNameSafe(BodySetup->GetOuter()), i);
			}
		}
	}
Esempio n. 4
0
	void AddBoxesToRigidActor_AssumesLocked() const
	{
		float ContactOffsetFactor, MaxContactOffset;
		GetContactOffsetParams(ContactOffsetFactor, MaxContactOffset);

		for (int32 i = 0; i < BodySetup->AggGeom.BoxElems.Num(); i++)
		{
			const FKBoxElem& BoxElem = BodySetup->AggGeom.BoxElems[i];

			PxBoxGeometry PBoxGeom;
			PBoxGeom.halfExtents.x = (0.5f * BoxElem.X * Scale3DAbs.X);
			PBoxGeom.halfExtents.y = (0.5f * BoxElem.Y * Scale3DAbs.Y);
			PBoxGeom.halfExtents.z = (0.5f * BoxElem.Z * Scale3DAbs.Z);

			FTransform BoxTransform = BoxElem.GetTransform() * RelativeTM;
			if (PBoxGeom.isValid() && BoxTransform.IsValid())
			{
				PxTransform PLocalPose(U2PTransform(BoxTransform));
				PLocalPose.p.x *= Scale3D.X;
				PLocalPose.p.y *= Scale3D.Y;
				PLocalPose.p.z *= Scale3D.Z;

				ensure(PLocalPose.isValid());
				{
					const float ContactOffset = FMath::Min(MaxContactOffset, ContactOffsetFactor * PBoxGeom.halfExtents.minElement());
					AttachShape_AssumesLocked(PBoxGeom, PLocalPose, ContactOffset);
				}
			}
			else
			{
				UE_LOG(LogPhysics, Warning, TEXT("AddBoxesToRigidActor: [%s] BoxElems[%d] invalid or has invalid transform"), *GetPathNameSafe(BodySetup->GetOuter()), i);
			}
		}
	}
Esempio n. 5
0
	void AddSpheresToRigidActor_AssumesLocked() const
	{
		float ContactOffsetFactor, MaxContactOffset;
		GetContactOffsetParams(ContactOffsetFactor, MaxContactOffset);

		for (int32 i = 0; i < BodySetup->AggGeom.SphereElems.Num(); i++)
		{
			const FKSphereElem& SphereElem = BodySetup->AggGeom.SphereElems[i];

			PxSphereGeometry PSphereGeom;
			PSphereGeom.radius = (SphereElem.Radius * MinScaleAbs);

			if (ensure(PSphereGeom.isValid()))
			{
				FVector LocalOrigin = RelativeTM.TransformPosition(SphereElem.Center);
				PxTransform PLocalPose(U2PVector(LocalOrigin));
				PLocalPose.p *= MinScale;

				ensure(PLocalPose.isValid());
				{
					const float ContactOffset = FMath::Min(MaxContactOffset, ContactOffsetFactor * PSphereGeom.radius);
					AttachShape_AssumesLocked(PSphereGeom, PLocalPose, ContactOffset);
				}
			}
			else
			{
				UE_LOG(LogPhysics, Warning, TEXT("AddSpheresToRigidActor: [%s] SphereElem[%d] invalid"), *GetPathNameSafe(BodySetup->GetOuter()), i);
			}
		}
	}
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;
}
Esempio n. 7
0
	void AddTriMeshToRigidActor_AssumesLocked() const
	{
		float ContactOffsetFactor, MaxContactOffset;
		GetContactOffsetParams(ContactOffsetFactor, MaxContactOffset);

		if (BodySetup->TriMesh || BodySetup->TriMeshNegX)
		{
			PxTransform PLocalPose;
			bool bUseNegX = CalcMeshNegScaleCompensation(Scale3D, PLocalPose);

			// Only case where TriMeshNegX should be null is BSP, which should not require negX version
			if (bUseNegX && BodySetup->TriMeshNegX == NULL)
			{
				UE_LOG(LogPhysics, Log, TEXT("AddTriMeshToRigidActor: Want to use NegX but it doesn't exist! %s"), *BodySetup->GetPathName());
			}

			PxTriangleMesh* UseTriMesh = bUseNegX ? BodySetup->TriMeshNegX : BodySetup->TriMesh;
			if (UseTriMesh != NULL)
			{
				PxTriangleMeshGeometry PTriMeshGeom;
				PTriMeshGeom.triangleMesh = bUseNegX ? BodySetup->TriMeshNegX : BodySetup->TriMesh;
				PTriMeshGeom.scale.scale = U2PVector(Scale3DAbs);
				if (BodySetup->bDoubleSidedGeometry)
				{
					PTriMeshGeom.meshFlags |= PxMeshGeometryFlag::eDOUBLE_SIDED;
				}


				if (PTriMeshGeom.isValid())
				{
					ensure(PLocalPose.isValid());

					// Create without 'sim shape' flag, problematic if it's kinematic, and it gets set later anyway.
					{
						if (!AttachShape_AssumesLocked(PTriMeshGeom, PLocalPose, MaxContactOffset, PxShapeFlag::eSCENE_QUERY_SHAPE | PxShapeFlag::eVISUALIZATION))
						{
							UE_LOG(LogPhysics, Log, TEXT("Can't create new mesh shape in AddShapesToRigidActor"));
						}
					}
				}
				else
				{
					UE_LOG(LogPhysics, Log, TEXT("AddTriMeshToRigidActor: TriMesh invalid"));
				}
			}
		}
	}