Face normals: 32-bit vs 64-bit

   2764   2   0
User Avatar
Member
51 posts
Joined: Oct. 2006
Offline
It seems that, at least under Windows, face normals computed by hou.Face.normal() in Python (and GEO_Face::computeNormal() in HDK) vary slightly between 32- and 64-bit builds.
For example try loading quad.bgeo from the attached archive and then execute something like this from the Python console:
print hou.node('/obj/geo1/file1').geometry().prims().normal()
For me it's under Win32 and under Win64.
The difference is small, but enough to cause some troubles - e.g. see ck_planar.py in the archive - this checks if polygon is planar using the normal reported by HOM - the result is planar under Win32, non-planar under Win64.
Well, I think I know exactly why this happens, but I wonder how to deal with it in Python. Python runtime itself apparently suffers from the same problem, so computing the normal in Python produces yet another result (and again it's apparently different between platforms). I solved this using explicit SSE code via inlinecpp (essentially emulating Win64 results), but this seems too heavy for something this simple.
Thanks!

Edit:
In case anyone may ever need something like this here is that inlinecpp code, mentioned above:
import inlinecpp

fnmod = inlinecpp.createLibrary(
name=“face_norm”,
includes=“#include <UT/UT_Vector3.h>\n#include <VM/VM_Math.h>\n”,
function_sources=[
“”"
void newell_calc(UT_Vector3D* pNml, UT_Vector3D* pVI, UT_Vector3D* pVJ, int mode) {
v4uf n((float)pNml->x(), (float)pNml->y(), (float)pNml->z(), 0.0f);
if (mode == 0) {
v4uf vi((float)pVI->x(), (float)pVI->y(), (float)pVI->z(), 0.0f);
v4uf vj((float)pVJ->x(), (float)pVJ->y(), (float)pVJ->z(), 0.0f);
v4uf dv = vi - vj;
v4uf sv = vi + vj;
n += v4uf(dv, dv, dv, 0.0f) * v4uf(sv, sv, sv, 0.0f);
} else {
v4uf nn = n * n;
n *= v4uf(1.0f) / sqrt(v4uf(nn) + v4uf(nn) + v4uf(nn));
}
(*pNml) = n;
(*pNml) = n;
(*pNml) = n;
}
“”"])


It's used like this:
def faceNorm(prim):
nml = hou.Vector3(0, 0, 0)
nvtx = len(prim.vertices())
for i in xrange(nvtx):
j = i - 1
if j < 0: j = nvtx - 1
vi = prim.vertices().point().position()
vj = prim.vertices().point().position()
fnmod.newell_calc(nml, vi, vj, 0)
fnmod.newell_calc(nml, vi, vj, 1)
return nml


At least on my test data this produces the same exactly _binary_ values on both platforms, and these are exactly the same values as computed by Houdini under Win64.

Attachments:
polynorm.zip (763 bytes)

User Avatar
Member
5 posts
Joined: Sept. 2011
Offline
axebeak
Well, I think I know exactly why this happens, but I wonder how to deal with it in Python. Python runtime itself apparently suffers from the same problem, so computing the normal in Python produces yet another result (and again it's apparently different between platforms). I solved this using explicit SSE code via inlinecpp (essentially emulating Win64 results)

This is related to SSE vs FPU precision matters, right?
User Avatar
Member
51 posts
Joined: Oct. 2006
Offline
Well, yes, I think so.

I'm pretty sure that Houdini uses the following method to compute face normals: http://tog.acm.org/resources/GraphicsGems/gemsiii/newell.c [tog.acm.org]

If you look at the code above you can see all those expressions in the form (A - B) * (C + D)
32-bit build uses stack-based FPU. For 32-bit target such expression will be compiled into something like the following pseudo-code (it's kind of like RPN Calculator):
Push A
Push B
Minus
Push C
Push D
Plus
Multiply
Pop result

The stack-based FPU will carry out all the arithmetic operations above with 80-bit [en.wikipedia.org] precision (unless switched explicitly into low-precession mode).

64-bit build will use SSE scalar instructions for the same computations (FPU is deprecated in 64-bit mode). So intermediate results will have 32-bit precision (assuming float type at the source level).
Hence the extra precision in 32-bit builds.

Almost certainly, this phenomenon is not limited to just face normals. Not sure if there are any serious consequence to this (say, is it possible to construct a scene that will behave differently between 32/64-bit builds?), but this can be somewhat annoying in some cases… However, this is not a bug either.
  • Quick Links