Wavefront OBJ exporter does not de-duplicate some UVs #120219

Open
opened 2024-04-03 17:42:30 +02:00 by george-broughton · 7 comments

System Information
Operating system: Ubuntu 20.04
Graphics card: Intel UHD

Blender Version
Broken: 4.1.0

Short description of error

When exporting as Wavefront .obj file, I can see that some of the data (texture coordinates) is needlessly duplicated in the exported file.

Exact steps for others to reproduce the error

  • Open attached .blend file (Default cube that has been texture mapped so that every side covers the full UV map10.
  • Export as Wavefront and inspect the exported file.

As every vertex is UV mapped to the corners of the texture, there should only be 4 unique UV coordinates. But if we inspect the exported file we can see that 6 'vt's have been produced, although 2 are duplicates.

As I see this, the final 2 'vt' lines can be removed entirely, and any faces indexing them can just point to the earlier vt lines with the same value.

**System Information** Operating system: Ubuntu 20.04 Graphics card: Intel UHD **Blender Version** Broken: 4.1.0 **Short description of error** When exporting as Wavefront .obj file, I can see that some of the data (texture coordinates) is needlessly duplicated in the exported file. **Exact steps for others to reproduce the error** - Open attached .blend file (Default cube that has been texture mapped so that every side covers the full UV map10. - Export as Wavefront and inspect the exported file. As every vertex is UV mapped to the corners of the texture, there should only be 4 unique UV coordinates. But if we inspect the exported file we can see that 6 'vt's have been produced, although 2 are duplicates. As I see this, the final 2 'vt' lines can be removed entirely, and any faces indexing them can just point to the earlier vt lines with the same value.
george-broughton added the
Priority
Normal
Status
Needs Triage
Type
Report
labels 2024-04-03 17:42:31 +02:00

I can confirm.
In fact, it seems that there is no need to have those vts repeated.
But my knowledge about .obj files is limited.

I imagine @aras_p might understand this better.

Confirming...

I can confirm. In fact, it seems that there is no need to have those `vt`s repeated. But my knowledge about .obj files is limited. I imagine @aras_p might understand this better. Confirming...

Yeah as far as I can tell, the C++ OBJ exporter does not "deduplicate" the UVs. Why, I don't quite know, someone wrote the code like that.

However, a good question is, is that worth doing at all. I have not checked, but it is very possible that for most actual models, this "deduplication" step would slow down the exporting process more than it would gain anything. What is the purpose/wish for the deduplication? Purely saving the file size, or something else?

(a cube is kinda the "worst case" since the model is very small to begin with, and many UVs are shared -- however in "actual" real world models way fewer UVs are shared)

Yeah as far as I can tell, the C++ OBJ exporter does not "deduplicate" the UVs. Why, I don't quite know, someone wrote the code like that. However, a good question is, is that worth doing at all. I have not checked, but it is very possible that for most actual models, this "deduplication" step would slow down the exporting process more than it would gain anything. What is the purpose/wish for the deduplication? Purely saving the file size, or something else? (a cube is kinda the "worst case" since the model is very small to begin with, and many UVs are shared -- however in "actual" real world models way fewer UVs are shared)
Aras Pranckevicius changed title from Wavefront exporter duplicating UV data to Wavefront OBJ exporter does not de-duplicate UVs 2024-04-04 06:04:56 +02:00

The purpose was more confusion about why the output file was not as I expected it to look, rather than any major gripe or use case.

As well as a smaller filesize, there might be an argument that de-duplicating would lead to more efficient importing of exported models, as it would have few lines to read, to parse, and lower memory consumption. If it slows down exporting but speeds up importing perhaps it could be an export setting. But yeah I guess it would probably be marginal...

The purpose was more confusion about why the output file was not as I expected it to look, rather than any major gripe or use case. As well as a smaller filesize, there might be an argument that de-duplicating would lead to more efficient importing of exported models, as it would have few lines to read, to parse, and lower memory consumption. If it slows down exporting but speeds up importing perhaps it could be an export setting. But yeah I guess it would probably be marginal...

At first glance I assumed the code was "deduplicating" UVs since I would expect to see 24 UVs (6 faces * 4 corners each), but we can only see 6 UVs there.

Is this because it "deduplicates" UVs that share the same vertex? This is for optimization?

If in real case models this is much less noticeable, perhaps it is not really an error.

At first glance I assumed the code was "deduplicating" UVs since I would expect to see 24 UVs (6 faces * 4 corners each), but we can only see 6 UVs there. Is this because it "deduplicates" UVs that share the same vertex? This is for optimization? If in real case models this is much less noticeable, perhaps it is not really an error.

Well in a Wavefront file you would typically first specify each 2D UV coordinate of the texture on lines beginning with vt.

Then when you define the faces of the mesh, you would say this vertex's texture coordinate can be found in the n-th vt line.

An importer would then lookup the n-th vt line and know that that contains the vertex's UV coordinate.

Of course when exporting, writing every single UV coordinate on a new 'vt' line is fine and as far as I understand valid, it's just that if two vertices share the same UV coordinate, the vt can just be written once to the file, and then they can both point to this same line.

How Blender arrives at 6 vt lines I'm not sure. There is some partial optimisation there - it isn't just blindly writing all 24 UV coordinate like you say. But as there are only 4 unique values having 6 in the file just struck me as odd. An error no, the file is valid. But odd.

From my perspective writing a wavefront importer for a program, this means that when my import code is loading blender Wavefront files, it needs to open a slightly larger file from disk, parse more lines, and then have more vt lines cached in memory before reconstructing the geometry. The end result is the same mesh though...

But yeah to what extent this affects real-world models I don't know - perhaps negligible. But I thought I would at least ask the question to you guys :)

Well in a Wavefront file you would typically first specify each 2D UV coordinate of the texture on lines beginning with vt. Then when you define the faces of the mesh, you would say this vertex's texture coordinate can be found in the n-th vt line. An importer would then lookup the n-th vt line and know that that contains the vertex's UV coordinate. Of course when exporting, writing every single UV coordinate on a new 'vt' line is fine and as far as I understand valid, it's just that if two vertices share the same UV coordinate, the vt can just be written once to the file, and then they can both point to this same line. How Blender arrives at 6 vt lines I'm not sure. There is some partial optimisation there - it isn't just blindly writing all 24 UV coordinate like you say. But as there are only 4 unique values having 6 in the file just struck me as odd. An error no, the file is valid. But odd. From my perspective writing a wavefront importer for a program, this means that when my import code is loading blender Wavefront files, it needs to open a slightly larger file from disk, parse more lines, and then have more vt lines cached in memory before reconstructing the geometry. The end result is the same mesh though... But yeah to what extent this affects real-world models I don't know - perhaps negligible. But I thought I would at least ask the question to you guys :)
Contributor

How Blender arrives at 6 vt lines I'm not sure. There is some partial optimisation there

It's deduping the UVs at full precision but printing them at a lower precision. There are exactly six unique UVs in that cube.

>>> set(l.uv[:] for l in D.meshes['Cube'].uv_layers[0].data)
{(0.0, 1.0), (0.0, 0.0), (1.0, 0.9999999403953552), (1.0, 1.0), (0.0, 0.9999999403953552), (1.0, 0.0)}

OBJ exporter prints UV coords at {:.6f} precision here

23265a2b6d/source/blender/io/wavefront_obj/exporter/obj_export_io.hh (L80-L83)

but stores them in its internal tables for deduplication in full precision here

6a9d2212e4/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc (L293)

Adding a roundoff after that line will probably fix this issue.

> How Blender arrives at 6 vt lines I'm not sure. There is some partial optimisation there It's deduping the UVs at full precision but printing them at a lower precision. There are exactly six unique UVs in that cube. ```py >>> set(l.uv[:] for l in D.meshes['Cube'].uv_layers[0].data) {(0.0, 1.0), (0.0, 0.0), (1.0, 0.9999999403953552), (1.0, 1.0), (0.0, 0.9999999403953552), (1.0, 0.0)} ``` OBJ exporter prints UV coords at `{:.6f}` precision here https://projects.blender.org/blender/blender/src/commit/23265a2b6d16709ba401ec0c2aea8c43c4ff9f64/source/blender/io/wavefront_obj/exporter/obj_export_io.hh#L80-L83 but stores them in its internal tables for deduplication in full precision here https://projects.blender.org/blender/blender/src/commit/6a9d2212e43ee0a49bbf32c32bb5531a40a8f7ee/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc#L293 Adding a roundoff after that line will probably fix this issue.

Ok, then I guess everything makes sense here. I suppose if had they been identical internally then the exported file would have been properly deduplicated.

Would it make sense to perform all actions at the same precision? Given what you guys have said I have no problem if the ticket is just closed as "not worth the effort" :)

Interestingly, I manually typed in each of those UV coordinates to set them to the corners. I guess it's not relevant to this ticket but I really wonder how some are slightly off internally but most fine.

Ok, then I guess everything makes sense here. I suppose if had they been identical internally then the exported file would have been properly deduplicated. Would it make sense to perform all actions at the same precision? Given what you guys have said I have no problem if the ticket is just closed as "not worth the effort" :) Interestingly, I manually typed in each of those UV coordinates to set them to the corners. I guess it's not relevant to this ticket but I really wonder how some are slightly off internally but most fine.
Germano Cavalcante changed title from Wavefront OBJ exporter does not de-duplicate UVs to Wavefront OBJ exporter does not de-duplicate some UVs 2024-04-10 16:52:03 +02:00
Germano Cavalcante added
Type
Known Issue
and removed
Type
Report
labels 2024-04-10 16:52:09 +02:00
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
4 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#120219
No description provided.