Creating and displaying DynamicMesh from C++ - messed up normals of half of the faces

Hi all,

I’m having hard times doing quite simple thing in UE, from C++ level.
The goal is simple. I want to be able to display a cube. I want to specify vertices, faces and normals by hand. Hardcode it in C++, create mesh and display. And yet I can’t get it right.

Full code of the project is available in this repo. Take a look at the AMyActor::RegenerateMeshByHand method, please.

I have a bare bones project with just a single MyActor deriving from the AActor. I create a UDynamicMeshComponent and set it as my root component.
In PostLoad() I attempt to create a UE::Geometry::FDynamicMesh3 mesh and set it in my root component.

It all works, the mesh is set, but it doesn’t look good. Every other face has a messed up normal and because of that half of the faces of the cube are invisible. They are visible only “from inside”, because only in this view, the normals are facing camera (I think).

When I call mesh.CheckValidity() I get false, so I must do something wrong.

I tried another thing: create a cube in Blender, export to OBJ file, look what’s inside and do the same from the code. AND IT WORKS (after ReverseOrientation and InitializeOverlayToPerTriangleNormals)!! Full cube is displayed, all the normals are fine.
So, I’m double-confused.

For sure I’m missing something obvious required by the engine. Does anyone have an idea what’s wrong?

Full code of the method if someone prefers it here:

UE::Geometry::FDynamicMesh3 AMyActor::RegenerateMeshByHand() {

  UE::Geometry::FDynamicMesh3 mesh;
  mesh.EnableAttributes();

  UE::Geometry::FDynamicMeshNormalOverlay *normalsOverlay =
      mesh.Attributes()->PrimaryNormals();

  const std::array vertices{FVector3d(-1, -1, -1), FVector3d(1, -1, -1),
                            FVector3d(-1, -1, 1),  FVector3d(1, -1, 1),
                            FVector3d(-1, 1, -1),  FVector3d(1, 1, -1),
                            FVector3d(-1, 1, 1),   FVector3d(1, 1, 1)};

  const std::array normals{FVector3f(0, -1, 0), FVector3f(0, 1, 0),
                           FVector3f(-1, 0, 0), FVector3f(1, 0, 0),
                           FVector3f(0, 0, -1), FVector3f(0, 0, 1)};

  int32 id;
  UE::Geometry::EMeshResult result;

  for (auto vertex : vertices) {
    mesh.AppendVertex(vertex * 100);
  }

  for (auto normal : normals) {
    normalsOverlay->AppendElement(normal);
    normalsOverlay->AppendElement(normal);
    normalsOverlay->AppendElement(normal);
  }

  // Face 0, 1. Normal 0
  id = mesh.AppendTriangle(0, 1, 2);
  result = normalsOverlay->SetTriangle(id, {0, 1, 2});

  id = mesh.AppendTriangle(3, 1, 2);
  result = normalsOverlay->SetTriangle(id, {0, 1, 2});

  // Face 2, 3. Normal 1
  id = mesh.AppendTriangle(4, 5, 6);
  result = normalsOverlay->SetTriangle(id, {1 * 3, 1 * 3 + 1, 1 * 3 + 2});

  id = mesh.AppendTriangle(7, 5, 6);
  result = normalsOverlay->SetTriangle(id, {1 * 3, 1 * 3 + 1, 1 * 3 + 2});

  // Face 4, 5. Normal 2
  id = mesh.AppendTriangle(4, 6, 0);
  result = normalsOverlay->SetTriangle(id, {2 * 3, 2 * 3 + 1, 2 * 3 + 2});

  id = mesh.AppendTriangle(2, 6, 0);
  result = normalsOverlay->SetTriangle(id, {2 * 3, 2 * 3 + 1, 2 * 3 + 2});

  // Face 6, 7. Normal 3
  id = mesh.AppendTriangle(1, 5, 3);
  result = normalsOverlay->SetTriangle(id, {3 * 3, 3 * 3 + 1, 3 * 3 + 2});

  id = mesh.AppendTriangle(7, 5, 3);
  result = normalsOverlay->SetTriangle(id, {3 * 3, 3 * 3 + 1, 3 * 3 + 2});

  // Face 8, 9. Normal 4
  id = mesh.AppendTriangle(0, 1, 4);
  result = normalsOverlay->SetTriangle(id, {4 * 3, 4 * 3 + 1, 4 * 3 + 2});

  id = mesh.AppendTriangle(5, 1, 4);
  result = normalsOverlay->SetTriangle(id, {4 * 3, 4 * 3 + 1, 4 * 3 + 2});

  // Face 10, 11. Normal 5
  id = mesh.AppendTriangle(2, 3, 6);
  result = normalsOverlay->SetTriangle(id, {5 * 3, 5 * 3 + 1, 5 * 3 + 2});

  id = mesh.AppendTriangle(7, 3, 6);
  result = normalsOverlay->SetTriangle(id, {5 * 3, 5 * 3 + 1, 5 * 3 + 2});

  // Why is this false?
  const auto validityResult =
      mesh.CheckValidity({}, UE::Geometry::EValidityCheckFailMode::ReturnOnly);

  return mesh;
}

Hi, @stryku2393,

The order of the vertices of a triangle defines where the triangle points.

The triangle defined by mesh.AppendTriangle(0, 1, 2) is facing one side. The triangle defined by mesh.AppendTriangle(0, 2, 1) is facing the opposite side.

Knowing this, try changing the order of the vertices of some of the triangles.