Skip to content

Unsupported FBX Format: ByPolygonVertex/Direct (and possible fix) #1272

@olichose123

Description

@olichose123

Alternative title: Insomnia-fueled exploration of hxd.fmt.fbx

The problem

I came upon a bug with a specific FBX setup. Blockbench (a low-poly 3D modelling software) outputs an FBX model where LayerElementUV has MappingInformationType as ByPolygonVertex and ReferenceInformationType as Direct, which means there are no indices. Compare this to Blender's FBX format which outputs as ByPolygonVertex/IndexToDirect, with indices mapping polygons to UV coordinates.

The function hxd.fmt.fbx.Geometry.hx:getUVs considers the absence of indices as a Maya quirk and generates a list of indices with the exact same values as the geometry's PolygonVertexIndex, while it should, in our case, generate a list of continuous integers.

The current method:

public function getUVs() {
	var uvs = [];
	for( v in root.getAll("LayerElementUV") ) {
		var index = v.get("UVIndex", true);
		var values = v.get("UV").getFloats();
		var index = if( index == null ) {
			// ByVertice/Direct (Maya sometimes...)
			[for( i in getPolygons() ) if( i < 0 ) -i - 1 else i];
		} else index.getInts();
		uvs.push({ values : values, index : index });
	}
	return uvs;
}

My FBX's Geometry:

Vertices: *24 {
	a: 400,800,400,400,800,-400,400,0,400,400,0,-400,-400,800,400,-400,800,-400,-400,0,400,-400,0,-400
}
PolygonVertexIndex: *24 {
	a: 1,0,2,-4,6,4,5,-8,4,0,1,-6,3,2,6,-8,2,0,4,-7,5,1,3,-8
}
LayerElementUV: 0 {
	Version: 101
	Name: ""
	MappingInformationType: "ByPolygonVertex"
	ReferenceInformationType: "Direct"
	UV: *48 {
		a: 0.25,1,0,1,0,0.75,0.25,0.75,0.25,0.46875,0.25,0.71875,0,0.71875,0,0.46875,0.28125,0.75,0.53125,0.75,0.53125,1,0.28125,1,0.53125,0.46875,0.53125,0.71875,0.28125,0.71875,0.28125,0.46875,0.25,0.1875,0.25,0.4375,0,0.4375,0,0.1875,0.8125,1,0.5625,1,0.5625,0.75,0.8125,0.75
			}
		}

in a nutshell

  • 8 vertices (24 values)
  • 6 quads (24 values)
  • 24 UV coordinates (48 values)

Expected output of "index" in getUVs' return output:
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]: length 24
Where 6 quads are represented in 24 UV coordinates.
(each four UV indices represent a quad)

Current output:
[for( i in getPolygons() ) if( i < 0 ) -i - 1 else i];
or
[1,0,2,3,6,4,5,7,4,0,1,5,3,2,6,7,2,0,4,6,5,1,3,-8] length 24
Which is the same value as PolygonVertexIndex, 1,0,2,-4,6,4,5,-8,4,0,1,-6,3,2,6,-8,2,0,4,-7,5,1,3,-8.

A possible solution

Here's an edited getUVs that would still support Maya and also support ByPolygonVertex/Direct. A cleaner approach would be to use enums, but it's important to note that for the FBX format both ByVertex and ByVertice are valid keywords.

public function getUVs() {
	var uvs = [];
	var mapping_type = root.get("LayerElementUV.MappingInformationType").props[0].toString();
	for( v in root.getAll("LayerElementUV") ) {
		var index = v.get("UVIndex", true);
		var values = v.get("UV").getFloats();
		var indices = null;
		// Ref info type is Direct instead of IndexToDirect
		if (index == null)
		{
			if (mapping_type == "ByVertex" || mapping_type == "ByVertice")
			{
				// Original Maya approach
				indices = [for( i in getPolygons() ) if( i < 0 ) -i - 1 else i];
			}
			else if (mapping_type == "ByPolygonVertex")
			{
				// Blockbench approach
				indices = [for(i in 0...getPolygons().length) i];
			}
		}
		else {
			indices = index.getInts();
		}
		uvs.push({ values : values, index : indices });
	}
	return uvs;
}

Note that I could not test a Maya FBX, but the code for it should not have changed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions