Export split normals in OBJ, work on FBX

Hi,

So today I committed the “split normals” in OBJ exporter, now when you check « Include Normals » you will get split normals.

I also kept working on FBX – one can get nice gain with optimizations here… Right now (only basic vertices, faces [now polygons] and edges export done), with a default cube subdivided nine times (i.e. over 1.5 millions of vertices and faces), here are the stats I get:

With edges:

New code:
New verts: done in 4.237405 secs...
New polys: done in 3.605981 secs...
New edges: done in 3.249940 secs...
export finished in 14.5939 sec.

Old code:
Old verts: done in 5.774732 secs...
Old faces: done in 5.692272 secs...
Old edges: done in 9.272664 secs...
export finished in 28.4587 sec.

Without edges:

New code:
New verts: done in 4.237738 secs...
New polys: done in 3.707349 secs...
New edges: done in 0.000003 secs...
export finished in 11.5021 sec.Old code:
Old verts: done in 5.733048 secs...
Old faces: done in 4.810387 secs...
Old edges: done in 0.000004 secs...
export finished in 16.1231 sec.

Still quite a bunch of work to do here (not to mention binary export 😉 )…

Export Sharp Edges as Vertex Normals – Day 8

Great news ‑ core code and RNA API are in trunk (commits r60005, r60014 and r60015)! Many thanks to Campbell, who helped a lot optimizing and cleaning up the core code, and to Brecht, who reviewed the API code. 😀

Note that for now, there is no preview in 3D View, and no storing of those split normals in .blend file, as this is only temp data currently.

Very soon (probably tomorrow), I will commit the OBJ update. FBX will have to wait a bit more, as it first needs some deeper changes! Anyway, hard work is done, py scripting is easy… 😛

Export Sharp Edges as Vertex Normals – Day 6 & 7

So, ping-pong with Master Yoda, King of Optimization (aka Campbell 😛 ) kept going…

I must say I’m rather amazed and happy with the results! In latest patch, we have another 50% or so gain in performance, and we now only use 8 bytes per edge and 4 bytes per loop!

Btw, found out FBX export currently exports tessellated faces, which is bad and will need to be fixed before adding split normals export to this format. Will try to tackle this in the next days (if optimizations suggestions stop filling up my available time! 😉 ).

Export Sharp Edges as Vertex Normals – Day 4

Spent a few hours on polishing the core code – removed some unused elements, gaining a few CPU cycles and over all, reducing temp edge data from 80 bytes to 48 bytes per edge (on 64 systems)! Also made some more tests, everything still successful. 🙂

Also reworked the API… Still very basic, but less nasty than first version imho. Now waiting feedback from Cambpell about it (issue here is that we have too much ways to do it, need some advices about the best one!).

Current patches: core and obj exporter.

So I’d say the core goal of the project is now done (remaining bits – FBX export & adding split angle threshold – are trivial). If current API is validated, will try to get that reviewed asap, and then will see about adding 3D View visualization…

Export Sharp Edges as Vertex Normals – Day 3

Small day, mostly coded a (rough) split normals export for OBJ (replaces the more basic “Export Normals” current behavior), to test the WIP code, and packaged a build on Graphicall (sorry, linux64 only), using those patches: core code and exporter script.

Now I need some people having access to 3DS Max or Maya (or any other “reference” OBJ importer 😉 ) to make some tests with real-case objects. I see not much point in working on the API & co until the core code is validated!

Just FYI, here is an export of a simple cube with two non-crossing edge loops marked as sharp:

# Blender v2.68 (sub 2) OBJ File: 'temp.blend'
# www.blender.org
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vn -0.000000 -0.707107 0.707107
vn 1.000000 0.000000 0.000000
vn 0.000000 -0.707107 -0.707107
vn -0.000000 0.707107 0.707107
vn -1.000000 -0.000000 -0.000000
vn 0.000000 0.707107 -0.707107
s 1
f 1//3 2//1 3//1 4//3
f 5//6 8//6 7//4 6//4
f 1//2 5//2 6//2 2//2
f 2//1 6//4 7//4 3//1
f 3//5 7//5 8//5 4//5
f 5//6 1//3 4//3 8//6

Export Sharp Edges as Vertex Normals – Day 2

