It's not obvious, but those are orthonormal. The catch is the case where 1-nz = 0 so unfortunately an if is needed:
Still even with the branch it is very nice. I was hoping that a careful use of IEEE floating point rules would allow the branch to be avoided but I don't see it. But perhaps some clever person will see a reconstructing. The terms 0*0/0 should be a zero in principle and then all works out. The good news is that for n.z near 1.0 the stability looks good.
1 comment:
This is great! Here is my variant:
if ( n.z >= n.y ) {
const float a = 1.0f/(1.0f + n.z);
const float b = -n.x*n.y*a;
b1 = Vec3f( 1.0f - n.x*n.x*a, b, -n.x );
b2 = Vec3f( b, 1.0f - n.y*n.y*a, -n.y );
} else {
const float a = 1.0f/(1.0f + n.y);
const float b = -n.x*n.z*a;
b1 = Vec3f( b, -n.z, 1.0f - n.z*n.z*a );
b2 = Vec3f( 1.0f - n.x*n.x*a, -n.x, b );
}
This one also has a branch, but it is marginally faster with MSVC. More importantly, it doesn't have a singularity, so it behaves better numerically (no division by a very small number).
Post a Comment