Hi all,
I am new to UE4 and this community. I made some brief searches beforehand and couldn’t find anything that answered my questions. I did spend more than a few hours searching online. Basically I have a static mesh (default UE4 cube) and I can successfully retrieve its vertices and indices. My goal is to be able to modify the mesh by removing/adding vertices at runtime. I know about the UProceduralMeshComponent but I saw that it is experimental and usually used to build a mesh from scratch, so I haven’t gone that way.
I have several issues:
- One of the problems is that after calling Init() on the PositionVertexBuffer the number of vertices doubles (e.g. 24 -> 48), instead of just refreshing.
- I also change the IndexBuffer with SetIndices() - in terms of index count it seems to work, but the change somehow persists between PIE instances until I decide to restart the editor.
- Nothing changes visually - I don’t see anything extra from the double vertices and I don’t see a missing face on the cube (removing the last 3 indices that form a face).
What am I doing wrong?
Here’s the code:
/get the mesh component(s)
_actor->GetComponents<UStaticMeshComponent>(Components);
for (int32 i = 0; i<Components.Num(); i++)
{
UStaticMeshComponent* StaticMeshComponent = Components*;
UStaticMesh* StaticMesh = StaticMeshComponent->StaticMesh;
}
//containers
TArray<FVector> vertices = TArray<FVector>();
TArray<uint32> indices = TArray<uint32>();
FStaticMeshVertexBuffer* VertexBuffer = &Components[0]->StaticMesh->RenderData->LODResources[0].VertexBuffer;
FPositionVertexBuffer* PositionVertexBuffer = &Components[0]->StaticMesh->RenderData->LODResources[0].PositionVertexBuffer;
FRawStaticIndexBuffer* IndexBuffer = &Components[0]->StaticMesh->RenderData->LODResources[0].IndexBuffer;
if (PositionVertexBuffer)
{
const int32 VertexCount = PositionVertexBuffer->GetNumVertices();
for (int32 Index = 0; Index < VertexCount; Index++)
{
//const FVector WorldSpaceVertexLocation = _actor->GetActorLocation() + _actor->GetTransform().TransformVector(PositionVertexBuffer->VertexPosition(Index));
//vertices.Add(WorldSpaceVertexLocation);
//if I get the vertices in world space and then feed the array list back, in addition to doubling the vertices all the walls and the cube change their position
vertices.Add(PositionVertexBuffer->VertexPosition(Index));
}
}
if (IndexBuffer)
{
IndexBuffer->GetCopy(indices);
}
TArray<uint32> newIndices;
count = indices.Num();
for (int32 Index = 0; Index < count - 3; Index++) //remove one face
{
newIndices.Add(indices[Index]);
}
Components[0]->StaticMesh->RenderData->LODResources[0].IndexBuffer.SetIndices(newIndices, EIndexBufferStride::AutoDetect);
TArray<FStaticMeshBuildVertex> newVertexList;
if (PositionVertexBuffer)
{
const int32 VertexCount = PositionVertexBuffer->GetNumVertices();
for (int32 Index = 0; Index < VertexCount; Index++)
{
FStaticMeshBuildVertex tempVertex;
tempVertex.Color = FColor::White;
tempVertex.Position = vertices[Index];
tempVertex.TangentX = VertexBuffer->VertexTangentX(Index);
tempVertex.TangentY = VertexBuffer->VertexTangentY(Index);
tempVertex.TangentZ = VertexBuffer->VertexTangentZ(Index);
tempVertex.UVs[0] = VertexBuffer->GetVertexUV(Index, 0);
newVertexList.Add(tempVertex);
}
}
Components[0]->StaticMesh->RenderData->LODResources[0].PositionVertexBuffer.Init(newVertexList);
RunAsyncTask(ENamedThreads::RenderThread, [this]()
{
Components[0]->StaticMesh->RenderData->LODResources[0].PositionVertexBuffer.InitRHI();
});
Here’s the RunAsyncTask function (got it from https://github.com/Temaran/UE4RenderDocPlugin/blob/master/RenderDocPlugin/Source/RenderDocPlugin/Private/RenderDocPluginModule.cpp):
Header File:
static void RunAsyncTask(ENamedThreads::Type Where, TFunction<void()> What);
Cpp File:
void UModelCutting::RunAsyncTask(ENamedThreads::Type Where, TFunction<void()> What)
{
struct FAsyncGraphTask : public FAsyncGraphTaskBase
{
ENamedThreads::Type TargetThread;
TFunction<void()> TheTask;
FAsyncGraphTask(ENamedThreads::Type Thread, TFunction<void()>&& Task) : TargetThread(Thread), TheTask(MoveTemp(Task)) { }
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) { TheTask(); }
ENamedThreads::Type GetDesiredThread() { return(TargetThread); }
};
TGraphTask<FAsyncGraphTask>::CreateTask().ConstructAndDispatchWhenReady(Where, MoveTemp(What));
}
Thank you in advance for your help.