Pfew… This has been epic (nearly 8 hours today), but I think the core function is now working correctly. For now I’ve setup a very dirty way to expose it to Python (proper solution will probably need to store it in CD and expose it as a loop’s member, as pyrna does not seems to really support arrays of vectors :/ ).

That WIP patch will allow the most motivated to test it (again, it’s not yet usable!) – others will have to champ at the bit! :p It’s too late to use this in OBJ export code and upload a build to graphicall, and I’ll likely not have any blender-time tomorrow, so I’ll try to do this on Thursday…

A very basic profiling shows it’s about twice slower as regular faces+vert normals computation, not that bad!

Btw, if any of you has a good free OBJ visualizer working under Linux, I‘d be very interested, else it’s hard for me to test complex cases! 😉

Export Per-vertex Normals Project

Hi everyone,

So, I propose to implement per-vertex normal for SharpEdge export from Blender (more details below), provided I can gather 600€ (800$) through Paypal.

Goal Reached! Progress: 600 / 600€

Donators (thanks very much!):

  • Jonathan Williamson
  • Ejner Fergo
  • Nosslak
  • Andy Davies (metalliandy)
  • Joseph Harford
  • Ken Beyer
  • myclay
  • mAlkAv!An
  • Ben Apuna
  • Benjamin Tolputt
  • Bloodwork
  • Bjørnar Frøyse
  • and 8 others…

Last updated: 2013/09/02, 6h30 UTC

Thanks again to all donators ! Now starts the best part – coding ! I will come back here as soon as I have something to show…

I will update this post as often as possible to reflect progress (nothing automatic here, so it won’t move when I’m sleeping or so…), and close the payment page when goal is reached. If you want to be named in the donators’ list, please let me know (e.g. in the remark field of the Paypal page or the contact form below), as by default I will only report total financial progress.

Note I’m often available on #blendercoders channel on freenode.net.

Deliverable

  • C function in Blender kernel which computes a Loop CD layer of normals (Loop CD layers are face-related data attached to vertices, best example are UVs), taking into account edges marked as sharp (and optionally an angle-between-faces threshold).
  • API glue code to expose this function to Python.
  • Use of this code to export per-vertex normals in FBX and OBJ formats

Please note that this work is to be reviewed and integrated in official Blender code, which means it will be maintained well! I’ll work with the maintainers of the related areas to be sure these goals are reached.

Project details

You may be aware (if you are an artist trying to use Blender inside a production pipeline, esp. for games) of the issue raised in this thread (don’t read it, it simply boils down to Blender currently not being able to generate/export per-vertex normals to represent its Sharp Edges feature).

The goal of this project is to implement (in C, Blender core source code) a function computing those vertices’ normals, taking into account edges marked as Sharp, and then add that export option to at least .obj and .fbx formats.

Now as it is not always simple and obvious to understand that topic, let’s take a simple example.

Here we have a simple mesh, with some edges marked as Sharp (the blue ones), which form an edge loop with a few additional “stray” ones.

Sharp edges (wire view)

Sharp edges (wire view)

Sharp edges (solid view)

Sharp edges (solid view)

If you export this object from Blender into Wavefront format without any “sharp edges handling”, here is what you get:


# Blender v2.68 (sub 2) OBJ File: 'demo.blend'
# http://www.blender.org
o Cube
v 0.000000 0.000000 -1.000000
v -0.000000 -0.000000 1.000000
v 1.000000 -0.000000 0.000000
v -0.000000 -1.000000 0.000000
v -1.000000 0.000000 0.000000
v 0.000000 1.000000 0.000000
v 0.750000 -0.000000 -0.750000
v 0.000000 0.750000 -0.750000
v 0.750000 0.750000 0.000000
v -0.000000 -0.750000 -0.750000
v 0.750000 -0.750000 0.000000
v -0.750000 0.000000 -0.750000
v -0.750000 -0.750000 0.000000
v -0.750000 0.750000 0.000000
v 0.750000 -0.000000 0.750000
v 0.000000 0.750000 0.750000
v -0.000000 -0.750000 0.750000
v -0.750000 0.000000 0.750000
v 0.555556 0.555556 -0.555556
v 0.555555 -0.555556 -0.555556
v -0.555556 -0.555555 -0.555556
v -0.555555 0.555556 -0.555556
v 0.555556 0.555555 0.555556
v 0.555555 -0.555556 0.555556
v -0.555556 -0.555556 0.555556
v -0.555556 0.555556 0.555556
s 1
f 1 8 19 7
f 1 7 20 10
f 1 10 21 12
f 1 12 22 8
f 2 15 23 16
f 2 16 26 18
f 2 18 25 17
f 2 17 24 15
f 3 7 19 9
f 3 9 23 15
f 3 15 24 11
f 3 11 20 7
f 4 10 20 11
f 4 11 24 17
f 4 17 25 13
f 4 13 21 10
f 5 12 21 13
f 5 13 25 18
f 5 18 26 14
f 5 14 22 12
f 6 16 23 9
f 6 9 19 8
f 6 8 22 14
f 6 14 26 16

