Add support for up to 4 texture channels when importing meshes

#2667
This commit is contained in:
Wojtek Figat
2025-01-11 22:40:20 +01:00
parent 756ba0a533
commit a1c46d2e6e
31 changed files with 427 additions and 475 deletions

View File

@@ -246,13 +246,15 @@ bool ProcessMesh(ModelData& result, AssimpImporterData& data, const aiMesh* aMes
mesh.Positions.Set((const Float3*)aMesh->mVertices, aMesh->mNumVertices);
// Texture coordinates
if (aMesh->mTextureCoords[0])
for (int32 channelIndex = 0; channelIndex < MODEL_MAX_UV && aMesh->mTextureCoords[channelIndex]; channelIndex++)
{
mesh.UVs.Resize(aMesh->mNumVertices, false);
aiVector3D* a = aMesh->mTextureCoords[0];
mesh.UVs.Resize(channelIndex + 1);
auto& channel = mesh.UVs[channelIndex];
channel.Resize(aMesh->mNumVertices, false);
aiVector3D* a = aMesh->mTextureCoords[channelIndex];
for (uint32 v = 0; v < aMesh->mNumVertices; v++)
{
mesh.UVs[v] = *(Float2*)a;
channel.Get()[v] = *(Float2*)a;
a++;
}
}
@@ -265,7 +267,7 @@ bool ProcessMesh(ModelData& result, AssimpImporterData& data, const aiMesh* aMes
const auto face = &aMesh->mFaces[faceIndex];
if (face->mNumIndices != 3)
{
errorMsg = TEXT("All faces in a mesh must be trangles!");
errorMsg = TEXT("All faces in a mesh must be triangles!");
return true;
}
@@ -296,57 +298,7 @@ bool ProcessMesh(ModelData& result, AssimpImporterData& data, const aiMesh* aMes
}
// Lightmap UVs
if (data.Options.LightmapUVsSource == ModelLightmapUVsSource::Disable)
{
// No lightmap UVs
}
else if (data.Options.LightmapUVsSource == ModelLightmapUVsSource::Generate)
{
// Generate lightmap UVs
if (mesh.GenerateLightmapUVs())
{
LOG(Error, "Failed to generate lightmap uvs");
}
}
else
{
// Select input channel index
int32 inputChannelIndex;
switch (data.Options.LightmapUVsSource)
{
case ModelLightmapUVsSource::Channel0:
inputChannelIndex = 0;
break;
case ModelLightmapUVsSource::Channel1:
inputChannelIndex = 1;
break;
case ModelLightmapUVsSource::Channel2:
inputChannelIndex = 2;
break;
case ModelLightmapUVsSource::Channel3:
inputChannelIndex = 3;
break;
default:
inputChannelIndex = INVALID_INDEX;
break;
}
// Check if has that channel texcoords
if (inputChannelIndex >= 0 && inputChannelIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS && aMesh->mTextureCoords[inputChannelIndex])
{
mesh.LightmapUVs.Resize(aMesh->mNumVertices, false);
aiVector3D* a = aMesh->mTextureCoords[inputChannelIndex];
for (uint32 v = 0; v < aMesh->mNumVertices; v++)
{
mesh.LightmapUVs[v] = *(Float2*)a;
a++;
}
}
else
{
LOG(Warning, "Cannot import result lightmap uvs. Missing texcoords channel {0}.", inputChannelIndex);
}
}
mesh.SetLightmapUVsSource(data.Options.LightmapUVsSource);
// Vertex Colors
if (data.Options.ImportVertexColors && aMesh->mColors[0])

View File

@@ -386,10 +386,12 @@ bool ProcessMesh(ImporterData& data, FbxMesh* fbxMesh, MeshData& mesh, String& e
}
// Texture coordinates
FbxGeometryElementUV* texcoords = fbxMesh->GetElementUV(0);
if (texcoords)
for (int32 channelIndex = 0; channelIndex < MODEL_MAX_UV && fbxMesh->GetElementUV(channelIndex); channelIndex++)
{
ReadLayerData(fbxMesh, *texcoords, mesh.UVs);
FbxGeometryElementUV* texcoords = fbxMesh->GetElementUV(0);
mesh.UVs.Resize(channelIndex + 1);
auto& channel = mesh.UVs[channelIndex];
ReadLayerData(fbxMesh, *texcoords, channel);
}
// Normals
@@ -405,53 +407,7 @@ bool ProcessMesh(ImporterData& data, FbxMesh* fbxMesh, MeshData& mesh, String& e
}
// Lightmap UVs
if (data.Options.LightmapUVsSource == ModelLightmapUVsSource::Disable)
{
// No lightmap UVs
}
else if (data.Options.LightmapUVsSource == ModelLightmapUVsSource::Generate)
{
// Generate lightmap UVs
if (mesh.GenerateLightmapUVs())
{
// TODO: we could propagate this message to Debug Console in editor? or create interface to gather some msgs from importing service
LOG(Warning, "Failed to generate lightmap uvs");
}
}
else
{
// Select input channel index
int32 inputChannelIndex;
switch (data.Options.LightmapUVsSource)
{
case ModelLightmapUVsSource::Channel0:
inputChannelIndex = 0;
break;
case ModelLightmapUVsSource::Channel1:
inputChannelIndex = 1;
break;
case ModelLightmapUVsSource::Channel2:
inputChannelIndex = 2;
break;
case ModelLightmapUVsSource::Channel3:
inputChannelIndex = 3;
break;
default:
inputChannelIndex = INVALID_INDEX;
break;
}
// Check if has that channel texcoords
if (inputChannelIndex >= 0 && inputChannelIndex < fbxMesh->GetElementUVCount() && fbxMesh->GetElementUV(inputChannelIndex))
{
ReadLayerData(fbxMesh, *fbxMesh->GetElementUV(inputChannelIndex), mesh.LightmapUVs);
}
else
{
// TODO: we could propagate this message to Debug Console in editor? or create interface to gather some msgs from importing service
LOG(Warning, "Cannot import model lightmap uvs. Missing texcoords channel {0}.", inputChannelIndex);
}
}
mesh.SetLightmapUVsSource(data.Options.LightmapUVsSource);
// Vertex Colors
if (data.Options.ImportVertexColors && fbxMesh->GetElementVertexColorCount() > 0)
@@ -609,10 +565,11 @@ bool ProcessMesh(ImporterData& data, FbxMesh* fbxMesh, MeshData& mesh, String& e
}
// Flip the Y in texcoords
for (int32 i = 0; i < mesh.UVs.Count(); i++)
mesh.UVs[i].Y = 1.0f - mesh.UVs[i].Y;
for (int32 i = 0; i < mesh.LightmapUVs.Count(); i++)
mesh.LightmapUVs[i].Y = 1.0f - mesh.LightmapUVs[i].Y;
for (auto& channel : mesh.UVs)
{
for (int32 i = 0; i < channel.Count(); i++)
channel[i].Y = 1.0f - channel[i].Y;
}
// Handle missing material case (could never happen but it's better to be sure it will work)
if (mesh.MaterialSlotIndex == -1)

View File

@@ -690,7 +690,6 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
const ofbx::GeometryPartition& partition = geometryData.getPartition(partitionIndex);
const int vertexCount = partition.triangles_count * 3;
const ofbx::Vec3Attributes& positions = geometryData.getPositions();
const ofbx::Vec2Attributes& uvs = geometryData.getUVs();
const ofbx::Vec3Attributes& normals = geometryData.getNormals();
const ofbx::Vec3Attributes& tangents = geometryData.getTangents();
const ofbx::Vec4Attributes& colors = geometryData.getColors();
@@ -723,15 +722,18 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
mesh.Indices.Get()[i] = i;
// Texture coordinates
if (uvs.values)
for (int32 channelIndex = 0; channelIndex < MODEL_MAX_UV && geometryData.getUVs(channelIndex).values; channelIndex++)
{
mesh.UVs.Resize(vertexCount, false);
const ofbx::Vec2Attributes& uvs = geometryData.getUVs(channelIndex);
mesh.UVs.Resize(channelIndex + 1);
auto& channel = mesh.UVs[channelIndex];
channel.Resize(vertexCount, false);
for (int i = 0; i < vertexCount; i++)
mesh.UVs.Get()[i] = ToFloat2(uvs.get(triangulatedIndices[i]));
channel.Get()[i] = ToFloat2(uvs.get(triangulatedIndices[i]));
if (data.ConvertRH)
{
for (int32 v = 0; v < vertexCount; v++)
mesh.UVs[v].Y = 1.0f - mesh.UVs[v].Y;
for (int v = 0; v < vertexCount; v++)
channel.Get()[v].Y = 1.0f - channel.Get()[v].Y;
}
}
@@ -776,59 +778,7 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
}
// Lightmap UVs
if (data.Options.LightmapUVsSource == ModelLightmapUVsSource::Disable)
{
// No lightmap UVs
}
else if (data.Options.LightmapUVsSource == ModelLightmapUVsSource::Generate)
{
// Generate lightmap UVs
if (mesh.GenerateLightmapUVs())
{
LOG(Error, "Failed to generate lightmap uvs");
}
}
else
{
// Select input channel index
int32 inputChannelIndex;
switch (data.Options.LightmapUVsSource)
{
case ModelLightmapUVsSource::Channel0:
inputChannelIndex = 0;
break;
case ModelLightmapUVsSource::Channel1:
inputChannelIndex = 1;
break;
case ModelLightmapUVsSource::Channel2:
inputChannelIndex = 2;
break;
case ModelLightmapUVsSource::Channel3:
inputChannelIndex = 3;
break;
default:
inputChannelIndex = INVALID_INDEX;
break;
}
// Check if has that channel texcoords
const auto lightmapUVs = geometryData.getUVs(inputChannelIndex);
if (lightmapUVs.values)
{
mesh.LightmapUVs.Resize(vertexCount, false);
for (int i = 0; i < vertexCount; i++)
mesh.LightmapUVs.Get()[i] = ToFloat2(lightmapUVs.get(triangulatedIndices[i]));
if (data.ConvertRH)
{
for (int32 v = 0; v < vertexCount; v++)
mesh.LightmapUVs[v].Y = 1.0f - mesh.LightmapUVs[v].Y;
}
}
else
{
LOG(Warning, "Cannot import model lightmap uvs. Missing texcoords channel {0}.", inputChannelIndex);
}
}
mesh.SetLightmapUVsSource(data.Options.LightmapUVsSource);
// Vertex Colors
if (data.Options.ImportVertexColors && colors.values)

View File

@@ -2027,11 +2027,14 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
meshopt_remapVertexBuffer(dstMesh->name.Get(), srcMesh->name.Get(), srcMeshVertexCount, sizeof(type), remap.Get()); \
}
REMAP_VERTEX_BUFFER(Positions, Float3);
REMAP_VERTEX_BUFFER(UVs, Float2);
dstMesh->UVs.Resize(srcMesh->UVs.Count());
for (int32 channelIdx = 0; channelIdx < srcMesh->UVs.Count(); channelIdx++)
{
REMAP_VERTEX_BUFFER(UVs[channelIdx], Float2);
}
REMAP_VERTEX_BUFFER(Normals, Float3);
REMAP_VERTEX_BUFFER(Tangents, Float3);
REMAP_VERTEX_BUFFER(Tangents, Float3);
REMAP_VERTEX_BUFFER(LightmapUVs, Float2);
REMAP_VERTEX_BUFFER(Colors, Color);
REMAP_VERTEX_BUFFER(BlendIndices, Int4);
REMAP_VERTEX_BUFFER(BlendWeights, Float4);