Parsing .obj uvs to ArrayMesh

Godot Version

4.4

Question

so I’m doing something a little psychotic right now, which is to take a .obj file and parse it directly into an ArrayMesh, so that I can procedurally combine .objs later. But I’m stuck trying to get the UVs to work. This is all c#. I’ve got the data out of the .obj file using this thing: https://github.com/stefangordon/ObjParser

Anyway, .obj files store their data as a list of vertices, a list of uvs, and a list of faces organized as vertIndex / uvIndex that looks like:

f 2/1 1/2 3/3 6/4
f 1/2 5/5 4/6 3/3
f 5/7 1/8 7/9 12/10
f 1/8 2/11 8/12 7/9
f 8/13 9/14 10/15 7/16
f 7/16 10/15 11/17 12/18
f 3/19 4/20 11/21 10/22
f 2/11 6/23 9/24 8/12
f 4/20 5/7 12/10 11/21
f 6/23 3/25 10/26 9/24

each f line being a quad or “Face”. I’m using an array i’m calling allDataArray for the ArrayMesh. It takes the .obj vertices directly like this

alldataArray[(int)Mesh.ArrayType.Vertex] = obj.vertices

and then I create the indexes for primitive.triangle faces as

for (int i = 0; i < obj.FaceList.Count; i++)
{
Face face = obj.FaceList[i];

indiceList.Add(face.VertexIndexList[0] - 1);
indiceList.Add(face.VertexIndexList[1] - 1);
indiceList.Add(face.VertexIndexList[2] - 1);

indiceList.Add(face.VertexIndexList[0] - 1);
indiceList.Add(face.VertexIndexList[2] - 1);
indiceList.Add(face.VertexIndexList[3] - 1);

}

alldataArray[(int)Mesh.ArrayType.Index] = indiceList.ToArray();

where face.VertexIndexList[0] is the 2 of f 2/1 and TextureVertexIndexList[0] is 1
The -1 everywhere is just because .obj starts at 1 and godot starts at 0.

This works fine and can be tested by adding empty UV info, but now I’m trying to add UV data from the obj and I don’t understand how ArrayMesh handles this. ArrayMesh wants an equal number of vertexes and uv coords or else it errors out, so it wants one UV per vertex?

My first approach was to make a uv array the same size of the vertex array, and assign each uv as you parse the faces as like

uvArray[face.VertexIndexList[0] - 1] = obj.TextureList[face.TextureVertexIndexList[0] - 1].xy;
uvArray[face.VertexIndexList[1] - 1] = obj.TextureList[face.TextureVertexIndexList[1] - 1].xy;
uvArray[face.VertexIndexList[2] - 1] = obj.TextureList[face.TextureVertexIndexList[2] - 1].xy;
uvArray[face.VertexIndexList[3] - 1] = obj.TextureList[face.TextureVertexIndexList[3] - 1].xy;

below I’ve got what it should look like vs what the broken textures look like


this is happening because the .obj faces includes both a 2/1 and 2/11 face so vertex[2] has multiple UV coordinates wherever there is a seam in the uv map, and the above code is just applying one of them. The internet says you should just have duplicated vertexes but I’m confused on how you would do that. I can see that there are 26 unique uv coords and 12 unique vertex positions, so I tried filling out duplicate vertexes up to 26 using the face data, but that just made another hexagon with differently wonky UVs. I am stumped.

has anyone worked with the UVs in arrayMesh before?

ok I solved my own problem. Sometimes you just need to write the problem out so the rocks rattling around in your head will get it together.

I rewrote it to this, overuse of ToArray is a problem for future me. also for some reason the y uv coords needed to be inverted? oh well

foreach (TextureVertex tv in obj.TextureList)
{
tv.xy = new Vector2((float)tv.X, 1f - (float)tv.Y);
}

List uvList = new List();
List vertList = new List();
List indicesList = new List();

for (int i = 0; i < obj.FaceList.Count; i++)
{
Face face = obj.FaceList[i];
for (int j = 0; j < 4; j++)
{
vertList.Add(obj.VertexList[face.VertexIndexList[j] -1].xyz);
uvList.Add(obj.TextureList[face.TextureVertexIndexList[j] -1].xy);
}
int thisMany = vertList.Count;
indicesList.Add(thisMany - 4);
indicesList.Add(thisMany - 3);
indicesList.Add(thisMany - 2);
indicesList.Add(thisMany - 4);
indicesList.Add(thisMany - 2);
indicesList.Add(thisMany - 1);
}

indices = indicesList.ToArray();
vertices = vertList.ToArray();
uvs = uvList.ToArray();

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.