No sharp edges handling - Shading

No sharp edges handling – Shading

No sharp edges handling - Normals

No sharp edges handling – Normals

Quite obviously, sharp edges data are completely lost!

If you try to use the Smooth Groups export option, you will get something like:


# Blender v2.68 (sub 2) OBJ File: 'demo.blend'
# http://www.blender.org
o Cube
v 0.000000 0.000000 -1.000000
v -0.000000 -0.000000 1.000000
v 1.000000 -0.000000 0.000000
v -0.000000 -1.000000 0.000000
v -1.000000 0.000000 0.000000
v 0.000000 1.000000 0.000000
v 0.750000 -0.000000 -0.750000
v 0.000000 0.750000 -0.750000
v 0.750000 0.750000 0.000000
v -0.000000 -0.750000 -0.750000
v 0.750000 -0.750000 0.000000
v -0.750000 0.000000 -0.750000
v -0.750000 -0.750000 0.000000
v -0.750000 0.750000 0.000000
v 0.750000 -0.000000 0.750000
v 0.000000 0.750000 0.750000
v -0.000000 -0.750000 0.750000
v -0.750000 0.000000 0.750000
v 0.555556 0.555556 -0.555556
v 0.555555 -0.555556 -0.555556
v -0.555556 -0.555555 -0.555556
v -0.555555 0.555556 -0.555556
v 0.555556 0.555555 0.555556
v 0.555555 -0.555556 0.555556
v -0.555556 -0.555556 0.555556
v -0.555556 0.555556 0.555556
s 1
f 1 8 19 7
f 1 7 20 10
f 1 10 21 12
f 1 12 22 8
f 3 7 19 9
f 3 11 20 7
f 4 10 20 11
f 4 13 21 10
f 5 12 21 13
f 5 14 22 12
f 6 9 19 8
f 6 8 22 14
s 2
f 2 15 23 16
f 2 16 26 18
f 2 18 25 17
f 2 17 24 15
f 3 9 23 15
f 3 15 24 11
f 4 11 24 17
f 4 17 25 13
f 5 13 25 18
f 5 18 26 14
f 6 16 23 9
f 6 14 26 16

Sharp edges exported as smooth groups - Shading

Sharp edges exported as smooth groups – Shading

Sharp edges exported as smooth groups - Normals

Sharp edges exported as smooth groups – Normals

It’s better but unfortunately, smooth groups can only handle sharp edges that define faces islands! the bottom picture shows normals as they would be reconstructed from the smooth groups data, but we still do not store any actual normals!

Now, one would expect something like this:


