1/// @ref gtc_matrix_transform 2/// @file glm/gtc/matrix_transform.inl 3 4#include "../geometric.hpp" 5#include "../trigonometric.hpp" 6#include "../matrix.hpp" 7 8namespace glm 9{ 10 template<typename T, qualifier Q> 11 GLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) 12 { 13 mat<4, 4, T, Q> Result(m); 14 Result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3]; 15 return Result; 16 } 17 18 template<typename T, qualifier Q> 19 GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v) 20 { 21 T const a = angle; 22 T const c = cos(a); 23 T const s = sin(a); 24 25 vec<3, T, Q> axis(normalize(v)); 26 vec<3, T, Q> temp((T(1) - c) * axis); 27 28 mat<4, 4, T, Q> Rotate; 29 Rotate[0][0] = c + temp[0] * axis[0]; 30 Rotate[0][1] = temp[0] * axis[1] + s * axis[2]; 31 Rotate[0][2] = temp[0] * axis[2] - s * axis[1]; 32 33 Rotate[1][0] = temp[1] * axis[0] - s * axis[2]; 34 Rotate[1][1] = c + temp[1] * axis[1]; 35 Rotate[1][2] = temp[1] * axis[2] + s * axis[0]; 36 37 Rotate[2][0] = temp[2] * axis[0] + s * axis[1]; 38 Rotate[2][1] = temp[2] * axis[1] - s * axis[0]; 39 Rotate[2][2] = c + temp[2] * axis[2]; 40 41 mat<4, 4, T, Q> Result; 42 Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; 43 Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; 44 Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; 45 Result[3] = m[3]; 46 return Result; 47 } 48 49 template<typename T, qualifier Q> 50 GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate_slow(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v) 51 { 52 T const a = angle; 53 T const c = cos(a); 54 T const s = sin(a); 55 mat<4, 4, T, Q> Result; 56 57 vec<3, T, Q> axis = normalize(v); 58 59 Result[0][0] = c + (static_cast<T>(1) - c) * axis.x * axis.x; 60 Result[0][1] = (static_cast<T>(1) - c) * axis.x * axis.y + s * axis.z; 61 Result[0][2] = (static_cast<T>(1) - c) * axis.x * axis.z - s * axis.y; 62 Result[0][3] = static_cast<T>(0); 63 64 Result[1][0] = (static_cast<T>(1) - c) * axis.y * axis.x - s * axis.z; 65 Result[1][1] = c + (static_cast<T>(1) - c) * axis.y * axis.y; 66 Result[1][2] = (static_cast<T>(1) - c) * axis.y * axis.z + s * axis.x; 67 Result[1][3] = static_cast<T>(0); 68 69 Result[2][0] = (static_cast<T>(1) - c) * axis.z * axis.x + s * axis.y; 70 Result[2][1] = (static_cast<T>(1) - c) * axis.z * axis.y - s * axis.x; 71 Result[2][2] = c + (static_cast<T>(1) - c) * axis.z * axis.z; 72 Result[2][3] = static_cast<T>(0); 73 74 Result[3] = vec<4, T, Q>(0, 0, 0, 1); 75 return m * Result; 76 } 77 78 template<typename T, qualifier Q> 79 GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) 80 { 81 mat<4, 4, T, Q> Result; 82 Result[0] = m[0] * v[0]; 83 Result[1] = m[1] * v[1]; 84 Result[2] = m[2] * v[2]; 85 Result[3] = m[3]; 86 return Result; 87 } 88 89 template<typename T, qualifier Q> 90 GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale_slow(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) 91 { 92 mat<4, 4, T, Q> Result(T(1)); 93 Result[0][0] = v.x; 94 Result[1][1] = v.y; 95 Result[2][2] = v.z; 96 return m * Result; 97 } 98 99 template<typename T> 100 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top) 101 { 102 mat<4, 4, T, defaultp> Result(static_cast<T>(1)); 103 Result[0][0] = static_cast<T>(2) / (right - left); 104 Result[1][1] = static_cast<T>(2) / (top - bottom); 105 Result[3][0] = - (right + left) / (right - left); 106 Result[3][1] = - (top + bottom) / (top - bottom); 107 return Result; 108 } 109 110 template<typename T> 111 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_ZO(T left, T right, T bottom, T top, T zNear, T zFar) 112 { 113 mat<4, 4, T, defaultp> Result(1); 114 Result[0][0] = static_cast<T>(2) / (right - left); 115 Result[1][1] = static_cast<T>(2) / (top - bottom); 116 Result[2][2] = static_cast<T>(1) / (zFar - zNear); 117 Result[3][0] = - (right + left) / (right - left); 118 Result[3][1] = - (top + bottom) / (top - bottom); 119 Result[3][2] = - zNear / (zFar - zNear); 120 return Result; 121 } 122 123 template<typename T> 124 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_NO(T left, T right, T bottom, T top, T zNear, T zFar) 125 { 126 mat<4, 4, T, defaultp> Result(1); 127 Result[0][0] = static_cast<T>(2) / (right - left); 128 Result[1][1] = static_cast<T>(2) / (top - bottom); 129 Result[2][2] = static_cast<T>(2) / (zFar - zNear); 130 Result[3][0] = - (right + left) / (right - left); 131 Result[3][1] = - (top + bottom) / (top - bottom); 132 Result[3][2] = - (zFar + zNear) / (zFar - zNear); 133 return Result; 134 } 135 136 template<typename T> 137 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_ZO(T left, T right, T bottom, T top, T zNear, T zFar) 138 { 139 mat<4, 4, T, defaultp> Result(1); 140 Result[0][0] = static_cast<T>(2) / (right - left); 141 Result[1][1] = static_cast<T>(2) / (top - bottom); 142 Result[2][2] = - static_cast<T>(1) / (zFar - zNear); 143 Result[3][0] = - (right + left) / (right - left); 144 Result[3][1] = - (top + bottom) / (top - bottom); 145 Result[3][2] = - zNear / (zFar - zNear); 146 return Result; 147 } 148 149 template<typename T> 150 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_NO(T left, T right, T bottom, T top, T zNear, T zFar) 151 { 152 mat<4, 4, T, defaultp> Result(1); 153 Result[0][0] = static_cast<T>(2) / (right - left); 154 Result[1][1] = static_cast<T>(2) / (top - bottom); 155 Result[2][2] = - static_cast<T>(2) / (zFar - zNear); 156 Result[3][0] = - (right + left) / (right - left); 157 Result[3][1] = - (top + bottom) / (top - bottom); 158 Result[3][2] = - (zFar + zNear) / (zFar - zNear); 159 return Result; 160 } 161 162 template<typename T> 163 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoZO(T left, T right, T bottom, T top, T zNear, T zFar) 164 { 165# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED 166 return orthoLH_ZO(left, right, bottom, top, zNear, zFar); 167# else 168 return orthoRH_ZO(left, right, bottom, top, zNear, zFar); 169# endif 170 } 171 172 template<typename T> 173 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoNO(T left, T right, T bottom, T top, T zNear, T zFar) 174 { 175# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED 176 return orthoLH_NO(left, right, bottom, top, zNear, zFar); 177# else 178 return orthoRH_NO(left, right, bottom, top, zNear, zFar); 179# endif 180 } 181 182 template<typename T> 183 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH(T left, T right, T bottom, T top, T zNear, T zFar) 184 { 185# if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 186 return orthoLH_ZO(left, right, bottom, top, zNear, zFar); 187# else 188 return orthoLH_NO(left, right, bottom, top, zNear, zFar); 189# endif 190 } 191 192 template<typename T> 193 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH(T left, T right, T bottom, T top, T zNear, T zFar) 194 { 195# if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 196 return orthoRH_ZO(left, right, bottom, top, zNear, zFar); 197# else 198 return orthoRH_NO(left, right, bottom, top, zNear, zFar); 199# endif 200 } 201 202 template<typename T> 203 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top, T zNear, T zFar) 204 { 205# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 206 return orthoLH_ZO(left, right, bottom, top, zNear, zFar); 207# elif GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE 208 return orthoLH_NO(left, right, bottom, top, zNear, zFar); 209# elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 210 return orthoRH_ZO(left, right, bottom, top, zNear, zFar); 211# elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE 212 return orthoRH_NO(left, right, bottom, top, zNear, zFar); 213# endif 214 } 215 216 template<typename T> 217 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal) 218 { 219 mat<4, 4, T, defaultp> Result(0); 220 Result[0][0] = (static_cast<T>(2) * nearVal) / (right - left); 221 Result[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom); 222 Result[2][0] = (right + left) / (right - left); 223 Result[2][1] = (top + bottom) / (top - bottom); 224 Result[2][2] = farVal / (farVal - nearVal); 225 Result[2][3] = static_cast<T>(1); 226 Result[3][2] = -(farVal * nearVal) / (farVal - nearVal); 227 return Result; 228 } 229 230 template<typename T> 231 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_NO(T left, T right, T bottom, T top, T nearVal, T farVal) 232 { 233 mat<4, 4, T, defaultp> Result(0); 234 Result[0][0] = (static_cast<T>(2) * nearVal) / (right - left); 235 Result[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom); 236 Result[2][0] = (right + left) / (right - left); 237 Result[2][1] = (top + bottom) / (top - bottom); 238 Result[2][2] = (farVal + nearVal) / (farVal - nearVal); 239 Result[2][3] = static_cast<T>(1); 240 Result[3][2] = - (static_cast<T>(2) * farVal * nearVal) / (farVal - nearVal); 241 return Result; 242 } 243 244 template<typename T> 245 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal) 246 { 247 mat<4, 4, T, defaultp> Result(0); 248 Result[0][0] = (static_cast<T>(2) * nearVal) / (right - left); 249 Result[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom); 250 Result[2][0] = (right + left) / (right - left); 251 Result[2][1] = (top + bottom) / (top - bottom); 252 Result[2][2] = farVal / (nearVal - farVal); 253 Result[2][3] = static_cast<T>(-1); 254 Result[3][2] = -(farVal * nearVal) / (farVal - nearVal); 255 return Result; 256 } 257 258 template<typename T> 259 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_NO(T left, T right, T bottom, T top, T nearVal, T farVal) 260 { 261 mat<4, 4, T, defaultp> Result(0); 262 Result[0][0] = (static_cast<T>(2) * nearVal) / (right - left); 263 Result[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom); 264 Result[2][0] = (right + left) / (right - left); 265 Result[2][1] = (top + bottom) / (top - bottom); 266 Result[2][2] = - (farVal + nearVal) / (farVal - nearVal); 267 Result[2][3] = static_cast<T>(-1); 268 Result[3][2] = - (static_cast<T>(2) * farVal * nearVal) / (farVal - nearVal); 269 return Result; 270 } 271 272 template<typename T> 273 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumZO(T left, T right, T bottom, T top, T nearVal, T farVal) 274 { 275# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED 276 return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); 277# else 278 return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); 279# endif 280 } 281 282 template<typename T> 283 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumNO(T left, T right, T bottom, T top, T nearVal, T farVal) 284 { 285# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED 286 return frustumLH_NO(left, right, bottom, top, nearVal, farVal); 287# else 288 return frustumRH_NO(left, right, bottom, top, nearVal, farVal); 289# endif 290 } 291 292 template<typename T> 293 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH(T left, T right, T bottom, T top, T nearVal, T farVal) 294 { 295# if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 296 return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); 297# else 298 return frustumLH_NO(left, right, bottom, top, nearVal, farVal); 299# endif 300 } 301 302 template<typename T> 303 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH(T left, T right, T bottom, T top, T nearVal, T farVal) 304 { 305# if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 306 return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); 307# else 308 return frustumRH_NO(left, right, bottom, top, nearVal, farVal); 309# endif 310 } 311 312 template<typename T> 313 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustum(T left, T right, T bottom, T top, T nearVal, T farVal) 314 { 315# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 316 return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); 317# elif GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE 318 return frustumLH_NO(left, right, bottom, top, nearVal, farVal); 319# elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 320 return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); 321# elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE 322 return frustumRH_NO(left, right, bottom, top, nearVal, farVal); 323# endif 324 } 325 326 template<typename T> 327 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_ZO(T fovy, T aspect, T zNear, T zFar) 328 { 329 assert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0)); 330 331 T const tanHalfFovy = tan(fovy / static_cast<T>(2)); 332 333 mat<4, 4, T, defaultp> Result(static_cast<T>(0)); 334 Result[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy); 335 Result[1][1] = static_cast<T>(1) / (tanHalfFovy); 336 Result[2][2] = zFar / (zNear - zFar); 337 Result[2][3] = - static_cast<T>(1); 338 Result[3][2] = -(zFar * zNear) / (zFar - zNear); 339 return Result; 340 } 341 342 template<typename T> 343 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_NO(T fovy, T aspect, T zNear, T zFar) 344 { 345 assert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0)); 346 347 T const tanHalfFovy = tan(fovy / static_cast<T>(2)); 348 349 mat<4, 4, T, defaultp> Result(static_cast<T>(0)); 350 Result[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy); 351 Result[1][1] = static_cast<T>(1) / (tanHalfFovy); 352 Result[2][2] = - (zFar + zNear) / (zFar - zNear); 353 Result[2][3] = - static_cast<T>(1); 354 Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear); 355 return Result; 356 } 357 358 template<typename T> 359 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_ZO(T fovy, T aspect, T zNear, T zFar) 360 { 361 assert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0)); 362 363 T const tanHalfFovy = tan(fovy / static_cast<T>(2)); 364 365 mat<4, 4, T, defaultp> Result(static_cast<T>(0)); 366 Result[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy); 367 Result[1][1] = static_cast<T>(1) / (tanHalfFovy); 368 Result[2][2] = zFar / (zFar - zNear); 369 Result[2][3] = static_cast<T>(1); 370 Result[3][2] = -(zFar * zNear) / (zFar - zNear); 371 return Result; 372 } 373 374 template<typename T> 375 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_NO(T fovy, T aspect, T zNear, T zFar) 376 { 377 assert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0)); 378 379 T const tanHalfFovy = tan(fovy / static_cast<T>(2)); 380 381 mat<4, 4, T, defaultp> Result(static_cast<T>(0)); 382 Result[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy); 383 Result[1][1] = static_cast<T>(1) / (tanHalfFovy); 384 Result[2][2] = (zFar + zNear) / (zFar - zNear); 385 Result[2][3] = static_cast<T>(1); 386 Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear); 387 return Result; 388 } 389 390 template<typename T> 391 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveZO(T fovy, T aspect, T zNear, T zFar) 392 { 393# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED 394 return perspectiveLH_ZO(fovy, aspect, zNear, zFar); 395# else 396 return perspectiveRH_ZO(fovy, aspect, zNear, zFar); 397# endif 398 } 399 400 template<typename T> 401 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveNO(T fovy, T aspect, T zNear, T zFar) 402 { 403# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED 404 return perspectiveLH_NO(fovy, aspect, zNear, zFar); 405# else 406 return perspectiveRH_NO(fovy, aspect, zNear, zFar); 407# endif 408 } 409 410 template<typename T> 411 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH(T fovy, T aspect, T zNear, T zFar) 412 { 413# if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 414 return perspectiveLH_ZO(fovy, aspect, zNear, zFar); 415# else 416 return perspectiveLH_NO(fovy, aspect, zNear, zFar); 417# endif 418 } 419 420 template<typename T> 421 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH(T fovy, T aspect, T zNear, T zFar) 422 { 423# if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 424 return perspectiveRH_ZO(fovy, aspect, zNear, zFar); 425# else 426 return perspectiveRH_NO(fovy, aspect, zNear, zFar); 427# endif 428 } 429 430 template<typename T> 431 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspective(T fovy, T aspect, T zNear, T zFar) 432 { 433# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 434 return perspectiveLH_ZO(fovy, aspect, zNear, zFar); 435# elif GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE 436 return perspectiveLH_NO(fovy, aspect, zNear, zFar); 437# elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 438 return perspectiveRH_ZO(fovy, aspect, zNear, zFar); 439# elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE 440 return perspectiveRH_NO(fovy, aspect, zNear, zFar); 441# endif 442 } 443 444 template<typename T> 445 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_ZO(T fov, T width, T height, T zNear, T zFar) 446 { 447 assert(width > static_cast<T>(0)); 448 assert(height > static_cast<T>(0)); 449 assert(fov > static_cast<T>(0)); 450 451 T const rad = fov; 452 T const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad); 453 T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? 454 455 mat<4, 4, T, defaultp> Result(static_cast<T>(0)); 456 Result[0][0] = w; 457 Result[1][1] = h; 458 Result[2][2] = zFar / (zNear - zFar); 459 Result[2][3] = - static_cast<T>(1); 460 Result[3][2] = -(zFar * zNear) / (zFar - zNear); 461 return Result; 462 } 463 464 template<typename T> 465 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_NO(T fov, T width, T height, T zNear, T zFar) 466 { 467 assert(width > static_cast<T>(0)); 468 assert(height > static_cast<T>(0)); 469 assert(fov > static_cast<T>(0)); 470 471 T const rad = fov; 472 T const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad); 473 T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? 474 475 mat<4, 4, T, defaultp> Result(static_cast<T>(0)); 476 Result[0][0] = w; 477 Result[1][1] = h; 478 Result[2][2] = - (zFar + zNear) / (zFar - zNear); 479 Result[2][3] = - static_cast<T>(1); 480 Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear); 481 return Result; 482 } 483 484 template<typename T> 485 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_ZO(T fov, T width, T height, T zNear, T zFar) 486 { 487 assert(width > static_cast<T>(0)); 488 assert(height > static_cast<T>(0)); 489 assert(fov > static_cast<T>(0)); 490 491 T const rad = fov; 492 T const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad); 493 T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? 494 495 mat<4, 4, T, defaultp> Result(static_cast<T>(0)); 496 Result[0][0] = w; 497 Result[1][1] = h; 498 Result[2][2] = zFar / (zFar - zNear); 499 Result[2][3] = static_cast<T>(1); 500 Result[3][2] = -(zFar * zNear) / (zFar - zNear); 501 return Result; 502 } 503 504 template<typename T> 505 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_NO(T fov, T width, T height, T zNear, T zFar) 506 { 507 assert(width > static_cast<T>(0)); 508 assert(height > static_cast<T>(0)); 509 assert(fov > static_cast<T>(0)); 510 511 T const rad = fov; 512 T const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad); 513 T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? 514 515 mat<4, 4, T, defaultp> Result(static_cast<T>(0)); 516 Result[0][0] = w; 517 Result[1][1] = h; 518 Result[2][2] = (zFar + zNear) / (zFar - zNear); 519 Result[2][3] = static_cast<T>(1); 520 Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear); 521 return Result; 522 } 523 524 template<typename T> 525 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovZO(T fov, T width, T height, T zNear, T zFar) 526 { 527# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED 528 return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); 529# else 530 return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); 531# endif 532 } 533 534 template<typename T> 535 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovNO(T fov, T width, T height, T zNear, T zFar) 536 { 537# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED 538 return perspectiveFovLH_NO(fov, width, height, zNear, zFar); 539# else 540 return perspectiveFovRH_NO(fov, width, height, zNear, zFar); 541# endif 542 } 543 544 template<typename T> 545 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH(T fov, T width, T height, T zNear, T zFar) 546 { 547# if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 548 return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); 549# else 550 return perspectiveFovLH_NO(fov, width, height, zNear, zFar); 551# endif 552 } 553 554 template<typename T> 555 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH(T fov, T width, T height, T zNear, T zFar) 556 { 557# if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 558 return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); 559# else 560 return perspectiveFovRH_NO(fov, width, height, zNear, zFar); 561# endif 562 } 563 564 template<typename T> 565 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFov(T fov, T width, T height, T zNear, T zFar) 566 { 567# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 568 return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); 569# elif GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE 570 return perspectiveFovLH_NO(fov, width, height, zNear, zFar); 571# elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 572 return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); 573# elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE 574 return perspectiveFovRH_NO(fov, width, height, zNear, zFar); 575# endif 576 } 577 578 template<typename T> 579 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveRH(T fovy, T aspect, T zNear) 580 { 581 T const range = tan(fovy / static_cast<T>(2)) * zNear; 582 T const left = -range * aspect; 583 T const right = range * aspect; 584 T const bottom = -range; 585 T const top = range; 586 587 mat<4, 4, T, defaultp> Result(static_cast<T>(0)); 588 Result[0][0] = (static_cast<T>(2) * zNear) / (right - left); 589 Result[1][1] = (static_cast<T>(2) * zNear) / (top - bottom); 590 Result[2][2] = - static_cast<T>(1); 591 Result[2][3] = - static_cast<T>(1); 592 Result[3][2] = - static_cast<T>(2) * zNear; 593 return Result; 594 } 595 596 template<typename T> 597 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveLH(T fovy, T aspect, T zNear) 598 { 599 T const range = tan(fovy / static_cast<T>(2)) * zNear; 600 T const left = -range * aspect; 601 T const right = range * aspect; 602 T const bottom = -range; 603 T const top = range; 604 605 mat<4, 4, T, defaultp> Result(T(0)); 606 Result[0][0] = (static_cast<T>(2) * zNear) / (right - left); 607 Result[1][1] = (static_cast<T>(2) * zNear) / (top - bottom); 608 Result[2][2] = static_cast<T>(1); 609 Result[2][3] = static_cast<T>(1); 610 Result[3][2] = - static_cast<T>(2) * zNear; 611 return Result; 612 } 613 614 template<typename T> 615 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspective(T fovy, T aspect, T zNear) 616 { 617# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED 618 return infinitePerspectiveLH(fovy, aspect, zNear); 619# else 620 return infinitePerspectiveRH(fovy, aspect, zNear); 621# endif 622 } 623 624 // Infinite projection matrix: http://www.terathon.com/gdc07_lengyel.pdf 625 template<typename T> 626 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear, T ep) 627 { 628 T const range = tan(fovy / static_cast<T>(2)) * zNear; 629 T const left = -range * aspect; 630 T const right = range * aspect; 631 T const bottom = -range; 632 T const top = range; 633 634 mat<4, 4, T, defaultp> Result(static_cast<T>(0)); 635 Result[0][0] = (static_cast<T>(2) * zNear) / (right - left); 636 Result[1][1] = (static_cast<T>(2) * zNear) / (top - bottom); 637 Result[2][2] = ep - static_cast<T>(1); 638 Result[2][3] = static_cast<T>(-1); 639 Result[3][2] = (ep - static_cast<T>(2)) * zNear; 640 return Result; 641 } 642 643 template<typename T> 644 GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear) 645 { 646 return tweakedInfinitePerspective(fovy, aspect, zNear, epsilon<T>()); 647 } 648 649 template<typename T, typename U, qualifier Q> 650 GLM_FUNC_QUALIFIER vec<3, T, Q> projectZO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) 651 { 652 vec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast<T>(1)); 653 tmp = model * tmp; 654 tmp = proj * tmp; 655 656 tmp /= tmp.w; 657 tmp.x = tmp.x * static_cast<T>(0.5) + static_cast<T>(0.5); 658 tmp.y = tmp.y * static_cast<T>(0.5) + static_cast<T>(0.5); 659 660 tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]); 661 tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]); 662 663 return vec<3, T, Q>(tmp); 664 } 665 666 template<typename T, typename U, qualifier Q> 667 GLM_FUNC_QUALIFIER vec<3, T, Q> projectNO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) 668 { 669 vec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast<T>(1)); 670 tmp = model * tmp; 671 tmp = proj * tmp; 672 673 tmp /= tmp.w; 674 tmp = tmp * static_cast<T>(0.5) + static_cast<T>(0.5); 675 tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]); 676 tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]); 677 678 return vec<3, T, Q>(tmp); 679 } 680 681 template<typename T, typename U, qualifier Q> 682 GLM_FUNC_QUALIFIER vec<3, T, Q> project(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) 683 { 684# if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 685 return projectZO(obj, model, proj, viewport); 686# else 687 return projectNO(obj, model, proj, viewport); 688# endif 689 } 690 691 template<typename T, typename U, qualifier Q> 692 GLM_FUNC_QUALIFIER vec<3, T, Q> unProjectZO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) 693 { 694 mat<4, 4, T, Q> Inverse = inverse(proj * model); 695 696 vec<4, T, Q> tmp = vec<4, T, Q>(win, T(1)); 697 tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]); 698 tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]); 699 tmp.x = tmp.x * static_cast<T>(2) - static_cast<T>(1); 700 tmp.y = tmp.y * static_cast<T>(2) - static_cast<T>(1); 701 702 vec<4, T, Q> obj = Inverse * tmp; 703 obj /= obj.w; 704 705 return vec<3, T, Q>(obj); 706 } 707 708 template<typename T, typename U, qualifier Q> 709 GLM_FUNC_QUALIFIER vec<3, T, Q> unProjectNO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) 710 { 711 mat<4, 4, T, Q> Inverse = inverse(proj * model); 712 713 vec<4, T, Q> tmp = vec<4, T, Q>(win, T(1)); 714 tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]); 715 tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]); 716 tmp = tmp * static_cast<T>(2) - static_cast<T>(1); 717 718 vec<4, T, Q> obj = Inverse * tmp; 719 obj /= obj.w; 720 721 return vec<3, T, Q>(obj); 722 } 723 724 template<typename T, typename U, qualifier Q> 725 GLM_FUNC_QUALIFIER vec<3, T, Q> unProject(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) 726 { 727# if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE 728 return unProjectZO(win, model, proj, viewport); 729# else 730 return unProjectNO(win, model, proj, viewport); 731# endif 732 } 733 734 template<typename T, qualifier Q, typename U> 735 GLM_FUNC_QUALIFIER mat<4, 4, T, Q> pickMatrix(vec<2, T, Q> const& center, vec<2, T, Q> const& delta, vec<4, U, Q> const& viewport) 736 { 737 assert(delta.x > static_cast<T>(0) && delta.y > static_cast<T>(0)); 738 mat<4, 4, T, Q> Result(static_cast<T>(1)); 739 740 if(!(delta.x > static_cast<T>(0) && delta.y > static_cast<T>(0))) 741 return Result; // Error 742 743 vec<3, T, Q> Temp( 744 (static_cast<T>(viewport[2]) - static_cast<T>(2) * (center.x - static_cast<T>(viewport[0]))) / delta.x, 745 (static_cast<T>(viewport[3]) - static_cast<T>(2) * (center.y - static_cast<T>(viewport[1]))) / delta.y, 746 static_cast<T>(0)); 747 748 // Translate and scale the picked region to the entire window 749 Result = translate(Result, Temp); 750 return scale(Result, vec<3, T, Q>(static_cast<T>(viewport[2]) / delta.x, static_cast<T>(viewport[3]) / delta.y, static_cast<T>(1))); 751 } 752 753 template<typename T, qualifier Q> 754 GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtRH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) 755 { 756 vec<3, T, Q> const f(normalize(center - eye)); 757 vec<3, T, Q> const s(normalize(cross(f, up))); 758 vec<3, T, Q> const u(cross(s, f)); 759 760 mat<4, 4, T, Q> Result(1); 761 Result[0][0] = s.x; 762 Result[1][0] = s.y; 763 Result[2][0] = s.z; 764 Result[0][1] = u.x; 765 Result[1][1] = u.y; 766 Result[2][1] = u.z; 767 Result[0][2] =-f.x; 768 Result[1][2] =-f.y; 769 Result[2][2] =-f.z; 770 Result[3][0] =-dot(s, eye); 771 Result[3][1] =-dot(u, eye); 772 Result[3][2] = dot(f, eye); 773 return Result; 774 } 775 776 template<typename T, qualifier Q> 777 GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtLH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) 778 { 779 vec<3, T, Q> const f(normalize(center - eye)); 780 vec<3, T, Q> const s(normalize(cross(up, f))); 781 vec<3, T, Q> const u(cross(f, s)); 782 783 mat<4, 4, T, Q> Result(1); 784 Result[0][0] = s.x; 785 Result[1][0] = s.y; 786 Result[2][0] = s.z; 787 Result[0][1] = u.x; 788 Result[1][1] = u.y; 789 Result[2][1] = u.z; 790 Result[0][2] = f.x; 791 Result[1][2] = f.y; 792 Result[2][2] = f.z; 793 Result[3][0] = -dot(s, eye); 794 Result[3][1] = -dot(u, eye); 795 Result[3][2] = -dot(f, eye); 796 return Result; 797 } 798 799 template<typename T, qualifier Q> 800 GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAt(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) 801 { 802# if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED 803 return lookAtLH(eye, center, up); 804# else 805 return lookAtRH(eye, center, up); 806# endif 807 } 808}//namespace glm 809