Announcement

Collapse
No announcement yet.

Custom Mesh Physics

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Custom Mesh Physics

    I want to create custom mesh's with their own Physics. I've been trying to do this for a long time now.
    My main problem here is that if I attached this object to the custom mesh, the mesh just dissapears when the physics starts..
    You can recreate this problem if you use this line in your custom mesh code:
    CustomMesh->SetSimulatePhysics(true);
    It'd be nice for the custom mesh tutorial to include physics, if anyone wants to do this.
    Has anyone solved this problem? I don't fully understand how unreal manages these things. I'm only a one man team, and only have the forums to consult. Please help me senpai's.

    Success in Voxel Smooth Terrain:
    Click image for larger version

Name:	10873013_911396465539044_8844958817588369169_o.jpg
Views:	1
Size:	47.9 KB
ID:	1142299

    As you can tell, the custom physics works well with static mesh's attached. So I may research into them instead of the custom mesh' code on the forum that extends UMeshComponent. But I heard that the latter, had alot of performance increases over static meshes.
    Succeess in custom physics:
    Click image for larger version

Name:	10344090_912414745437216_271765640058133907_o.jpg
Views:	1
Size:	120.9 KB
ID:	1142300

    First I copied the UBoxComponent code and made my own class for custom physics:

    Code:
    class TESTTERRAIN_API UTestCustomPhysics : public UShapeComponent {
    Then I created a bunch of Triangle Data in the header:
    Code:
    	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Shape)
    	TArray<FGenerateMeshTriangle> Triangles;
    Then I changed the UpdateBodySetup, from using the BoxElem to the ConvexElem.

    Code:
    // Fill out your copyright notice in the Description page of Project Settings.
    
    #pragma once
    
    #include "GameFramework/Actor.h"
    #include "Components/ShapeComponent.h"
    #include "GenerateMesh.h"
    #include "TestCustomPhysics.generated.h"
    
    
    UCLASS(ClassGroup = Shapes, editinlinenew, hidecategories = (Object, LOD, Lighting, TextureStreaming), meta = (BlueprintSpawnableComponent))
    class TESTTERRAIN_API UTestCustomPhysics : public UShapeComponent {
    	GENERATED_UCLASS_BODY()
    public:
    	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Shape)
    	TArray<FGenerateMeshTriangle> Triangles;
    	//UPROPERTY(BlueprintCallable, Category = Shape)
    	void AddCustomBox(FVector Size, FVector Position);
    	//UPROPERTY(BlueprintCallable, Category = Shape)
    		void AddCustomBox();
    
    	virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) OVERRIDE;
    		UPROPERTY(EditAnywhere, BlueprintReadOnly, export, Category = Shape)
    			FVector Size;
    		UPROPERTY(EditAnywhere, BlueprintReadOnly, export, Category = Shape)
    			FVector Offset;
    
    	// Begin UPrimitiveComponent interface.
    	virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
    	virtual bool IsZeroExtent() const override;
    	virtual struct FCollisionShape GetCollisionShape(float Inflation = 0.0f) const override;
    	//virtual bool AreSymmetricRotations(const FQuat& A, const FQuat& B, const FVector& Scale3D) const override;
    	// End UPrimitiveComponent interface.
    
    	// Begin USceneComponent interface
    	virtual FBoxSphereBounds CalcBounds(const FTransform & LocalToWorld) const override;
    	//virtual void CalcBoundingCylinder(float& CylinderRadius, float& CylinderHalfHeight) const override;
    	// End USceneComponent interface
    
    	// Begin UShapeComponent interface
    	virtual void UpdateBodySetup() override;
    	// End UShapeComponent interface
    };
    Code:
    #include "TestTerrain.h"
    #include "Engine.h"
    #include "DynamicMeshBuilder.h"
    #include "TestCustomPhysics.h"
    
    // Vertex Buffer
    class FGeneratedMeshVertexBuffer : public FVertexBuffer {
    public:
    	TArray<FDynamicMeshVertex> Vertices;
    
    	virtual void InitRHI() 	{
    
    		//#if ENGINE_MAJOR_VERSION >= 4 && ENGINE_MINOR_VERSION >= 3
    		FRHIResourceCreateInfo CreateInfo;
    		VertexBufferRHI = RHICreateVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), BUF_Static, CreateInfo);
    		//#else
    		//		VertexBufferRHI = RHICreateVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), NULL, BUF_Static);
    		//#endif
    		// Copy the vertex data into the vertex buffer.
    		void* VertexBufferData = RHILockVertexBuffer(VertexBufferRHI, 0, Vertices.Num() * sizeof(FDynamicMeshVertex), RLM_WriteOnly);
    		FMemory::Memcpy(VertexBufferData, Vertices.GetTypedData(), Vertices.Num() * sizeof(FDynamicMeshVertex));
    		RHIUnlockVertexBuffer(VertexBufferRHI);
    	}
    };
    
    // Index Buffer
    class FGeneratedMeshIndexBuffer : public FIndexBuffer
    {
    public:
    	TArray<int32> Indices;
    
    	virtual void InitRHI()	{
    		//#if ENGINE_MAJOR_VERSION >= 4 && ENGINE_MINOR_VERSION >= 3
    		FRHIResourceCreateInfo CreateInfo;
    		IndexBufferRHI = RHICreateIndexBuffer(sizeof(int32), Indices.Num() * sizeof(int32), BUF_Static, CreateInfo);
    		//#else
    		//		IndexBufferRHI = RHICreateIndexBuffer(sizeof(int32), Indices.Num() * sizeof(int32), NULL, BUF_Static);
    		//#endif
    		// Write the indices to the index buffer.
    		void* Buffer = RHILockIndexBuffer(IndexBufferRHI, 0, Indices.Num() * sizeof(int32), RLM_WriteOnly);
    		FMemory::Memcpy(Buffer, Indices.GetTypedData(), Indices.Num() * sizeof(int32));
    		RHIUnlockIndexBuffer(IndexBufferRHI);
    	}
    };
    
    // Vertex Factory
    class FGeneratedMeshVertexFactory : public FLocalVertexFactory {
    public:
    	FGeneratedMeshVertexFactory()
    	{}
    
    
    	// Initialization
    	void Init(const FGeneratedMeshVertexBuffer* VertexBuffer) 	{
    		check(!IsInRenderingThread());
    
    		ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
    			InitGeneratedMeshVertexFactory,
    			FGeneratedMeshVertexFactory*, VertexFactory, this,
    			const FGeneratedMeshVertexBuffer*, VertexBuffer, VertexBuffer,
    			{
    			// Initialize the vertex factory's stream components.
    			DataType NewData;
    			NewData.PositionComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, Position, VET_Float3);
    			NewData.TextureCoordinates.Add(
    				FVertexStreamComponent(VertexBuffer, STRUCT_OFFSET(FDynamicMeshVertex, TextureCoordinate), sizeof(FDynamicMeshVertex), VET_Float2)
    				);
    			NewData.TangentBasisComponents[0] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, TangentX, VET_PackedNormal);
    			NewData.TangentBasisComponents[1] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, TangentZ, VET_PackedNormal);
    			NewData.ColorComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, Color, VET_Color);
    			VertexFactory->SetData(NewData);
    		});
    	}
    };
    
    void UTestCustomPhysics::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) {
    
    	AddCustomBox();
    	Super::PostEditChangeProperty(PropertyChangedEvent);
    }
    UTestCustomPhysics::UTestCustomPhysics(const class FPostConstructInitializeProperties& PCIP)
    : Super(PCIP)
    {
    	//SphereRadius = 130;
    	Size = FVector(500, 500, 500);
    	ShapeColor = FColor(255, 0, 0, 255);
    	AddCustomBox();
    
    	//bUseEditorCompositing = true;
    }
    
    void UTestCustomPhysics::AddCustomBox() {
    	AddCustomBox(Size, Offset);
    }
    
    void UTestCustomPhysics::AddCustomBox(FVector Size, FVector Position) {
    	// make vertex positions
    	FVector p0 = FVector(Position.X, Position.Y, Position.Z);
    	FVector p1 = FVector(Position.X, Position.Y, Position.Z + Size.Z);
    	FVector p2 = FVector(Position.X + Size.X, Position.Y, Position.Z + Size.Z);
    	FVector p3 = FVector(Position.X + Size.X, Position.Y, Position.Z);
    	FVector p4 = FVector(Position.X + Size.X, Position.Y + Size.Y, Position.Z);
    	FVector p5 = FVector(Position.X + Size.X, Position.Y + Size.Y, Position.Z + Size.Z);
    	FVector p6 = FVector(Position.X, Position.Y + Size.Y, Position.Z + Size.Z);
    	FVector p7 = FVector(Position.X, Position.Y + Size.Y, Position.Z);
    
    	// Verticies used in the triangles
    	FGenerateMeshTriangleVertex v0;
    	FGenerateMeshTriangleVertex v1;
    	FGenerateMeshTriangleVertex v2;
    	FGenerateMeshTriangleVertex v3;
    	v0.U = 0; v0.V = 0;
    	v1.U = 0; v1.V = .5;
    	v2.U = .5; v2.V = .5;
    	v3.U = .5; v3.V = 0;
    	float LightRed = 1;
    	float LightGreen = 1;
    	float LightBlue = 1;
    	v0.Color = FColor(LightRed, LightGreen, LightBlue, 255);
    	v1.Color = FColor(LightRed, LightGreen, LightBlue, 255);
    	v2.Color = FColor(LightRed, LightGreen, LightBlue, 255);
    	v3.Color = FColor(LightRed, LightGreen, LightBlue, 255);
    	v0.U = 0; v0.V = 0;
    	v1.U = 0; v1.V = 0 + 1;
    	v2.U = 0 + 1; v2.V = 0 + 1;
    	v3.U = 0 + 1; v3.V = 0;
    	FGenerateMeshTriangle t1;
    	FGenerateMeshTriangle t2;
    
    	// front face
    	v0.Position = p0;
    	v1.Position = p1;
    	v2.Position = p2;
    	v3.Position = p3;
    	t1.Vertex0 = v0;
    	t1.Vertex1 = v1;
    	t1.Vertex2 = v2;
    	t2.Vertex0 = v0;
    	t2.Vertex1 = v2;
    	t2.Vertex2 = v3;
    	Triangles.Add(t1);
    	Triangles.Add(t2);
    
    	//back face
    	v0.Position = p4;
    	v1.Position = p5;
    	v2.Position = p6;
    	v3.Position = p7;
    	t1.Vertex0 = v0;
    	t1.Vertex1 = v1;
    	t1.Vertex2 = v2;
    	t2.Vertex0 = v0;
    	t2.Vertex1 = v2;
    	t2.Vertex2 = v3;
    	Triangles.Add(t1);
    	Triangles.Add(t2);
    
    	// left face
    	v0.Position = p7;
    	v1.Position = p6;
    	v2.Position = p1;
    	v3.Position = p0;
    	t1.Vertex0 = v0;
    	t1.Vertex1 = v1;
    	t1.Vertex2 = v2;
    	t2.Vertex0 = v0;
    	t2.Vertex1 = v2;
    	t2.Vertex2 = v3;
    	Triangles.Add(t1);
    	Triangles.Add(t2);
    
    	// right face
    	v0.Position = p3;
    	v1.Position = p2;
    	v2.Position = p5;
    	v3.Position = p4;
    	t1.Vertex0 = v0;
    	t1.Vertex1 = v1;
    	t1.Vertex2 = v2;
    	t2.Vertex0 = v0;
    	t2.Vertex1 = v2;
    	t2.Vertex2 = v3;
    	Triangles.Add(t1);
    	Triangles.Add(t2);
    
    	// top face
    	v0.Position = p1;
    	v1.Position = p6;
    	v2.Position = p5;
    	v3.Position = p2;
    	t1.Vertex0 = v0;
    	t1.Vertex1 = v1;
    	t1.Vertex2 = v2;
    	t2.Vertex0 = v0;
    	t2.Vertex1 = v2;
    	t2.Vertex2 = v3;
    	Triangles.Add(t1);
    	Triangles.Add(t2);
    
    	// bottom face
    	v0.Position = p3;
    	v1.Position = p4;
    	v2.Position = p7;
    	v3.Position = p0;
    	t1.Vertex0 = v0;
    	t1.Vertex1 = v1;
    	t1.Vertex2 = v2;
    	t2.Vertex0 = v0;
    	t2.Vertex1 = v2;
    	t2.Vertex2 = v3;
    	Triangles.Add(t1);
    	Triangles.Add(t2);
    }
    
    FBoxSphereBounds UTestCustomPhysics::CalcBounds(const FTransform & LocalToWorld) const {
    	return FBoxSphereBounds(FBox(-Size, Size).TransformBy(LocalToWorld));
    }
    
    void UTestCustomPhysics::UpdateBodySetup() {
    	if (ShapeBodySetup == NULL || ShapeBodySetup->IsPendingKill())
    	{
    		ShapeBodySetup = ConstructObject<UBodySetup>(UBodySetup::StaticClass(), this);
    		ShapeBodySetup->CollisionTraceFlag = CTF_UseSimpleAsComplex;
    		ShapeBodySetup->AggGeom.ConvexElems.Add(FKConvexElem());
    	}
    	FKConvexElem* convex = ShapeBodySetup->AggGeom.ConvexElems.GetTypedData();
    	for (int32 i = convex->VertexData.Num() - 1; i > -1; i--) {
    		convex->VertexData.RemoveAt(i);
    	}
    	for (int32 i = 0; i < Triangles.Num(); i++) {
    		convex->VertexData.Add(Triangles[i].Vertex0.Position);
    		convex->VertexData.Add(Triangles[i].Vertex1.Position);
    		convex->VertexData.Add(Triangles[i].Vertex2.Position);
    	}
    }
    
    /*void UTestCustomPhysics::SetSphereRadius(float InSphereRadius, bool bUpdateOverlaps)
    {
    	//SphereRadius = InSphereRadius;
    	MarkRenderStateDirty();
    
    	if (bPhysicsStateCreated)
    	{
    		DestroyPhysicsState();
    		UpdateBodySetup();
    		CreatePhysicsState();
    
    		if (bUpdateOverlaps && IsCollisionEnabled() && GetOwner())
    		{
    			UpdateOverlaps();
    		}
    	}
    }*/
    
    bool UTestCustomPhysics::IsZeroExtent() const
    {
    	return (Size.X == 0 && Size.Y == 0 && Size.Z == 0);
    }
    
    
    FPrimitiveSceneProxy* UTestCustomPhysics::CreateSceneProxy() {
    	/** Represents a DrawLightRadiusComponent to the scene manager. */
    	class FSphereSceneProxy : public FPrimitiveSceneProxy {
    	private:
    		const uint32				bDrawOnlyIfSelected : 1;
    		const FColor				SphereColor;
    		const UMaterialInterface*	ShapeMaterial;
    		const FVector Size;
    
    		UMaterialInterface* Material;
    		FGeneratedMeshVertexBuffer VertexBuffer;
    		FGeneratedMeshIndexBuffer IndexBuffer;
    		FGeneratedMeshVertexFactory VertexFactory;
    		FMaterialRelevance MaterialRelevance;
    	public:
    
    		/** Initialization constructor. */
    		FSphereSceneProxy(const UTestCustomPhysics* InComponent)
    			: FPrimitiveSceneProxy(InComponent)
    			, bDrawOnlyIfSelected(InComponent->bDrawOnlyIfSelected)
    			, SphereColor(InComponent->ShapeColor)
    			, ShapeMaterial(InComponent->ShapeMaterial)
    			, Size(InComponent->Size)
    		{
    			for (int32 i = 0; i < InComponent->Triangles.Num(); i++) {
    				const FGenerateMeshTriangle& Tri = InComponent->Triangles[i];
    
    					FDynamicMeshVertex Vert0;
    					Vert0.Position = Tri.Vertex0.Position;
    					Vert0.Color = Tri.Vertex0.Color;
    					//Vert0.SetTangents(TangentX, TangentY, TangentZ);
    					Vert0.SetTangents(Tri.Vertex0.Normal, Tri.Vertex1.Normal, Tri.Vertex2.Normal);
    					Vert0.TextureCoordinate.Set(Tri.Vertex0.U, Tri.Vertex0.V);
    					int32 VIndex = VertexBuffer.Vertices.Add(Vert0);
    					IndexBuffer.Indices.Add(VIndex);
    					// new stuff
    
    					FDynamicMeshVertex Vert1;
    					Vert1.Position = Tri.Vertex1.Position;
    					Vert1.Color = Tri.Vertex1.Color;
    					//Vert1.SetTangents(TangentX, TangentY, TangentZ);
    					Vert1.SetTangents(Tri.Vertex0.Normal, Tri.Vertex1.Normal, Tri.Vertex2.Normal);
    					Vert1.TextureCoordinate.Set(Tri.Vertex1.U, Tri.Vertex1.V);
    					VIndex = VertexBuffer.Vertices.Add(Vert1);
    					IndexBuffer.Indices.Add(VIndex);
    
    					FDynamicMeshVertex Vert2;
    					Vert2.Position = Tri.Vertex2.Position;
    					Vert2.Color = Tri.Vertex2.Color;
    					//Vert2.SetTangents(TangentX, TangentY, TangentZ);
    					Vert2.SetTangents(Tri.Vertex0.Normal, Tri.Vertex1.Normal, Tri.Vertex2.Normal);
    					Vert2.TextureCoordinate.Set(Tri.Vertex2.U, Tri.Vertex2.V);
    					VIndex = VertexBuffer.Vertices.Add(Vert2);
    					IndexBuffer.Indices.Add(VIndex);
    				}
    
    				// Init vertex factory
    				VertexFactory.Init(&VertexBuffer);
    
    				// Enqueue initialization of render resource
    				BeginInitResource(&VertexBuffer);
    				BeginInitResource(&IndexBuffer);
    				BeginInitResource(&VertexFactory);
    
    				// Grab material
    				Material = InComponent->GetMaterial(0);
    				if (Material == NULL) 			{
    					Material = UMaterial::GetDefaultMaterial(MD_Surface);
    				}
    			bWillEverBeLit = false;
    		}
    		virtual ~FSphereSceneProxy() 		{
    			VertexBuffer.ReleaseResource();
    			IndexBuffer.ReleaseResource();
    			VertexFactory.ReleaseResource();
    		}
    		// this is where the actual rendering is done
    		/*virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override
    		{
    			QUICK_SCOPE_CYCLE_COUNTER(STAT_BoxSceneProxy_GetDynamicMeshElements);
    
    			const FMatrix& LocalToWorld = GetLocalToWorld();
    			const FColor DrawColor = GetSelectionColor(SphereColor, IsSelected(), IsHovered(), false);
    
    			for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
    			{
    				if (VisibilityMap & (1 << ViewIndex))
    				{
    					FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);
    					DrawOrientedWireBox(PDI, LocalToWorld.GetOrigin(), LocalToWorld.GetScaledAxis(EAxis::X), LocalToWorld.GetScaledAxis(EAxis::Y), LocalToWorld.GetScaledAxis(EAxis::Z), Size, DrawColor, SDPG_World);
    				}
    			}
    		}*/
    
    		virtual void DrawDynamicElements(FPrimitiveDrawInterface* PDI, const FSceneView* View) override
    		{
    			/*QUICK_SCOPE_CYCLE_COUNTER(STAT_BoxSceneProxy_DrawDynamicElements);
    
    			const FMatrix& LocalToWorld = GetLocalToWorld();
    			const FColor DrawColor = GetSelectionColor(SphereColor, IsSelected(), IsHovered(), false);
    			DrawOrientedWireBox(PDI, LocalToWorld.GetOrigin(), LocalToWorld.GetScaledAxis(EAxis::X), LocalToWorld.GetScaledAxis(EAxis::Y), LocalToWorld.GetScaledAxis(EAxis::Z), Size, DrawColor, SDPG_World);*/
    
    			QUICK_SCOPE_CYCLE_COUNTER(STAT_GeneratedMeshSceneProxy_DrawDynamicElements);
    
    			const bool bWireframe = View->Family->EngineShowFlags.Wireframe;
    
    			FColoredMaterialRenderProxy WireframeMaterialInstance(
    				WITH_EDITOR ? GEngine->WireframeMaterial->GetRenderProxy(IsSelected()) : NULL,
    				//GEngine->WireframeMaterial->GetRenderProxy(IsSelected()),
    				//FLinearColor(0, 0.5f, 1.f)
    				FLinearColor(1.0f, 0.0f, 0.f)
    				);
    
    			FMaterialRenderProxy* MaterialProxy = NULL;
    			if (bWireframe)
    			{
    				MaterialProxy = &WireframeMaterialInstance;
    			}
    			else
    			{
    				MaterialProxy = Material->GetRenderProxy(IsSelected());
    			}
    
    			// Draw the mesh.
    			FMeshBatch Mesh;
    			FMeshBatchElement& BatchElement = Mesh.Elements[0];
    			Mesh.bWireframe = bWireframe;
    			Mesh.VertexFactory = &VertexFactory;
    			Mesh.MaterialRenderProxy = MaterialProxy;
    			Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative();
    			Mesh.Type = PT_TriangleList;
    			Mesh.DepthPriorityGroup = SDPG_World;
    			Mesh.CastShadow = true;
    
    			BatchElement.IndexBuffer = &IndexBuffer;
    			BatchElement.FirstIndex = 0;
    			BatchElement.NumPrimitives = IndexBuffer.Indices.Num() / 3;
    			BatchElement.MinVertexIndex = 0;
    			//BatchElement.MaxVertexIndex = VertexBuffer.Vertices.Num() - 1;
    			//BatchElement.PrimitiveUniformBuffer = CreatePrimitiveUniformBufferImmediate(GetLocalToWorld(), GetBounds(), GetLocalBounds(), true);
    			BatchElement.PrimitiveUniformBuffer = CreatePrimitiveUniformBufferImmediate(GetLocalToWorld(), GetBounds(), GetLocalBounds(), true, true);
    			PDI->DrawMesh(Mesh);
    		}
    
    		virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View)  override {
    			FPrimitiveViewRelevance Result;
    			Result.bDrawRelevance = IsShown(View);
    			Result.bShadowRelevance = IsShadowCast(View);
    			Result.bDynamicRelevance = true;
    			MaterialRelevance.SetPrimitiveViewRelevance(Result);
    			return Result;
    		}
    
    		virtual bool CanBeOccluded() const OVERRIDE
    		{
    			return !MaterialRelevance.bDisableDepthTest;
    		}
    		virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
    		uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
    	};
    
    	return new FSphereSceneProxy(this);
    }
    
    
    FCollisionShape UTestCustomPhysics::GetCollisionShape(float Inflation) const {
    	//if (IsBox) {
    		FVector Extent = Size + Inflation;
    		if (Inflation < 0.f)
    		{
    			// Don't shrink below zero size.
    			Extent = Extent.ComponentMax(FVector::ZeroVector);
    		}
    
    		return FCollisionShape::MakeBox(Extent);
    }
    Attached Files

    #2
    Ahh wow I fixed this pretty quick. The harder part was mainly the bit I did in the above code.
    First I create an object. Then I add the normal custom mesh to it. However I don't set it as a root, and I turn all collisions off.
    Next I add the Custom Physics Object to it, and set it as the root. Then when updating the mesh, I update the physics object too.
    The key part was setting the Render Mesh to the location/rotation of the actor in the tick cycle!

    It's more of a hack, but it works. If anyone has any idea how to create a singular object, with both rendering and physics, let me know. Pretty sure it's to due with UShapeComponent only rendering in wireframe mode. I tried to turn it off but failed. I think if I delved into shape component's code i would figure it all out.

    Comment


      #3
      I still have a problem. The convex mesh doesn't work (the collisionss don't work on the mesh) when i use this line:
      ShapeBodySetup->CollisionTraceFlag = ECollisionTraceFlag::CTF_UseComplexAsSimple;
      and if i use:
      ShapeBodySetup->CollisionTraceFlag = ECollisionTraceFlag::CTF_UseSimpleAsComplex;
      It simplifies all the triangle data. So the collisions with the mesh are too simple. If any one knows a way around this, please let me know.

      Comment

      Working...
      X