Nori
|
00001 /* 00002 This file is part of Nori, a simple educational ray tracer 00003 00004 Copyright (c) 2012 by Wenzel Jakob and Steve Marschner. 00005 00006 Nori is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License Version 3 00008 as published by the Free Software Foundation. 00009 00010 Nori is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00019 #if !defined(__FRAME_H) 00020 #define __FRAME_H 00021 00022 #include <nori/vector.h> 00023 00024 NORI_NAMESPACE_BEGIN 00025 00026 /** 00027 * \brief Stores a three-dimensional orthonormal coordinate frame 00028 * 00029 * This class is mostly used to quickly convert between different 00030 * cartesian coordinate systems and to efficiently compute certain 00031 * quantities (e.g. \ref cosTheta(), \ref tanTheta, ..). 00032 */ 00033 struct Frame { 00034 Vector3f s, t; 00035 Normal3f n; 00036 00037 /// Default constructor -- performs no initialization! 00038 inline Frame() { } 00039 00040 /// Given a normal and tangent vectors, construct a new coordinate frame 00041 inline Frame(const Vector3f &s, const Vector3f &t, const Normal3f &n) 00042 : s(s), t(t), n(n) { } 00043 00044 /// Construct a frame from the given orthonormal vectors 00045 inline Frame(const Vector3f &x, const Vector3f &y, const Vector3f &z) 00046 : s(x), t(y), n(z) { } 00047 00048 /// Construct a new coordinate frame from a single vector 00049 inline Frame(const Vector3f &n) : n(n) { 00050 coordinateSystem(n, s, t); 00051 } 00052 00053 /// Convert from world coordinates to local coordinates 00054 inline Vector3f toLocal(const Vector3f &v) const { 00055 return Vector3f( 00056 v.dot(s), v.dot(t), v.dot(n) 00057 ); 00058 } 00059 00060 /// Convert from local coordinates to world coordinates 00061 inline Vector3f toWorld(const Vector3f &v) const { 00062 return s * v.x() + t * v.y() + n * v.z(); 00063 } 00064 00065 /** \brief Assuming that the given direction is in the local coordinate 00066 * system, return the cosine of the angle between the normal and v */ 00067 inline static float cosTheta(const Vector3f &v) { 00068 return v.z(); 00069 } 00070 00071 /** \brief Assuming that the given direction is in the local coordinate 00072 * system, return the sine of the angle between the normal and v */ 00073 inline static float sinTheta(const Vector3f &v) { 00074 float temp = sinTheta2(v); 00075 if (temp <= 0.0f) 00076 return 0.0f; 00077 return std::sqrt(temp); 00078 } 00079 00080 /** \brief Assuming that the given direction is in the local coordinate 00081 * system, return the tangent of the angle between the normal and v */ 00082 inline static float tanTheta(const Vector3f &v) { 00083 float temp = 1 - v.z()*v.z(); 00084 if (temp <= 0.0f) 00085 return 0.0f; 00086 return std::sqrt(temp) / v.z(); 00087 } 00088 00089 /** \brief Assuming that the given direction is in the local coordinate 00090 * system, return the squared sine of the angle between the normal and v */ 00091 inline static float sinTheta2(const Vector3f &v) { 00092 return 1.0f - v.z() * v.z(); 00093 } 00094 00095 /** \brief Assuming that the given direction is in the local coordinate 00096 * system, return the sine of the phi parameter in spherical coordinates */ 00097 inline static float sinPhi(const Vector3f &v) { 00098 float sinTheta = Frame::sinTheta(v); 00099 if (sinTheta == 0.0f) 00100 return 1.0f; 00101 return clamp(v.y() / sinTheta, -1.0f, 1.0f); 00102 } 00103 00104 /** \brief Assuming that the given direction is in the local coordinate 00105 * system, return the cosine of the phi parameter in spherical coordinates */ 00106 inline static float cosPhi(const Vector3f &v) { 00107 float sinTheta = Frame::sinTheta(v); 00108 if (sinTheta == 0.0f) 00109 return 1.0f; 00110 return clamp(v.x() / sinTheta, -1.0f, 1.0f); 00111 } 00112 00113 /** \brief Assuming that the given direction is in the local coordinate 00114 * system, return the squared sine of the phi parameter in spherical 00115 * coordinates */ 00116 inline static float sinPhi2(const Vector3f &v) { 00117 return clamp(v.y() * v.y() / sinTheta2(v), 0.0f, 1.0f); 00118 } 00119 00120 /** \brief Assuming that the given direction is in the local coordinate 00121 * system, return the squared cosine of the phi parameter in spherical 00122 * coordinates */ 00123 inline static float cosPhi2(const Vector3f &v) { 00124 return clamp(v.x() * v.x() / sinTheta2(v), 0.0f, 1.0f); 00125 } 00126 00127 /// Equality test 00128 inline bool operator==(const Frame &frame) const { 00129 return frame.s == s && frame.t == t && frame.n == n; 00130 } 00131 00132 /// Inequality test 00133 inline bool operator!=(const Frame &frame) const { 00134 return !operator==(frame); 00135 } 00136 00137 /// Return a human-readable string summary of this frame 00138 inline QString toString() const { 00139 return QString( 00140 "Frame[\n" 00141 " s = %1,\n" 00142 " t = %2,\n" 00143 " n = %3\n" 00144 "]") 00145 .arg(s.toString()).arg(t.toString()).arg(n.toString()); 00146 } 00147 }; 00148 00149 NORI_NAMESPACE_END 00150 00151 #endif /* __FRAME_H */