# Blender v2.68 (sub 2) OBJ File: 'demo.blend'
# http://www.blender.org
o Cube
v 0.000000 0.000000 -1.000000
v -0.000000 -0.000000 1.000000
v 1.000000 -0.000000 0.000000
v -0.000000 -1.000000 0.000000
v -1.000000 0.000000 0.000000
v 0.000000 1.000000 0.000000
v 0.750000 -0.000000 -0.750000
v 0.000000 0.750000 -0.750000
v 0.750000 0.750000 0.000000
v -0.000000 -0.750000 -0.750000
v 0.750000 -0.750000 0.000000
v -0.750000 0.000000 -0.750000
v -0.750000 -0.750000 0.000000
v -0.750000 0.750000 0.000000
v 0.750000 -0.000000 0.750000
v 0.000000 0.750000 0.750000
v -0.000000 -0.750000 0.750000
v -0.750000 0.000000 0.750000
v 0.555556 0.555556 -0.555556
v 0.555555 -0.555556 -0.555556
v -0.555556 -0.555555 -0.555556
v -0.555555 0.555556 -0.555556
v 0.555556 0.555555 0.555556
v 0.555555 -0.555556 0.555556
v -0.555556 -0.555556 0.555556
v -0.555556 0.555556 0.555556
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.707083 -0.707083
vn 0.577349 0.577349 -0.577349
vn 0.707083 0.000000 -0.707083
vn 0.577349 -0.577349 -0.577349
vn 0.000000 -0.707083 -0.707083
vn -0.577349 -0.577349 -0.577349
vn -0.707083 0.000000 -0.707083
vn -0.577349 0.577349 -0.577349
vn 1.000000 0.000000 0.000000
vn 0.707083 0.707083 0.000000
vn 0.707083 -0.707083 0.000000
vn 0.000000 -1.000000 0.000000
vn -0.707083 -0.707083 0.000000
vn -1.000000 0.000000 0.000000
vn -0.707083 0.707083 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 1.000000
vn 0.707083 0.000000 0.707083
vn 0.577349 0.577349 0.577349
vn 0.000000 0.707083 0.707083
vn -0.577349 0.577349 0.577349
vn -0.707083 0.000000 0.707083
vn -0.577349 -0.577349 0.577349
vn 0.000000 -0.707083 0.707083
vn 0.577349 -0.577349 0.577349
vn 0.655610 -0.655610 -0.374634
vn 0.928477 0.000000 -0.371391
vn 0.655610 0.655610 -0.374634
vn 0.000000 0.928477 -0.371391
vn -0.655610 0.655610 -0.374634
vn -0.928477 0.000000 -0.371391
vn 0.655610 -0.655610 -0.374634
vn 0.000000 -0.928477 -0.371390
vn 0.870388 -0.348155 0.348155
vn 0.928477 0.000000 0.371391
vn 0.655610 0.655610 0.374634
vn 0.000000 0.928477 0.371391
vn -0.655610 0.655610 0.374634
vn -0.928477 0.000000 0.371391
vn 0.655610 -0.655610 0.374634
vn 0.000000 -0.928477 0.371390
vn 0.348155 -0.870388 0.348155
vn 0.348155 -0.348155 0.870388
s 1
f 1//1 8//2 19//3 7//4
f 1//1 7//4 20//5 10//6
f 1//1 10//6 21//7 12//8
f 1//1 12//8 22//9 8//2
f 3//28 7//4 19//3 9//29
f 3//28 11//27 20//5 7//4
f 4//34 10//6 20//5 11//27
f 4//34 13//33 21//7 10//6
f 5//32 12//8 21//7 13//33
f 5//32 14//31 22//9 12//8
f 6//30 9//29 19//3 8//2
f 6//30 8//2 22//9 14//31
s 2
f 2//18 15//19 23//20 16//21
f 2//18 16//21 26//22 18//23
f 2//18 18//23 25//24 17//25
f 2//18 17//25 24//44 15//19
f 3//36 9//37 23//20 15//19
f 3//36 15//19 24//35 11//35
f 4//42 11//43 24//43 17//25
f 4//42 17//25 25//24 13//41
f 5//40 13//41 25//24 18//23
f 5//40 18//23 26//22 14//39
f 6//38 16//21 23//20 9//37
f 6//38 14//39 26//22 16//21

Per-vertex normals for sharp edges - Shading

Per-vertex normals for sharp edges – Shading

Per-vertex normals for sharp edges - Normals

Per-vertex normals for sharp edges – Normals

As you can see, this time the .obj file has much more data, as it stores at least one normal per vertex. And when a vertex is “on” a sharp edges, it can store two or more normals for this vertex, which get used by different faces to “show” the sharp edges.

This feature currently does not exists when exporting from Blender, and this is what I propose to implement.

Please note that this project is not about manual vertex normals editing. It might be a base (a first step) for such a project, though.

About me

My name’s Bastien Montagne, I’m a 29 years old french man. I’ve been working with and for Blender for many years, starting with wiki documentation. Since about two years and half, I started real code works, and am now over 1000 commits to Blender (more stats here), including the WeightVGroup modifiers, uiLists enhancements, many bug fixes – and I’m currently the maintainer of the i18n module (UI translation). I use Blender mostly to make some small videos for non-profit environmental organizations…