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:
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.
-
Figure out how to write UV data to channel 0. From here the lighting should be easy to build.
-
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!