| 1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
| 2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
| 3 | #pragma once |
| 4 | |
| 5 | #include <cmath> |
| 6 | |
| 7 | #include "Prerequisites/BsPrerequisitesUtil.h" |
| 8 | #include "Math/BsRadian.h" |
| 9 | |
| 10 | namespace bs |
| 11 | { |
| 12 | /** @addtogroup Math |
| 13 | * @{ |
| 14 | */ |
| 15 | |
| 16 | /** A three dimensional vector. */ |
| 17 | class BS_UTILITY_EXPORT Vector3 |
| 18 | { |
| 19 | public: |
| 20 | float x, y, z; |
| 21 | |
| 22 | public: |
| 23 | Vector3() = default; |
| 24 | |
| 25 | constexpr Vector3(BS_ZERO) |
| 26 | :x(0.0f), y(0.0f), z(0.0f) |
| 27 | { } |
| 28 | |
| 29 | constexpr Vector3(float x, float y, float z) |
| 30 | :x(x), y(y), z(z) |
| 31 | { } |
| 32 | |
| 33 | explicit Vector3(const Vector4& vec); |
| 34 | |
| 35 | /** Exchange the contents of this vector with another. */ |
| 36 | void swap(Vector3& other) |
| 37 | { |
| 38 | std::swap(x, other.x); |
| 39 | std::swap(y, other.y); |
| 40 | std::swap(z, other.z); |
| 41 | } |
| 42 | |
| 43 | float operator[] (UINT32 i) const |
| 44 | { |
| 45 | assert(i < 3); |
| 46 | |
| 47 | return *(&x + i); |
| 48 | } |
| 49 | |
| 50 | float& operator[] (UINT32 i) |
| 51 | { |
| 52 | assert(i < 3); |
| 53 | |
| 54 | return *(&x + i); |
| 55 | } |
| 56 | |
| 57 | /** Pointer accessor for direct copying. */ |
| 58 | float* ptr() |
| 59 | { |
| 60 | return &x; |
| 61 | } |
| 62 | |
| 63 | /** Pointer accessor for direct copying. */ |
| 64 | const float* ptr() const |
| 65 | { |
| 66 | return &x; |
| 67 | } |
| 68 | |
| 69 | Vector3& operator= (float rhs) |
| 70 | { |
| 71 | x = rhs; |
| 72 | y = rhs; |
| 73 | z = rhs; |
| 74 | |
| 75 | return *this; |
| 76 | } |
| 77 | |
| 78 | bool operator== (const Vector3& rhs) const |
| 79 | { |
| 80 | return (x == rhs.x && y == rhs.y && z == rhs.z); |
| 81 | } |
| 82 | |
| 83 | bool operator!= (const Vector3& rhs) const |
| 84 | { |
| 85 | return (x != rhs.x || y != rhs.y || z != rhs.z); |
| 86 | } |
| 87 | |
| 88 | Vector3 operator+ (const Vector3& rhs) const |
| 89 | { |
| 90 | return Vector3(x + rhs.x, y + rhs.y, z + rhs.z); |
| 91 | } |
| 92 | |
| 93 | Vector3 operator- (const Vector3& rhs) const |
| 94 | { |
| 95 | return Vector3(x - rhs.x, y - rhs.y, z - rhs.z); |
| 96 | } |
| 97 | |
| 98 | Vector3 operator* (float rhs) const |
| 99 | { |
| 100 | return Vector3(x * rhs, y * rhs, z * rhs); |
| 101 | } |
| 102 | |
| 103 | Vector3 operator* (const Vector3& rhs) const |
| 104 | { |
| 105 | return Vector3(x * rhs.x, y * rhs.y, z * rhs.z); |
| 106 | } |
| 107 | |
| 108 | Vector3 operator/ (float val) const |
| 109 | { |
| 110 | assert(val != 0.0); |
| 111 | |
| 112 | float fInv = 1.0f / val; |
| 113 | return Vector3(x * fInv, y * fInv, z * fInv); |
| 114 | } |
| 115 | |
| 116 | Vector3 operator/ (const Vector3& rhs) const |
| 117 | { |
| 118 | return Vector3(x / rhs.x, y / rhs.y, z / rhs.z); |
| 119 | } |
| 120 | |
| 121 | const Vector3& operator+ () const |
| 122 | { |
| 123 | return *this; |
| 124 | } |
| 125 | |
| 126 | Vector3 operator- () const |
| 127 | { |
| 128 | return Vector3(-x, -y, -z); |
| 129 | } |
| 130 | |
| 131 | friend Vector3 operator* (float lhs, const Vector3& rhs) |
| 132 | { |
| 133 | return Vector3(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z); |
| 134 | } |
| 135 | |
| 136 | friend Vector3 operator/ (float lhs, const Vector3& rhs) |
| 137 | { |
| 138 | return Vector3(lhs / rhs.x, lhs / rhs.y, lhs / rhs.z); |
| 139 | } |
| 140 | |
| 141 | friend Vector3 operator+ (const Vector3& lhs, float rhs) |
| 142 | { |
| 143 | return Vector3(lhs.x + rhs, lhs.y + rhs, lhs.z + rhs); |
| 144 | } |
| 145 | |
| 146 | friend Vector3 operator+ (float lhs, const Vector3& rhs) |
| 147 | { |
| 148 | return Vector3(lhs + rhs.x, lhs + rhs.y, lhs + rhs.z); |
| 149 | } |
| 150 | |
| 151 | friend Vector3 operator- (const Vector3& lhs, float rhs) |
| 152 | { |
| 153 | return Vector3(lhs.x - rhs, lhs.y - rhs, lhs.z - rhs); |
| 154 | } |
| 155 | |
| 156 | friend Vector3 operator- (float lhs, const Vector3& rhs) |
| 157 | { |
| 158 | return Vector3(lhs - rhs.x, lhs - rhs.y, lhs - rhs.z); |
| 159 | } |
| 160 | |
| 161 | Vector3& operator+= (const Vector3& rhs) |
| 162 | { |
| 163 | x += rhs.x; |
| 164 | y += rhs.y; |
| 165 | z += rhs.z; |
| 166 | |
| 167 | return *this; |
| 168 | } |
| 169 | |
| 170 | Vector3& operator+= (float rhs) |
| 171 | { |
| 172 | x += rhs; |
| 173 | y += rhs; |
| 174 | z += rhs; |
| 175 | |
| 176 | return *this; |
| 177 | } |
| 178 | |
| 179 | Vector3& operator-= (const Vector3& rhs) |
| 180 | { |
| 181 | x -= rhs.x; |
| 182 | y -= rhs.y; |
| 183 | z -= rhs.z; |
| 184 | |
| 185 | return *this; |
| 186 | } |
| 187 | |
| 188 | Vector3& operator-= (float rhs) |
| 189 | { |
| 190 | x -= rhs; |
| 191 | y -= rhs; |
| 192 | z -= rhs; |
| 193 | |
| 194 | return *this; |
| 195 | } |
| 196 | |
| 197 | Vector3& operator*= (float rhs) |
| 198 | { |
| 199 | x *= rhs; |
| 200 | y *= rhs; |
| 201 | z *= rhs; |
| 202 | |
| 203 | return *this; |
| 204 | } |
| 205 | |
| 206 | Vector3& operator*= (const Vector3& rhs) |
| 207 | { |
| 208 | x *= rhs.x; |
| 209 | y *= rhs.y; |
| 210 | z *= rhs.z; |
| 211 | |
| 212 | return *this; |
| 213 | } |
| 214 | |
| 215 | Vector3& operator/= (float rhs) |
| 216 | { |
| 217 | assert(rhs != 0.0f); |
| 218 | |
| 219 | float inv = 1.0f / rhs; |
| 220 | |
| 221 | x *= inv; |
| 222 | y *= inv; |
| 223 | z *= inv; |
| 224 | |
| 225 | return *this; |
| 226 | } |
| 227 | |
| 228 | Vector3& operator/= (const Vector3& rhs) |
| 229 | { |
| 230 | x /= rhs.x; |
| 231 | y /= rhs.y; |
| 232 | z /= rhs.z; |
| 233 | |
| 234 | return *this; |
| 235 | } |
| 236 | |
| 237 | /** Returns the length (magnitude) of the vector. */ |
| 238 | float length() const |
| 239 | { |
| 240 | return std::sqrt(x * x + y * y + z * z); |
| 241 | } |
| 242 | |
| 243 | /** Returns the square of the length(magnitude) of the vector. */ |
| 244 | float squaredLength() const |
| 245 | { |
| 246 | return x * x + y * y + z * z; |
| 247 | } |
| 248 | |
| 249 | /** Returns the distance to another vector. */ |
| 250 | float distance(const Vector3& rhs) const |
| 251 | { |
| 252 | return (*this - rhs).length(); |
| 253 | } |
| 254 | |
| 255 | /** Returns the square of the distance to another vector. */ |
| 256 | float squaredDistance(const Vector3& rhs) const |
| 257 | { |
| 258 | return (*this - rhs).squaredLength(); |
| 259 | } |
| 260 | |
| 261 | /** Calculates the dot (scalar) product of this vector with another. */ |
| 262 | float dot(const Vector3& vec) const |
| 263 | { |
| 264 | return x * vec.x + y * vec.y + z * vec.z; |
| 265 | } |
| 266 | |
| 267 | /** Normalizes the vector. */ |
| 268 | float normalize() |
| 269 | { |
| 270 | float len = length(); |
| 271 | |
| 272 | // Will also work for zero-sized vectors, but will change nothing |
| 273 | if (len > 1e-08f) |
| 274 | { |
| 275 | float invLen = 1.0f / len; |
| 276 | x *= invLen; |
| 277 | y *= invLen; |
| 278 | z *= invLen; |
| 279 | } |
| 280 | return len; |
| 281 | } |
| 282 | |
| 283 | |
| 284 | /** Calculates the cross-product of 2 vectors, that is, the vector that lies perpendicular to them both. */ |
| 285 | Vector3 cross(const Vector3& other) const |
| 286 | { |
| 287 | return Vector3( |
| 288 | y * other.z - z * other.y, |
| 289 | z * other.x - x * other.z, |
| 290 | x * other.y - y * other.x); |
| 291 | } |
| 292 | |
| 293 | /** Sets this vector's components to the minimum of its own and the ones of the passed in vector. */ |
| 294 | void min(const Vector3& cmp) |
| 295 | { |
| 296 | if (cmp.x < x) x = cmp.x; |
| 297 | if (cmp.y < y) y = cmp.y; |
| 298 | if (cmp.z < z) z = cmp.z; |
| 299 | } |
| 300 | |
| 301 | /** Sets this vector's components to the maximum of its own and the ones of the passed in vector. */ |
| 302 | void max(const Vector3& cmp) |
| 303 | { |
| 304 | if (cmp.x > x) x = cmp.x; |
| 305 | if (cmp.y > y) y = cmp.y; |
| 306 | if (cmp.z > z) z = cmp.z; |
| 307 | } |
| 308 | |
| 309 | /** Generates a vector perpendicular to this vector. */ |
| 310 | Vector3 perpendicular() const |
| 311 | { |
| 312 | static const float squareZero = (float)(1e-06 * 1e-06); |
| 313 | |
| 314 | Vector3 perp = this->cross(Vector3::UNIT_X); |
| 315 | |
| 316 | if (perp.squaredLength() < squareZero) |
| 317 | perp = this->cross(Vector3::UNIT_Y); |
| 318 | |
| 319 | perp.normalize(); |
| 320 | return perp; |
| 321 | } |
| 322 | |
| 323 | /** Gets the angle between 2 vectors. */ |
| 324 | inline Radian angleBetween(const Vector3& dest) const; |
| 325 | |
| 326 | /** Returns true if this vector is zero length. */ |
| 327 | bool isZeroLength() const |
| 328 | { |
| 329 | float sqlen = (x * x) + (y * y) + (z * z); |
| 330 | return (sqlen < (1e-06f * 1e-06f)); |
| 331 | } |
| 332 | |
| 333 | /** Calculates a reflection vector to the plane with the given normal. */ |
| 334 | Vector3 reflect(const Vector3& normal) const |
| 335 | { |
| 336 | return Vector3(*this - (2 * this->dot(normal) * normal)); |
| 337 | } |
| 338 | |
| 339 | /** Calculates two vectors orthonormal to the current vector, and normalizes the current vector if not already. */ |
| 340 | void orthogonalComplement(Vector3& a, Vector3& b) |
| 341 | { |
| 342 | if (std::abs(x) > std::abs(y)) |
| 343 | a = Vector3(-z, 0, x); |
| 344 | else |
| 345 | a = Vector3(0, z, -y); |
| 346 | |
| 347 | b = cross(a); |
| 348 | |
| 349 | orthonormalize(*this, a, b); |
| 350 | } |
| 351 | |
| 352 | /** Performs Gram-Schmidt orthonormalization. */ |
| 353 | static void orthonormalize(Vector3& vec0, Vector3& vec1, Vector3& vec2) |
| 354 | { |
| 355 | vec0.normalize(); |
| 356 | |
| 357 | float dot0 = vec0.dot(vec1); |
| 358 | vec1 -= dot0*vec0; |
| 359 | vec1.normalize(); |
| 360 | |
| 361 | float dot1 = vec1.dot(vec2); |
| 362 | dot0 = vec0.dot(vec2); |
| 363 | vec2 -= dot0*vec0 + dot1*vec1; |
| 364 | vec2.normalize(); |
| 365 | } |
| 366 | |
| 367 | /** Calculates the dot (scalar) product of two vectors. */ |
| 368 | static float dot(const Vector3& a, const Vector3& b) |
| 369 | { |
| 370 | return a.x * b.x + a.y * b.y + a.z * b.z; |
| 371 | } |
| 372 | |
| 373 | /** Normalizes the provided vector and returns a new normalized instance. */ |
| 374 | static Vector3 normalize(const Vector3& val); |
| 375 | |
| 376 | /** Calculates the cross-product of 2 vectors, that is, the vector that lies perpendicular to them both. */ |
| 377 | static Vector3 cross(const Vector3& a, const Vector3& b) |
| 378 | { |
| 379 | return Vector3( |
| 380 | a.y * b.z - a.z * b.y, |
| 381 | a.z * b.x - a.x * b.z, |
| 382 | a.x * b.y - a.y * b.x); |
| 383 | } |
| 384 | |
| 385 | /** |
| 386 | * Linearly interpolates between the two vectors using @p t. t should be in [0, 1] range, where t = 0 corresponds |
| 387 | * to the left vector, while t = 1 corresponds to the right vector. |
| 388 | */ |
| 389 | static Vector3 lerp(float t, const Vector3& a, const Vector3& b) |
| 390 | { |
| 391 | return (1.0f - t) * a + t * b; |
| 392 | } |
| 393 | |
| 394 | /** Checks are any of the vector components not a number. */ |
| 395 | inline bool isNaN() const; |
| 396 | |
| 397 | /** Returns the minimum of all the vector components as a new vector. */ |
| 398 | static Vector3 min(const Vector3& a, const Vector3& b) |
| 399 | { |
| 400 | return Vector3(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z)); |
| 401 | } |
| 402 | |
| 403 | /** Returns the maximum of all the vector components as a new vector. */ |
| 404 | static Vector3 max(const Vector3& a, const Vector3& b) |
| 405 | { |
| 406 | return Vector3(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z)); |
| 407 | } |
| 408 | |
| 409 | static const Vector3 ZERO; |
| 410 | static const Vector3 ONE; |
| 411 | static const Vector3 INF; |
| 412 | static const Vector3 UNIT_X; |
| 413 | static const Vector3 UNIT_Y; |
| 414 | static const Vector3 UNIT_Z; |
| 415 | }; |
| 416 | |
| 417 | /** @} */ |
| 418 | |
| 419 | /** @cond SPECIALIZATIONS */ |
| 420 | BS_ALLOW_MEMCPY_SERIALIZATION(Vector3); |
| 421 | /** @endcond */ |
| 422 | } |
| 423 | |
| 424 | /** @cond SPECIALIZATIONS */ |
| 425 | namespace std |
| 426 | { |
| 427 | template<> class numeric_limits<bs::Vector3> |
| 428 | { |
| 429 | public: |
| 430 | constexpr static bs::Vector3 infinity() |
| 431 | { |
| 432 | return bs::Vector3( |
| 433 | std::numeric_limits<float>::infinity(), |
| 434 | std::numeric_limits<float>::infinity(), |
| 435 | std::numeric_limits<float>::infinity()); |
| 436 | } |
| 437 | }; |
| 438 | } |
| 439 | /** @endcond */ |