class ONB { public: ONB(float3 normal); float3 WorldToLocal(const float3 &v); float3 LocalToWorld(const float3 &v); private: float3 n; float3 s; float3 t; }; ONB::ONB(float3 normal) : n(normal) { if (fabs(n.x) > fabs(n.z)) { s.x = -n.y; s.y = n.x; s.z = 0; } else { s.x = 0; s.y = -n.z; s.z = n.y; } s = normalize(s); t = cross(n, s); } float3 ONB::WorldToLocal(const float3 &v) { return make_float3(dot(v, s), dot(v, t), dot(v, n)); } float3 ONB::LocalToWorld(const float3 &v) { return (v.x * s) + (v.y * t) + (v.z * n); }