Generating Static Mesh UV Map Probelm

Good day all

This might be a bit of a niche question, but when I generate a static mesh, the UV does not end up in the correct UV channel.

Context

I’m working on a ArchViz project. A building is loaded over the network as a stream of vertices and other data. We used to do this using procedural meshes, but now we also want the option to use static meshes so that we can bake textures and lighting. For this, we are using editor side scripting to load the same data over the network, and build static meshes instead.

The code

To generate the static mesh, I wrote the C++ function below, and call it from blueprints:

UStaticMesh* UUtilityFunctions::CreateStaticMesh(UPARAM(ref) TArray<FVector>& Vertices, UPARAM(ref) TArray<FVector>& Normals, UPARAM(ref) TArray<int>& Triangles, UPARAM(ref) TArray<FVector2D>& UVMaps) {
	FMeshDescription meshDesc;
	FStaticMeshAttributes Attributes(meshDesc);
	UStaticMesh* staticMesh = NewObject<UStaticMesh>();
	Attributes.Register();

	FMeshDescriptionBuilder meshDescBuilder;
	meshDescBuilder.SetMeshDescription(&meshDesc);
	meshDescBuilder.EnablePolyGroups();
	meshDescBuilder.SetNumUVLayers(1);
	FPolygonGroupID polygonGroup = meshDescBuilder.AppendPolygonGroup();

	int Vertices_Length = Vertices.Num();

	int triangle_points = Triangles.Num();
	// Loop through all the triangles in the mesh
	for (int triangle_index = 0; triangle_index < triangle_points; triangle_index += 3) {
		// Create vertex instance per vertex in triangle
		TArray< FVertexInstanceID > vertexInsts;
		for (int point_index = triangle_index; point_index < triangle_index + 3; point_index++) {
			int vertex_index = Triangles[point_index];
			FVector vertex = Vertices[vertex_index];
			FVector normal = Normals[vertex_index];
			FVector2D UV = UVMaps[vertex_index];
			// Append vertex to the mesh
			FVertexID vertex_id = meshDescBuilder.AppendVertex(vertex);
			// Create an instance of this vertex
			FVertexInstanceID instance = meshDescBuilder.AppendInstance(vertex_id);
			// Set the UV value of this instance
			meshDescBuilder.SetInstanceUV(instance, UV,0);
			// Set the normal of this instance
			meshDescBuilder.SetInstanceNormal(instance, normal);
			// Add instance to array
			vertexInsts.Add(instance);
		}
		// Create triangle in the mesh by defining the three instances to use
		meshDescBuilder.AppendTriangle(vertexInsts[0], vertexInsts[1], vertexInsts[2], polygonGroup);
	}

	UStaticMesh::FBuildMeshDescriptionsParams mdParams;
	mdParams.bBuildSimpleCollision = true;

	// Build static mesh
	TArray<const FMeshDescription*> meshDescPtrs;
	meshDescPtrs.Emplace(&meshDesc);
	staticMesh->BuildFromMeshDescriptions(meshDescPtrs, mdParams);

	return staticMesh;
}

What happens

Geometry is generated and spawned into the scene. However the UV map of the static mesh is empty.


As you can tell from the screenshot, there is one UV channel, and it is empty. When I try to build the lighting it gives errors.

Now at this point you might think that my UV information just isn’t making it into the mesh at all, however that’s not true. When I add a UV channel in the editor blueprint:
image

This new channel somehow contains my UV data!


(I’ve confirmed that it’s my UV data and not being generated. If I comment out the code that writes the UV data then this channel is blank).
So my UV data makes it into the mesh, just not in channel 0, which is strange because the ‘SetInstanceUV’ function I use takes as argument the desired UV layer, which is set to 0, but the data ends up in layer 1.
Once I have this layer, I can set the “Light Map Coordinate Index” to 1, after which the lighting builds without errors. However setting this parameter for possibly 100s of meshes is not feasible.

Possible solutions

The way I see it I have two possible solutions.

  1. Figure out how to write UV data to channel 0. From here the lighting should be easy to build.

  2. Figure out how to set the “Light Map Coordinate Index” from editor utility blueprints. For some reason this doesn’t seem possible. I can edit the “Generate Lightmap UVs” boolean, but not where to generate them from.

I’m not an expert in Unreal Engine, so if I’m doing something dumb, let me know. Thanks for your time!

I figured out the problem. Apparently Unreal is working just fine. The UV textures (Made in Rhino) were outside the 0-1 range. So the UV Channel wasn’t empty, it was just not in the visible frame. Rescaling the values to between 0-1 fixed this problem.

I’m not an expert on texture mapping. Do the values always need to be between 0 and 1?

Marking this as solved.