System Information
Operating system: Mojave 10.14.6
Graphics card: NVIDIA GeForce GT 750M 2 GB
Blender Version
Broken: Version 3.1.0 (3.1.0 2022-03-09)
Worked: Version 2.93.4
Summary
Blender OBJ import has the option to "keep vertex order". When exporting the Blender Object back out, the v's, g's and f's should be in the same order as they were imported.
Details
The bug is triggered if the input file spreads a single group's faces over multiple g labels. If a group's faces are in a single g label, then the OBJ exports correctly. the OBJ format allows a group's faces to be declared in multiple separate g labels. They are logically connected into a single group. Some applications export OBJs with faces in single groups, some export in internal vert order, adding g labels as needed.
Implications
Some commercial packages use objects as shape keys for morphs and animations. A specific requirement is that vertex order is maintained. This includes faces and group compositions. This has worked correctly up until the new C++ OBJ importer.
Steps
Import an OBJ with the faces of a single group spread over multiple g labels, with the only option being "poly groups" and "keep vertex order". Export with same options. The exported OBJ in 3.1.0 has broken groups. The v order, f structures, and f order are correct. But some of the f's show up in the wrong g's
Note: the attached files contain a commercial figure consisting of proprietary information. Do not use or distribute beyond what is required for this BUG process.
The following script compares the files. The vert count and face count's are equal, but their distribution within groups in the 3.1.0 exported OBJ are incorrect
import re
files = [
'Dawn.obj',
'2.93.4-Dawn.obj-import.obj',
'3.1.0-Dawn.obj-import.obj'
]
raw = {}
obj = {}
print('FILES:', files)
print()
print('{: <30} {: <20} {: <20}'.format(
'FILENAME',
'VERT COUNT',
'FACE COUNT'
))
for filename in files:
file = open(filename, 'r')
data = file.readlines()
raw[filename] = []
obj[filename] = {'v':[],'g':{}}
grp = None
for line in data:
line = re.sub(r'\n$', r'', line)
raw[filename].append(line)
ins = line[:2]
if ins == 'v ':
obj[filename]['v'].append(line)
elif ins == 'g ' :
grp = line.split(' ')[1]
obj[filename]['g'].setdefault(grp, [])
elif ins == 'f ' :
obj[filename]['g'][grp].append(line)
print('{: <32} {: <20} {: <20}'.format(
filename,
len(obj[filename]['v']),
sum([len(obj[filename]['g'][x]) for x in obj[filename]['g']])
))
print()
print('{: <15} {: ^75}'.format('', 'GROUP FACE COUNTS'))
print('{: <15} {: <15} {: <30} {: <30}'.format('', *files))
for grp in obj[files[0]]['g']:
print('{: <15} {: <15} {: <30} {: <30}'.format(
grp,
len(obj[files[0]]['g'][grp]),
len(obj[files[1]]['g'][grp]),
len(obj[files[2]]['g'][grp])
))output
FILES: ['Dawn.obj', '2.93.4-Dawn.obj-import.obj', '3.1.0-Dawn.obj-import.obj']
FILENAME VERT COUNT FACE COUNT
Dawn.obj 39096 39326
2.93.4-Dawn.obj-import.obj 39096 39326
3.1.0-Dawn.obj-import.obj 39096 39326
GROUP FACE COUNTS
Dawn.obj 2.93.4-Dawn.obj-import.obj 3.1.0-Dawn.obj-import.obj
head 10188 10188 10350
lowerJaw 4582 4582 4504
lEye 624 624 624
rEye 624 624 624
tongue01 72 72 80
tongue02 72 72 72
tongue03 72 72 72
tongue04 312 312 288
rForeArm 568 568 645
rCollar 463 463 536
rShldr 453 453 380
rHand 691 691 766
rThumb1 141 141 133
rThumb2 182 182 181
rCarpal 318 318 322
rIndex2 160 160 200
rIndex3 301 301 281
rIndex1 120 120 80
rMid2 160 160 200
rMid1 141 141 100
rRing2 160 160 200
rRing1 120 120 80
rPinky2 160 160 200
rPinky1 125 125 80
rMid3 301 301 281
rRing3 302 302 282
rPinky3 298 298 278
rThumb3 300 300 280
lForeArm 568 568 645
lCollar 463 463 536
lShldr 453 453 380
lHand 691 691 766
lThumb1 141 141 133
lThumb2 182 182 181
lCarpal 318 318 322
lIndex2 160 160 200
lIndex3 301 301 281
lIndex1 120 120 80
lMid2 160 160 200
lMid1 141 141 100
lRing2 160 160 200
lRing1 120 120 80
lPinky2 160 160 200
lPinky1 125 125 80
lMid3 301 301 281
lRing3 302 302 282
lPinky3 298 298 278
lThumb3 300 300 280
rThigh 626 626 692
rShin 562 562 565
rFoot 597 597 605
rToe 689 689 744
rBigToe 248 248 228
rIndexToe 308 308 288
rMidToe 283 283 263
rRingToe 263 263 243
rPinkyToe 245 245 225
lThigh 626 626 692
lShin 562 562 565
lFoot 597 597 605
lToe 689 689 744
lBigToe 248 248 228
lIndexToe 308 308 288
lMidToe 283 283 263
lRingToe 263 263 243
lPinkyToe 245 245 225
neck 338 338 442
neck2 260 260 136
chest2 1678 1678 1614
chest 446 446 444
abdomen2 256 256 256
abdomen 320 320 326
pelvis 618 618 618
hip 294 294 160