/* This file is part of Nori, a simple educational ray tracer Copyright (c) 2015 by Wenzel Jakob Nori is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License Version 3 as published by the Free Software Foundation. Nori is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma once #include NORI_NAMESPACE_BEGIN /** * \brief Stores a three-dimensional orthonormal coordinate frame * * This class is mostly used to quickly convert between different * cartesian coordinate systems and to efficiently compute certain * quantities (e.g. \ref cosTheta(), \ref tanTheta, ..). */ struct Frame { Vector3f s, t; Normal3f n; /// Default constructor -- performs no initialization! Frame() { } /// Given a normal and tangent vectors, construct a new coordinate frame Frame(const Vector3f &s, const Vector3f &t, const Normal3f &n) : s(s), t(t), n(n) { } /// Construct a frame from the given orthonormal vectors Frame(const Vector3f &x, const Vector3f &y, const Vector3f &z) : s(x), t(y), n(z) { } /// Construct a new coordinate frame from a single vector Frame(const Vector3f &n) : n(n) { coordinateSystem(n, s, t); } /// Convert from world coordinates to local coordinates Vector3f toLocal(const Vector3f &v) const { return Vector3f( v.dot(s), v.dot(t), v.dot(n) ); } /// Convert from local coordinates to world coordinates Vector3f toWorld(const Vector3f &v) const { return s * v.x() + t * v.y() + n * v.z(); } /** \brief Assuming that the given direction is in the local coordinate * system, return the cosine of the angle between the normal and v */ static float cosTheta(const Vector3f &v) { return v.z(); } /** \brief Assuming that the given direction is in the local coordinate * system, return the sine of the angle between the normal and v */ static float sinTheta(const Vector3f &v) { float temp = sinTheta2(v); if (temp <= 0.0f) return 0.0f; return std::sqrt(temp); } /** \brief Assuming that the given direction is in the local coordinate * system, return the tangent of the angle between the normal and v */ static float tanTheta(const Vector3f &v) { float temp = 1 - v.z()*v.z(); if (temp <= 0.0f) return 0.0f; return std::sqrt(temp) / v.z(); } /** \brief Assuming that the given direction is in the local coordinate * system, return the squared sine of the angle between the normal and v */ static float sinTheta2(const Vector3f &v) { return 1.0f - v.z() * v.z(); } /** \brief Assuming that the given direction is in the local coordinate * system, return the sine of the phi parameter in spherical coordinates */ static float sinPhi(const Vector3f &v) { float sinTheta = Frame::sinTheta(v); if (sinTheta == 0.0f) return 1.0f; return clamp(v.y() / sinTheta, -1.0f, 1.0f); } /** \brief Assuming that the given direction is in the local coordinate * system, return the cosine of the phi parameter in spherical coordinates */ static float cosPhi(const Vector3f &v) { float sinTheta = Frame::sinTheta(v); if (sinTheta == 0.0f) return 1.0f; return clamp(v.x() / sinTheta, -1.0f, 1.0f); } /** \brief Assuming that the given direction is in the local coordinate * system, return the squared sine of the phi parameter in spherical * coordinates */ static float sinPhi2(const Vector3f &v) { return clamp(v.y() * v.y() / sinTheta2(v), 0.0f, 1.0f); } /** \brief Assuming that the given direction is in the local coordinate * system, return the squared cosine of the phi parameter in spherical * coordinates */ static float cosPhi2(const Vector3f &v) { return clamp(v.x() * v.x() / sinTheta2(v), 0.0f, 1.0f); } /// Equality test bool operator==(const Frame &frame) const { return frame.s == s && frame.t == t && frame.n == n; } /// Inequality test bool operator!=(const Frame &frame) const { return !operator==(frame); } /// Return a human-readable string summary of this frame std::string toString() const { return tfm::format( "Frame[\n" " s = %s,\n" " t = %s,\n" " n = %s\n" "]", s.toString(), t.toString(), n.toString()); } }; NORI_NAMESPACE_END