英文:
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;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论