英文:
UStaticMeshComponent::SetStaticMesh() crash; how to create a static mesh from raw mesh data in UE5?
问题
I am trying to create a static mesh from a raw mesh data (vertex + index buffer) at runtime. First, I was able to successfully create a static sphere mesh (using StaticLoadObject
to load "/Engine/BasicShapes/Sphere") and to assign the same material (as returned by AMyActor::CreateMaterial
below). Then, instead of the sphere mesh, I want to create my vertex and index data at runtime. With information I found around, I wrote the following code:
UStaticMeshComponent* AMyActor::CreateMesh(AActor* ActorOwner, FLinearColor Color)
{
UStaticMesh* StaticMesh = NewObject<UStaticMesh>();
StaticMesh->AddSourceModel();
FStaticMeshSourceModel& SourceModel = StaticMesh->GetSourceModel(0);
//SourceModel.RawMeshBulkData->SaveRawMesh(RawMesh);
StaticMesh->Build(false);
UStaticMeshComponent* Mesh = NewObject<UStaticMeshComponent>(ActorOwner);
UE_LOG(LogTemp, Warning, TEXT("Calling Mesh->SetStaticMesh(%x)..."), (void*)StaticMesh);
// crashes here:
Mesh->SetStaticMesh(StaticMesh);
Mesh->SetMaterial(0, CreateMaterial(Color));
Mesh->SetCollisionProfileName(TEXT("Pawn"));
Mesh->SetHiddenInGame(false);
Mesh->RegisterComponent();
return Mesh;
}
UMaterialInstanceDynamic* AMyActor::CreateMaterial(FLinearColor Color)
{
FStringAssetReference MaterialRef(TEXT("/Game/SimBlank/Materials/GlossyRedMaterial"));
UMaterialInterface* LoadedMaterial = Cast<UMaterialInterface>(StaticLoadObject(UMaterialInterface::StaticClass(), nullptr, *MaterialRef.ToString()));
UMaterialInstanceDynamic* NewMaterial = UMaterialInstanceDynamic::Create(LoadedMaterial, this);
NewMaterial->SetVectorParameterValue("BaseColor", Color);
return NewMaterial;
}
The above code crashes at Mesh->SetStaticMesh(StaticMesh);
. Before crashing it prints:
Assertion failed: (Index >= 0) & (Index < ArrayNum) [File:D:\build++UE5\Sync\Engine\Source\Runtime\Core\Public\Containers\Array.h] [Line: 752] Array index out of bounds: 0 from an array of size 0
To make a simpler test, I removed the part where I create the FRawMesh
and also the call to SourceModel.RawMeshBulkData->SaveRawMesh(RawMesh)
, however, it crashes in the same way, with the same assertion failed message. Code:
UStaticMeshComponent* AMyActor::CreateMesh(AActor* ActorOwner, FLinearColor Color)
{
UStaticMesh* StaticMesh = NewObject<UStaticMesh>();
StaticMesh->AddSourceModel();
FStaticMeshSourceModel& SourceModel = StaticMesh->GetSourceModel(0);
//SourceModel.RawMeshBulkData->SaveRawMesh(RawMesh);
StaticMesh->Build(false);
UStaticMeshComponent* Mesh = NewObject<UStaticMeshComponent>(ActorOwner);
UE_LOG(LogTemp, Warning, TEXT("Calling Mesh->SetStaticMesh(%x)..."), (void*)StaticMesh);
// crashes here:
Mesh->SetStaticMesh(StaticMesh);
Mesh->SetMaterial(0, CreateMaterial(Color));
Mesh->SetCollisionProfileName(TEXT("Pawn"));
Mesh->SetHiddenInGame(false);
Mesh->RegisterComponent();
return Mesh;
}
What's the correct way to create a static mesh from raw mesh data?
英文:
I am trying to create a static mesh from a raw mesh data (vertex + index buffer) at runtime.
First, I was able to successfully create a static sphere mesh (using StaticLoadObject
to load "/Engine/BasicShapes/Sphere") and to assign the same material (as returned by AMyActor::CreateMaterial
below).
Then, instead of the sphere mesh, I want to create my vertex and index data at runtime.
With information I found around, I wrote the following code:
UStaticMeshComponent* AMyActor::CreateMesh(AActor* ActorOwner, FLinearColor Color)
{
FRawMesh RawMesh;
RawMesh.VertexPositions.Emplace(FVector(0.f, 0.f, 0.f));
RawMesh.VertexPositions.Emplace(FVector(100.f, 0.f, 0.f));
RawMesh.VertexPositions.Emplace(FVector(100.f, 100.f, 0.f));
RawMesh.VertexPositions.Emplace(FVector(0.f, 100.f, 0.f));
RawMesh.WedgeIndices.Emplace(0);
RawMesh.WedgeIndices.Emplace(1);
RawMesh.WedgeIndices.Emplace(2);
RawMesh.WedgeIndices.Emplace(0);
RawMesh.WedgeIndices.Emplace(2);
RawMesh.WedgeIndices.Emplace(3);
RawMesh.WedgeIndices.Emplace(1);
RawMesh.WedgeIndices.Emplace(0);
RawMesh.WedgeIndices.Emplace(3);
RawMesh.WedgeIndices.Emplace(1);
RawMesh.WedgeIndices.Emplace(3);
RawMesh.WedgeIndices.Emplace(2);
// Create a static mesh from the FRawMesh
UStaticMesh* StaticMesh = NewObject<UStaticMesh>();
StaticMesh->AddSourceModel();
FStaticMeshSourceModel& SourceModel = StaticMesh->GetSourceModel(0);
SourceModel.RawMeshBulkData->SaveRawMesh(RawMesh);
StaticMesh->Build(false);
UStaticMeshComponent* Mesh = NewObject<UStaticMeshComponent>(ActorOwner);
UE_LOG(LogTemp, Warning, TEXT("Calling Mesh->SetStaticMesh(%x)..."), (void*)StaticMesh);
// crashes here:
Mesh->SetStaticMesh(StaticMesh);
Mesh->SetMaterial(0, CreateMaterial(Color));
Mesh->SetCollisionProfileName(TEXT("Pawn"));
Mesh->SetHiddenInGame(false);
Mesh->RegisterComponent();
return Mesh;
}
UMaterialInstanceDynamic* AMyActor::CreateMaterial(FLinearColor Color)
{
FStringAssetReference MaterialRef(TEXT("/Game/SimBlank/Materials/GlossyRedMaterial"));
UMaterialInterface* LoadedMaterial = Cast<UMaterialInterface>(StaticLoadObject(UMaterialInterface::StaticClass(), nullptr, *MaterialRef.ToString()));
UMaterialInstanceDynamic* NewMaterial = UMaterialInstanceDynamic::Create(LoadedMaterial, this);
NewMaterial->SetVectorParameterValue("BaseColor", Color);
return NewMaterial;
}
which I call in the first tick of my plugin, with:
MeshActor = World->SpawnActor<AActor>();
MeshActor->SetRootComponent(CreateMesh(MeshActor, FLinearColor::Gray));
MeshActor->SetActorLocation(GetActorLocation() + FVector(100.0f, 0.0f, 40.0f));
but the above code crashes at Mesh->SetStaticMesh(StaticMesh);
.
Before crashing it prints:
Assertion failed: (Index >= 0) & (Index < ArrayNum) [File:D:\build++UE5\Sync\Engine\Source\Runtime\Core\Public\Containers\Array.h] [Line: 752] Array index out of bounds: 0 from an array of size 0
To make a simpler test, I removed the part where I create the FRawMesh
and also the call to SourceModel.RawMeshBulkData->SaveRawMesh(RawMesh)
, however it crashes in the same way, with the same assertion failed message. Code:
UStaticMeshComponent* AMyActor::CreateMesh(AActor* ActorOwner, FLinearColor Color)
{
UStaticMesh* StaticMesh = NewObject<UStaticMesh>();
StaticMesh->AddSourceModel();
FStaticMeshSourceModel& SourceModel = StaticMesh->GetSourceModel(0);
//SourceModel.RawMeshBulkData->SaveRawMesh(RawMesh);
StaticMesh->Build(false);
UStaticMeshComponent* Mesh = NewObject<UStaticMeshComponent>(ActorOwner);
UE_LOG(LogTemp, Warning, TEXT("Calling Mesh->SetStaticMesh(%x)..."), (void*)StaticMesh);
// crashes here:
Mesh->SetStaticMesh(StaticMesh);
Mesh->SetMaterial(0, CreateMaterial(Color));
Mesh->SetCollisionProfileName(TEXT("Pawn"));
Mesh->SetHiddenInGame(false);
Mesh->RegisterComponent();
return Mesh;
}
What's the correct way to create a static mesh from raw mesh data?
答案1
得分: 1
I think your RawMesh
is missing additional information. 我认为你的RawMesh
缺少额外的信息。
I haven't tested your code but creating RawMesh
and saving it to the StaticMesh
works on my end by adding values in WedgeColors
, WedgeTangent
, WedgeTexCoords
, FaceMaterialIndices
, and FaceSmoothingMasks
. 我尚未测试过你的代码,但通过在WedgeColors
、WedgeTangent
、WedgeTexCoords
、FaceMaterialIndices
和FaceSmoothingMasks
中添加值,我成功创建了RawMesh
并保存到StaticMesh
中。
As an example: 作为示例:
FRawMesh CreateQuadRawMesh()
{
FVector3f EmptyVector = FVector3f(0, 0, 0);
FColor WhiteVertex = FColor(255, 255, 255, 255);
FRawMesh QuadRawMesh;
QuadRawMesh.VertexPositions.Emplace(FVector3f(0.f, 0.f, 0.f));
QuadRawMesh.VertexPositions.Emplace(FVector3f(100.f, 0.f, 0.f));
QuadRawMesh.VertexPositions.Emplace(FVector3f(100.f, 100.f, 0.f));
QuadRawMesh.VertexPositions.Emplace(FVector3f(0.f, 100.f, 0.f));
QuadRawMesh.WedgeIndices.Emplace(0);
QuadRawMesh.WedgeIndices.Emplace(1);
QuadRawMesh.WedgeIndices.Emplace(2);
QuadRawMesh.WedgeIndices.Emplace(0);
QuadRawMesh.WedgeIndices.Emplace(2);
QuadRawMesh.WedgeIndices.Emplace(3);
QuadRawMesh.WedgeIndices.Emplace(1);
QuadRawMesh.WedgeIndices.Emplace(0);
QuadRawMesh.WedgeIndices.Emplace(3);
QuadRawMesh.WedgeIndices.Emplace(1);
QuadRawMesh.WedgeIndices.Emplace(3);
QuadRawMesh.WedgeIndices.Emplace(2);
for (int i = 0; i < 4; ++i)
{
QuadRawMesh.WedgeColors.Add(WhiteVertex);
QuadRawMesh.WedgeColors.Add(WhiteVertex);
QuadRawMesh.WedgeColors.Add(WhiteVertex);
QuadRawMesh.WedgeTangentX.Add(EmptyVector);
QuadRawMesh.WedgeTangentX.Add(EmptyVector);
QuadRawMesh.WedgeTangentX.Add(EmptyVector);
QuadRawMesh.WedgeTangentY.Add(EmptyVector);
QuadRawMesh.WedgeTangentY.Add(EmptyVector);
QuadRawMesh.WedgeTangentY.Add(EmptyVector);
QuadRawMesh.WedgeTangentZ.Add(EmptyVector);
QuadRawMesh.WedgeTangentZ.Add(EmptyVector);
QuadRawMesh.WedgeTangentZ.Add(EmptyVector);
for (int UVIndex = 0; UVIndex < MAX_MESH_TEXTURE_COORDS; UVIndex++)
{
QuadRawMesh.WedgeTexCoords[UVIndex].Add(FVector2f(0.0f, 0.0f));
QuadRawMesh.WedgeTexCoords[UVIndex].Add(FVector2f(0.0f, 0.0f));
QuadRawMesh.WedgeTexCoords[UVIndex].Add(FVector2f(0.0f, 0.0f));
}
QuadRawMesh.FaceMaterialIndices.Add(0);
QuadRawMesh.FaceSmoothingMasks.Add(0xFFFFFFFF); // Phong ?
}
return QuadRawMesh;
}
英文:
I think your RawMesh
is missing additional information. I haven't tested your code but creating RawMesh
and saving it to the StaticMesh
works on my end by adding values in WedgeColors
, WedgeTangent
, WedgeTexCoords
, FaceMaterialIndices
and FaceSmoothingMasks
.
As an example:
FRawMesh CreateQuadRawMesh()
{
FVector3f EmptyVector = FVector3f(0, 0, 0);
FColor WhiteVertex = FColor(255, 255, 255, 255);
FRawMesh QuadRawMesh;
QuadRawMesh.VertexPositions.Emplace(FVector3f(0.f, 0.f, 0.f));
QuadRawMesh.VertexPositions.Emplace(FVector3f(100.f, 0.f, 0.f));
QuadRawMesh.VertexPositions.Emplace(FVector3f(100.f, 100.f, 0.f));
QuadRawMesh.VertexPositions.Emplace(FVector3f(0.f, 100.f, 0.f));
QuadRawMesh.WedgeIndices.Emplace(0);
QuadRawMesh.WedgeIndices.Emplace(1);
QuadRawMesh.WedgeIndices.Emplace(2);
QuadRawMesh.WedgeIndices.Emplace(0);
QuadRawMesh.WedgeIndices.Emplace(2);
QuadRawMesh.WedgeIndices.Emplace(3);
QuadRawMesh.WedgeIndices.Emplace(1);
QuadRawMesh.WedgeIndices.Emplace(0);
QuadRawMesh.WedgeIndices.Emplace(3);
QuadRawMesh.WedgeIndices.Emplace(1);
QuadRawMesh.WedgeIndices.Emplace(3);
QuadRawMesh.WedgeIndices.Emplace(2);
for (int i = 0; i < 4; ++i)
{
QuadRawMesh.WedgeColors.Add(WhiteVertex);
QuadRawMesh.WedgeColors.Add(WhiteVertex);
QuadRawMesh.WedgeColors.Add(WhiteVertex);
QuadRawMesh.WedgeTangentX.Add(EmptyVector);
QuadRawMesh.WedgeTangentX.Add(EmptyVector);
QuadRawMesh.WedgeTangentX.Add(EmptyVector);
QuadRawMesh.WedgeTangentY.Add(EmptyVector);
QuadRawMesh.WedgeTangentY.Add(EmptyVector);
QuadRawMesh.WedgeTangentY.Add(EmptyVector);
QuadRawMesh.WedgeTangentZ.Add(EmptyVector);
QuadRawMesh.WedgeTangentZ.Add(EmptyVector);
QuadRawMesh.WedgeTangentZ.Add(EmptyVector);
for (int UVIndex = 0; UVIndex < MAX_MESH_TEXTURE_COORDS; UVIndex++)
{
QuadRawMesh.WedgeTexCoords[UVIndex].Add(FVector2f(0.0f, 0.0f));
QuadRawMesh.WedgeTexCoords[UVIndex].Add(FVector2f(0.0f, 0.0f));
QuadRawMesh.WedgeTexCoords[UVIndex].Add(FVector2f(0.0f, 0.0f));
}
QuadRawMesh.FaceMaterialIndices.Add(0);
QuadRawMesh.FaceSmoothingMasks.Add(0xFFFFFFFF); // Phong ?
}
return QuadRawMesh;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论