1
$\begingroup$

I'm writing an exporter for an old game file format that only supports one normal per vertex. This requires creating duplicates for each vertex (or rather, loop) that has split normals. The problem I'm having is that, even when the split normals are averaged (via Mesh -> Normals -> Average -> Custom Normal), the result I get can be slightly different, causing my script to duplicate the vertex.

I made a simple test, with 2 triangles joined at vertices 0 and 2.

Test example

Here's a sample code I'm using to check the values of the split normals. The current example ignores transforming from object space to world space for simplicity.

import bpy

print("start")

for  object in bpy.data.objects:
    
    mesh = object.data
    mesh.calc_loop_triangles()
    mesh.calc_normals_split() 

    print(object.name)
    print(mesh.has_custom_normals)
    
    for triangle in mesh.loop_triangles:
        
         for loop, vertex, normal in zip(triangle.loops, triangle.vertices, triangle.split_normals):

            n = mesh.loops[loop].normal
            #n = normal #triangle normal gives the same result
             
            print(vertex, str(tuple(n)))

And the output of the script for my sample

start
Sphere
True
0 (-0.02063608169555664, 0.7257574796676636, 0.6876412034034729)
1 (-0.2683730721473694, 0.6490309834480286, 0.7118530869483948)
2 (-0.02064351737499237, 0.7257753610610962, 0.6876221299171448)
0 (-0.020633935928344727, 0.7257868647575378, 0.6876101493835449)
2 (-0.020631134510040283, 0.7257802486419678, 0.6876172423362732)
3 (0.2285022735595703, 0.7532715797424316, 0.616740345954895)

I would expect the split normal for vertices 0 and 2 to be identical, but it's not. In this case the difference is fairly minimal but, in some real-world scenarios, I've noticed bigger differences. Am I missing something? Do the values of the normals need to be somehow corrected per face/triangle?

$\endgroup$
1
  • $\begingroup$ why don't you just use edge split modifier? $\endgroup$
    – Crantisz
    Commented Jul 26, 2022 at 13:26

1 Answer 1

0
$\begingroup$

You're not missing anything AFAIK, split normals are just weird. The low order digits are junk. They can vary across platforms too.

So it's common for exporters to round the normals off. The OBJ exporter for example rounds to 4 digits, which should be sufficient for regular lighting and stuff. Of course this also has the advantage that you don't needlessly duplicate a vertex for the sake of imperceptible differences in the normal.

$\endgroup$
1
  • $\begingroup$ Thank you, the good news here is that I'm not losing my mind. The bad news is, of course, that there might be no real fix to the issue. My actual script already includes a rounding to 4 decimal places, but the lack of precision triggers my OCD quite badly 😅 $\endgroup$ Commented Jul 26, 2022 at 15:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .