|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma once |
|
|
|
|
|
#include <cmath> |
|
|
#include <float.h> |
|
|
#include <cassert> |
|
|
#include <string.h> |
|
|
|
|
|
#include "core.h" |
|
|
#include "types.h" |
|
|
|
|
|
#ifdef __CUDACC__ |
|
|
#define CUDA_CALLABLE __host__ __device__ |
|
|
#else |
|
|
#define CUDA_CALLABLE |
|
|
#endif |
|
|
|
|
|
const float kPi = 3.141592653589f; |
|
|
const float k2Pi = 2.0f*kPi; |
|
|
const float kInvPi = 1.0f/kPi; |
|
|
const float kInv2Pi = 0.5f/kPi; |
|
|
const float kDegToRad = kPi/180.0f; |
|
|
const float kRadToDeg = 180.0f/kPi; |
|
|
|
|
|
CUDA_CALLABLE inline float DegToRad(float t) |
|
|
{ |
|
|
return t * kDegToRad; |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float RadToDeg(float t) |
|
|
{ |
|
|
return t * kRadToDeg; |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float Sin(float theta) |
|
|
{ |
|
|
return sinf(theta); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float Cos(float theta) |
|
|
{ |
|
|
return cosf(theta); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline void SinCos(float theta, float& s, float& c) |
|
|
{ |
|
|
|
|
|
s = sinf(theta); |
|
|
c = cosf(theta); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float Tan(float theta) |
|
|
{ |
|
|
return tanf(theta); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float Sqrt(float x) |
|
|
{ |
|
|
return sqrtf(x); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline double Sqrt(double x) |
|
|
{ |
|
|
return sqrt(x); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float ASin(float theta) |
|
|
{ |
|
|
return asinf(theta); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float ACos(float theta) |
|
|
{ |
|
|
return acosf(theta); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float ATan(float theta) |
|
|
{ |
|
|
return atanf(theta); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float ATan2(float x, float y) |
|
|
{ |
|
|
return atan2f(x, y); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float Abs(float x) |
|
|
{ |
|
|
return fabsf(x); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float Pow(float b, float e) |
|
|
{ |
|
|
return powf(b, e); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float Sgn(float x) |
|
|
{ |
|
|
return (x < 0.0f ? -1.0f : 1.0f); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float Sign(float x) |
|
|
{ |
|
|
return x < 0.0f ? -1.0f : 1.0f; |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline double Sign(double x) |
|
|
{ |
|
|
return x < 0.0f ? -1.0f : 1.0f; |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float Mod(float x, float y) |
|
|
{ |
|
|
return fmod(x, y); |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE inline T Min(T a, T b) |
|
|
{ |
|
|
return a < b ? a : b; |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE inline T Max(T a, T b) |
|
|
{ |
|
|
return a > b ? a : b; |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE inline void Swap(T& a, T& b) |
|
|
{ |
|
|
T tmp = a; |
|
|
a = b; |
|
|
b = tmp; |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE inline T Clamp(T a, T low, T high) |
|
|
{ |
|
|
if (low > high) |
|
|
Swap(low, high); |
|
|
|
|
|
return Max(low, Min(a, high)); |
|
|
} |
|
|
|
|
|
template <typename V, typename T> |
|
|
CUDA_CALLABLE inline V Lerp(const V& start, const V& end, const T& t) |
|
|
{ |
|
|
return start + (end-start)*t; |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float InvSqrt(float x) |
|
|
{ |
|
|
return 1.0f / sqrtf(x); |
|
|
} |
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline int Round(float f) |
|
|
{ |
|
|
return int(f+0.5f); |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE T Normalize(const T& v) |
|
|
{ |
|
|
T a(v); |
|
|
a /= Length(v); |
|
|
return a; |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE inline typename T::value_type LengthSq(const T v) |
|
|
{ |
|
|
return Dot(v,v); |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE inline typename T::value_type Length(const T& v) |
|
|
{ |
|
|
typename T::value_type lSq = LengthSq(v); |
|
|
if (lSq) |
|
|
return Sqrt(LengthSq(v)); |
|
|
else |
|
|
return 0.0f; |
|
|
} |
|
|
|
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE inline typename T::value_type Distance(const T& v1, const T& v2) |
|
|
{ |
|
|
return Length(v1-v2); |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE inline T SafeNormalize(const T& v, const T& fallback=T()) |
|
|
{ |
|
|
float l = LengthSq(v); |
|
|
if (l > 0.0f) |
|
|
{ |
|
|
return v * InvSqrt(l); |
|
|
} |
|
|
else |
|
|
return fallback; |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE inline T Sqr(T x) { return x*x; } |
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE inline T Cube(T x) { return x*x*x; } |
|
|
|
|
|
#include "vec2.h" |
|
|
#include "vec3.h" |
|
|
#include "vec4.h" |
|
|
#include "quat.h" |
|
|
#include "point3.h" |
|
|
#include "mat22.h" |
|
|
#include "mat33.h" |
|
|
#include "mat44.h" |
|
|
#include "matnn.h" |
|
|
|
|
|
|
|
|
class Plane : public Vec4 |
|
|
{ |
|
|
public: |
|
|
|
|
|
CUDA_CALLABLE inline Plane() {} |
|
|
CUDA_CALLABLE inline Plane(float x, float y, float z, float w) : Vec4(x, y, z, w) {} |
|
|
CUDA_CALLABLE inline Plane(const Vec3& p, const Vector3& n) |
|
|
{ |
|
|
x = n.x; |
|
|
y = n.y; |
|
|
z = n.z; |
|
|
w = -Dot3(p, n); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline Vec3 GetNormal() const { return Vec3(x, y, z); } |
|
|
CUDA_CALLABLE inline Vec3 GetPoint() const { return Vec3(x*-w, y*-w, z*-w); } |
|
|
|
|
|
CUDA_CALLABLE inline Plane(const Vec3& v) : Vec4(v.x, v.y, v.z, 1.0f) {} |
|
|
CUDA_CALLABLE inline Plane(const Vec4& v) : Vec4(v) {} |
|
|
}; |
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE inline T Dot(const XVector4<T>& v1, const XVector4<T>& v2) |
|
|
{ |
|
|
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w; |
|
|
} |
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline float Dot(const Plane& p, const Vector3& v) |
|
|
{ |
|
|
return p.x*v.x + p.y*v.y + p.z*v.z; |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float Dot(const Vector3& v, const Plane& p) |
|
|
{ |
|
|
return Dot(p, v); |
|
|
} |
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline float Dot(const Plane& p, const Point3& v) |
|
|
{ |
|
|
return p.x*v.x + p.y*v.y + p.z*v.z + p.w; |
|
|
} |
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline Vec4 NormalizePlane(const Vec4& p) |
|
|
{ |
|
|
float l = Length(Vec3(p)); |
|
|
|
|
|
return (1.0f/l)*p; |
|
|
} |
|
|
|
|
|
|
|
|
inline float RandomUnit() |
|
|
{ |
|
|
float r = (float)rand(); |
|
|
r /= RAND_MAX; |
|
|
return r; |
|
|
} |
|
|
|
|
|
|
|
|
inline float RandomSignedUnit() |
|
|
{ |
|
|
float r = (float)rand(); |
|
|
r /= RAND_MAX; |
|
|
r = 2.0f * r - 1.0f; |
|
|
return r; |
|
|
} |
|
|
|
|
|
inline float Random(float lo, float hi) |
|
|
{ |
|
|
float r = (float)rand(); |
|
|
r /= RAND_MAX; |
|
|
r = (hi - lo) * r + lo; |
|
|
return r; |
|
|
} |
|
|
|
|
|
extern uint32_t seed1; |
|
|
extern uint32_t seed2; |
|
|
|
|
|
void RandInit(); |
|
|
|
|
|
|
|
|
inline uint32_t Rand() |
|
|
{ |
|
|
seed1 = ( seed2 ^ ( ( seed1 << 5 ) | ( seed1 >> 27 ) ) ) ^ ( seed1*seed2 ); |
|
|
seed2 = seed1 ^ ( ( seed2 << 12 ) | ( seed2 >> 20 ) ); |
|
|
|
|
|
return seed1; |
|
|
} |
|
|
|
|
|
|
|
|
inline uint32_t Rand(uint32_t min, uint32_t max) |
|
|
{ |
|
|
return min + Rand()%(max-min); |
|
|
} |
|
|
|
|
|
|
|
|
inline float Randf() |
|
|
{ |
|
|
uint32_t value = Rand(); |
|
|
uint32_t limit = 0xffffffff; |
|
|
|
|
|
return ( float )value*( 1.0f/( float )limit ); |
|
|
} |
|
|
|
|
|
|
|
|
inline float Randf(float min, float max) |
|
|
{ |
|
|
|
|
|
float t = Randf(); |
|
|
return (1.0f-t)*min + t*(max); |
|
|
} |
|
|
|
|
|
|
|
|
inline float Randf(float max) |
|
|
{ |
|
|
return Randf()*max; |
|
|
} |
|
|
|
|
|
|
|
|
inline Vec3 RandomUnitVector() |
|
|
{ |
|
|
float phi = Randf(kPi*2.0f); |
|
|
float theta = Randf(kPi*2.0f); |
|
|
|
|
|
float cosTheta = Cos(theta); |
|
|
float sinTheta = Sin(theta); |
|
|
|
|
|
float cosPhi = Cos(phi); |
|
|
float sinPhi = Sin(phi); |
|
|
|
|
|
return Vec3(cosTheta*sinPhi,cosPhi,sinTheta*sinPhi); |
|
|
} |
|
|
|
|
|
inline Vec3 RandVec3() { return Vec3(Randf(-1.0f, 1.0f), Randf(-1.0f, 1.0f), Randf(-1.0f, 1.0f)); } |
|
|
|
|
|
|
|
|
inline Vec3 UniformSampleSphereVolume() |
|
|
{ |
|
|
for(;;) |
|
|
{ |
|
|
Vec3 v = RandVec3(); |
|
|
if (Dot(v, v) < 1.0f) |
|
|
return v; |
|
|
} |
|
|
} |
|
|
|
|
|
inline Vec3 UniformSampleSphere() |
|
|
{ |
|
|
float u1 = Randf(0.0f, 1.0f); |
|
|
float u2 = Randf(0.0f, 1.0f); |
|
|
|
|
|
float z = 1.f - 2.f * u1; |
|
|
float r = sqrtf(Max(0.f, 1.f - z*z)); |
|
|
float phi = 2.f * kPi * u2; |
|
|
float x = r * cosf(phi); |
|
|
float y = r * sinf(phi); |
|
|
|
|
|
return Vector3(x, y, z); |
|
|
} |
|
|
|
|
|
inline Vec3 UniformSampleHemisphere() |
|
|
{ |
|
|
|
|
|
float z = Randf(0.0f, 1.0f); |
|
|
float w = Sqrt(1.0f-z*z); |
|
|
|
|
|
float phi = k2Pi*Randf(0.0f, 1.0f); |
|
|
float x = Cos(phi)*w; |
|
|
float y = Sin(phi)*w; |
|
|
|
|
|
return Vec3(x, y, z); |
|
|
} |
|
|
|
|
|
inline Vec2 UniformSampleDisc() |
|
|
{ |
|
|
float r = Sqrt(Randf(0.0f, 1.0f)); |
|
|
float theta = k2Pi*Randf(0.0f, 1.0f); |
|
|
|
|
|
return Vec2(r * Cos(theta), r * Sin(theta)); |
|
|
} |
|
|
|
|
|
inline void UniformSampleTriangle(float& u, float& v) |
|
|
{ |
|
|
float r = Sqrt(Randf()); |
|
|
u = 1.0f - r; |
|
|
v = Randf() * r; |
|
|
} |
|
|
|
|
|
inline Vec3 CosineSampleHemisphere() |
|
|
{ |
|
|
Vec2 s = UniformSampleDisc(); |
|
|
float z = Sqrt(Max(0.0f, 1.0f - s.x*s.x - s.y*s.y)); |
|
|
|
|
|
return Vec3(s.x, s.y, z); |
|
|
} |
|
|
|
|
|
inline Vec3 SphericalToXYZ(float theta, float phi) |
|
|
{ |
|
|
float cosTheta = cos(theta); |
|
|
float sinTheta = sin(theta); |
|
|
|
|
|
return Vec3(sin(phi)*sinTheta, cosTheta, cos(phi)*sinTheta); |
|
|
} |
|
|
|
|
|
|
|
|
inline Vec4 Randf(const Vec4 &range) |
|
|
{ |
|
|
return Vec4(Randf(-range.x, range.x), |
|
|
Randf(-range.y, range.y), |
|
|
Randf(-range.z, range.z), |
|
|
Randf(-range.w, range.w)); |
|
|
} |
|
|
|
|
|
|
|
|
inline void BasisFromVector(const Vec3& w, Vec3* u, Vec3* v) |
|
|
{ |
|
|
if (fabsf(w.x) > fabsf(w.y)) |
|
|
{ |
|
|
float invLen = 1.0f / sqrtf(w.x*w.x + w.z*w.z); |
|
|
*u = Vec3(-w.z*invLen, 0.0f, w.x*invLen); |
|
|
} |
|
|
else |
|
|
{ |
|
|
float invLen = 1.0f / sqrtf(w.y*w.y + w.z*w.z); |
|
|
*u = Vec3(0.0f, w.z*invLen, -w.y*invLen); |
|
|
} |
|
|
|
|
|
*v = Cross(w, *u); |
|
|
|
|
|
assert(fabsf(Length(*u)-1.0f) < 0.01f); |
|
|
assert(fabsf(Length(*v)-1.0f) < 0.01f); |
|
|
} |
|
|
|
|
|
|
|
|
inline Mat44 TransformFromVector(const Vec3& w, const Point3& t=Point3(0.0f, 0.0f, 0.0f)) |
|
|
{ |
|
|
Mat44 m = Mat44::kIdentity; |
|
|
m.SetCol(2, Vec4(w.x, w.y, w.z, 0.0)); |
|
|
m.SetCol(3, Vec4(t.x, t.y, t.z, 1.0f)); |
|
|
|
|
|
BasisFromVector(w, (Vec3*)m.columns[0], (Vec3*)m.columns[1]); |
|
|
|
|
|
return m; |
|
|
} |
|
|
|
|
|
|
|
|
inline Mat44 ViewMatrix(const Point3& pos) |
|
|
{ |
|
|
|
|
|
float view[4][4] = { { 1.0f, 0.0f, 0.0f, 0.0f }, |
|
|
{ 0.0f, 1.0f, 0.0f, 0.0f }, |
|
|
{ 0.0f, 0.0f, 1.0f, 0.0f }, |
|
|
{ -pos.x, -pos.y, -pos.z, 1.0f } }; |
|
|
|
|
|
return Mat44(&view[0][0]); |
|
|
} |
|
|
|
|
|
|
|
|
inline Mat44 LookAtMatrix(const Point3& viewer, const Point3& target) |
|
|
{ |
|
|
|
|
|
Vec3 forward = -Normalize(target-viewer); |
|
|
Vec3 up(0.0f, 1.0f, 0.0f); |
|
|
Vec3 left = Normalize(Cross(up, forward)); |
|
|
up = Cross(forward, left); |
|
|
|
|
|
float xform[4][4] = { { left.x, left.y, left.z, 0.0f }, |
|
|
{ up.x, up.y, up.z, 0.0f}, |
|
|
{ forward.x, forward.y, forward.z, 0.0f}, |
|
|
{ viewer.x, viewer.y, viewer.z, 1.0f} }; |
|
|
|
|
|
return AffineInverse(Mat44(&xform[0][0])); |
|
|
} |
|
|
|
|
|
|
|
|
inline Mat44 RotationMatrix(float angle, const Vec3& axis) |
|
|
{ |
|
|
Vec3 a = Normalize(axis); |
|
|
float s = sinf(angle); |
|
|
float c = cosf(angle); |
|
|
|
|
|
float m[4][4]; |
|
|
|
|
|
m[0][0] = a.x * a.x + (1.0f - a.x * a.x) * c; |
|
|
m[0][1] = a.x * a.y * (1.0f - c) + a.z * s; |
|
|
m[0][2] = a.x * a.z * (1.0f - c) - a.y * s; |
|
|
m[0][3] = 0.0f; |
|
|
|
|
|
m[1][0] = a.x * a.y * (1.0f - c) - a.z * s; |
|
|
m[1][1] = a.y * a.y + (1.0f - a.y * a.y) * c; |
|
|
m[1][2] = a.y * a.z * (1.0f - c) + a.x * s; |
|
|
m[1][3] = 0.0f; |
|
|
|
|
|
m[2][0] = a.x * a.z * (1.0f - c) + a.y * s; |
|
|
m[2][1] = a.y * a.z * (1.0f - c) - a.x * s; |
|
|
m[2][2] = a.z * a.z + (1.0f - a.z * a.z) * c; |
|
|
m[2][3] = 0.0f; |
|
|
|
|
|
m[3][0] = 0.0f; |
|
|
m[3][1] = 0.0f; |
|
|
m[3][2] = 0.0f; |
|
|
m[3][3] = 1.0f; |
|
|
|
|
|
return Mat44(&m[0][0]); |
|
|
} |
|
|
|
|
|
inline Mat44 RotationMatrix(Quat q) |
|
|
{ |
|
|
Matrix33 rotation(q); |
|
|
|
|
|
Matrix44 m; |
|
|
m.SetAxis(0, rotation.cols[0]); |
|
|
m.SetAxis(1, rotation.cols[1]); |
|
|
m.SetAxis(2, rotation.cols[2]); |
|
|
m.SetTranslation(Point3(0.0f)); |
|
|
|
|
|
return m; |
|
|
} |
|
|
|
|
|
inline Mat44 TranslationMatrix(const Point3& t) |
|
|
{ |
|
|
Mat44 m(Mat44::kIdentity); |
|
|
m.SetTranslation(t); |
|
|
return m; |
|
|
} |
|
|
|
|
|
inline Mat44 OrthographicMatrix(float left, float right, float bottom, float top, float n, float f) |
|
|
{ |
|
|
|
|
|
float m[4][4] = { { 2.0f/(right-left), 0.0f, 0.0f, 0.0f }, |
|
|
{ 0.0f, 2.0f/(top-bottom), 0.0f, 0.0f }, |
|
|
{ 0.0f, 0.0f, -2.0f/(f-n), 0.0f }, |
|
|
{ -(right+left)/(right-left), -(top+bottom)/(top-bottom), -(f+n)/(f-n), 1.0f } }; |
|
|
|
|
|
|
|
|
return Mat44(&m[0][0]); |
|
|
} |
|
|
|
|
|
|
|
|
inline Mat44 ProjectionMatrix(float fov, float aspect, float znear, float zfar) |
|
|
{ |
|
|
float f = 1.0f / tanf(DegToRad(fov*0.5f)); |
|
|
float zd = znear-zfar; |
|
|
|
|
|
float view[4][4] = { { f/aspect, 0.0f, 0.0f, 0.0f }, |
|
|
{ 0.0f, f, 0.0f, 0.0f }, |
|
|
{ 0.0f, 0.0f, (zfar+znear)/zd, -1.0f }, |
|
|
{ 0.0f, 0.0f, (2.0f*znear*zfar)/zd, 0.0f } }; |
|
|
|
|
|
return Mat44(&view[0][0]); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Rotation |
|
|
{ |
|
|
public: |
|
|
|
|
|
Rotation() : yaw(0), pitch(0), roll(0) {} |
|
|
Rotation(float inYaw, float inPitch, float inRoll) : yaw(inYaw), pitch(inPitch), roll(inRoll) {} |
|
|
|
|
|
Rotation& operator +=(const Rotation& rhs) {yaw += rhs.yaw; pitch += rhs.pitch; roll += rhs.roll; return *this;} |
|
|
Rotation& operator -=(const Rotation& rhs) {yaw -= rhs.yaw; pitch -= rhs.pitch; roll -= rhs.roll; return *this;} |
|
|
|
|
|
Rotation operator + (const Rotation& rhs) const { Rotation lhs(*this); lhs += rhs; return lhs; } |
|
|
Rotation operator - (const Rotation& rhs) const { Rotation lhs(*this); lhs -= rhs; return lhs; } |
|
|
|
|
|
|
|
|
float yaw; |
|
|
float pitch; |
|
|
float roll; |
|
|
}; |
|
|
|
|
|
inline Mat44 ScaleMatrix(const Vector3& s) |
|
|
{ |
|
|
float m[4][4] = { {s.x, 0.0f, 0.0f, 0.0f }, |
|
|
{ 0.0f, s.y, 0.0f, 0.0f}, |
|
|
{ 0.0f, 0.0f, s.z, 0.0f}, |
|
|
{ 0.0f, 0.0f, 0.0f, 1.0f} }; |
|
|
|
|
|
return Mat44(&m[0][0]); |
|
|
} |
|
|
|
|
|
|
|
|
inline Mat44 TransformMatrix(const Rotation& r, const Point3& p) |
|
|
{ |
|
|
const float yaw = DegToRad(r.yaw); |
|
|
const float pitch = DegToRad(r.pitch); |
|
|
const float roll = DegToRad(r.roll); |
|
|
|
|
|
const float s1 = Sin(roll); |
|
|
const float c1 = Cos(roll); |
|
|
const float s2 = Sin(pitch); |
|
|
const float c2 = Cos(pitch); |
|
|
const float s3 = Sin(yaw); |
|
|
const float c3 = Cos(yaw); |
|
|
|
|
|
|
|
|
float mr[4][4] = { { c2*c3, s2, -c2*s3, 0.0f}, |
|
|
{ s1*s3-c1*c3*s2, c1*c2, c3*s1+c1*s2*s3, 0.0f}, |
|
|
{ c3*s1*s2+c1*s3, -c2*s1, c1*c3-s1*s2*s3, 0.0f}, |
|
|
{ p.x, p.y, p.z, 1.0f} }; |
|
|
|
|
|
Mat44 m1(&mr[0][0]); |
|
|
|
|
|
return m1; |
|
|
} |
|
|
|
|
|
class Transform |
|
|
{ |
|
|
public: |
|
|
|
|
|
Transform() {}; |
|
|
Transform(const Point3& p, const Rotation& r) : position(p), rotation(r) {} |
|
|
|
|
|
Mat44 ToMatrix() const |
|
|
{ |
|
|
return TransformMatrix(rotation, position); |
|
|
} |
|
|
|
|
|
|
|
|
void Translate(const Vec3& delta) |
|
|
{ |
|
|
position += delta; |
|
|
} |
|
|
|
|
|
|
|
|
void Rotate(const Rotation& delta) |
|
|
{ |
|
|
rotation += delta; |
|
|
} |
|
|
|
|
|
void RotateToLookAt(const Point3& target) |
|
|
{ |
|
|
|
|
|
Vec3 delta = target-position; |
|
|
|
|
|
|
|
|
rotation.yaw = atan2f(delta.z, delta.x); |
|
|
rotation.pitch = atan2f(delta.y, sqrt(delta.x*delta.x+delta.z*delta.z)); |
|
|
rotation.roll = 0.0f; |
|
|
} |
|
|
|
|
|
Vec3 GetXAxis() const |
|
|
{ |
|
|
return ToMatrix().columns[0]; |
|
|
} |
|
|
|
|
|
Vec3 GetYAxis() const |
|
|
{ |
|
|
return ToMatrix().columns[1]; |
|
|
} |
|
|
|
|
|
Vec3 GetZAxis() const |
|
|
{ |
|
|
return ToMatrix().columns[2]; |
|
|
} |
|
|
|
|
|
Point3 position; |
|
|
Rotation rotation; |
|
|
}; |
|
|
|
|
|
|
|
|
inline Rotation AlignToVector(const Vec3& vector) |
|
|
{ |
|
|
|
|
|
return Rotation(0.0f, RadToDeg(atan2(vector.y, vector.x)), 0.0f); |
|
|
} |
|
|
|
|
|
|
|
|
inline Vec2 AngleToVector(float a) |
|
|
{ |
|
|
return Vec2(Cos(a), Sin(a)); |
|
|
} |
|
|
|
|
|
inline float VectorToAngle(const Vec2& v) |
|
|
{ |
|
|
return atan2f(v.y, v.x); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float SmoothStep(float a, float b, float t) |
|
|
{ |
|
|
t = Clamp(t-a / (b-a), 0.0f, 1.0f); |
|
|
return t*t*(3.0f-2.0f*t); |
|
|
} |
|
|
|
|
|
|
|
|
template <typename T> |
|
|
T HermiteInterpolate(const T& a, const T& b, const T& t1, const T& t2, float t) |
|
|
{ |
|
|
|
|
|
const float w1 = 1.0f - 3*t*t + 2*t*t*t; |
|
|
const float w2 = t*t*(3.0f-2.0f*t); |
|
|
const float w3 = t*t*t - 2*t*t + t; |
|
|
const float w4 = t*t*(t-1.0f); |
|
|
|
|
|
|
|
|
return a*w1 + b*w2 + t1*w3 + t2*w4; |
|
|
|
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
T HermiteTangent(const T& a, const T& b, const T& t1, const T& t2, float t) |
|
|
{ |
|
|
|
|
|
const float w1 = 6.0f*t*t-6*t; |
|
|
const float w2 = -6.0f*t*t + 6*t; |
|
|
const float w3 = 3*t*t - 4*t + 1; |
|
|
const float w4 = 3*t*t - 2*t; |
|
|
|
|
|
|
|
|
return a*w1 + b*w2 + t1*w3 + t2*w4; |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
T HermiteSecondDerivative(const T& a, const T& b, const T& t1, const T& t2, float t) |
|
|
{ |
|
|
|
|
|
const float w1 = 12*t - 6.0f; |
|
|
const float w2 = -12.0f*t + 6; |
|
|
const float w3 = 6*t - 4.0f; |
|
|
const float w4 = 6*t - 2.0f; |
|
|
|
|
|
|
|
|
return a*w1 + b*w2 + t1*w3 + t2*w4; |
|
|
} |
|
|
|
|
|
inline float Log(float base, float x) |
|
|
{ |
|
|
|
|
|
return logf(x) / logf(base); |
|
|
} |
|
|
|
|
|
inline int Log2(int x) |
|
|
{ |
|
|
int n = 0; |
|
|
while (x >= 2) |
|
|
{ |
|
|
++n; |
|
|
x /= 2; |
|
|
} |
|
|
|
|
|
return n; |
|
|
} |
|
|
|
|
|
|
|
|
template <typename T> |
|
|
T RangeMap(T value, T lower, T upper) |
|
|
{ |
|
|
assert(upper >= lower); |
|
|
return (value-lower)/(upper-lower); |
|
|
} |
|
|
|
|
|
|
|
|
class Colour |
|
|
{ |
|
|
public: |
|
|
|
|
|
enum Preset |
|
|
{ |
|
|
kRed, |
|
|
kGreen, |
|
|
kBlue, |
|
|
kWhite, |
|
|
kBlack |
|
|
}; |
|
|
|
|
|
Colour(float r_=0.0f, float g_=0.0f, float b_=0.0f, float a_=1.0f) : r(r_), g(g_), b(b_), a(a_) {} |
|
|
Colour(float* p) : r(p[0]), g(p[1]), b(p[2]), a(p[3]) {} |
|
|
Colour(uint32_t rgba) |
|
|
{ |
|
|
a = ((rgba)&0xff)/255.0f; |
|
|
r = ((rgba>>24)&0xff)/255.0f; |
|
|
g = ((rgba>>16)&0xff)/255.0f; |
|
|
b = ((rgba>>8)&0xff)/255.0f; |
|
|
} |
|
|
Colour(Preset p); |
|
|
|
|
|
|
|
|
operator const float*() const { return &r; } |
|
|
operator float*() { return &r; } |
|
|
|
|
|
Colour operator * (float scale) const { Colour r(*this); r *= scale; return r; } |
|
|
Colour operator / (float scale) const { Colour r(*this); r /= scale; return r; } |
|
|
Colour operator + (const Colour& v) const { Colour r(*this); r += v; return r; } |
|
|
Colour operator - (const Colour& v) const { Colour r(*this); r -= v; return r; } |
|
|
Colour operator * (const Colour& scale) const { Colour r(*this); r *= scale; return r;} |
|
|
|
|
|
Colour& operator *=(float scale) {r *= scale; g *= scale; b*= scale; a*= scale; return *this;} |
|
|
Colour& operator /=(float scale) {float s(1.0f/scale); r *= s; g *= s; b *= s; a *=s; return *this;} |
|
|
Colour& operator +=(const Colour& v) {r += v.r; g += v.g; b += v.b; a += v.a; return *this;} |
|
|
Colour& operator -=(const Colour& v) {r -= v.r; g -= v.g; b -= v.b; a -= v.a; return *this;} |
|
|
Colour& operator *=(const Colour& v) {r *= v.r; g *= v.g; b *= v.b; a *= v.a; return *this;} |
|
|
|
|
|
float r, g, b, a; |
|
|
|
|
|
}; |
|
|
|
|
|
inline bool operator == (const Colour& lhs, const Colour& rhs) |
|
|
{ |
|
|
return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && lhs.a == rhs.a; |
|
|
} |
|
|
|
|
|
inline bool operator != (const Colour& lhs, const Colour& rhs) |
|
|
{ |
|
|
return !(lhs == rhs); |
|
|
} |
|
|
|
|
|
inline Colour ToneMap(const Colour& s) |
|
|
{ |
|
|
|
|
|
float Y = 0.3333f*(s.r + s.g + s.b); |
|
|
return s / (1.0f + Y); |
|
|
} |
|
|
|
|
|
|
|
|
inline Colour operator * (float lhs, const Colour& rhs) |
|
|
{ |
|
|
Colour r(rhs); |
|
|
r *= lhs; |
|
|
return r; |
|
|
} |
|
|
|
|
|
inline Colour YxyToXYZ(float Y, float x, float y) |
|
|
{ |
|
|
float X = x * (Y / y); |
|
|
float Z = (1.0f - x - y) * Y / y; |
|
|
|
|
|
return Colour(X, Y, Z, 1.0f); |
|
|
} |
|
|
|
|
|
inline Colour HSVToRGB( float h, float s, float v ) |
|
|
{ |
|
|
float r, g, b; |
|
|
|
|
|
int i; |
|
|
float f, p, q, t; |
|
|
if( s == 0 ) { |
|
|
|
|
|
r = g = b = v; |
|
|
} |
|
|
else |
|
|
{ |
|
|
h *= 6.0f; |
|
|
i = int(floor( h )); |
|
|
f = h - i; |
|
|
p = v * ( 1 - s ); |
|
|
q = v * ( 1 - s * f ); |
|
|
t = v * ( 1 - s * ( 1 - f ) ); |
|
|
switch( i ) { |
|
|
case 0: |
|
|
r = v; |
|
|
g = t; |
|
|
b = p; |
|
|
break; |
|
|
case 1: |
|
|
r = q; |
|
|
g = v; |
|
|
b = p; |
|
|
break; |
|
|
case 2: |
|
|
r = p; |
|
|
g = v; |
|
|
b = t; |
|
|
break; |
|
|
case 3: |
|
|
r = p; |
|
|
g = q; |
|
|
b = v; |
|
|
break; |
|
|
case 4: |
|
|
r = t; |
|
|
g = p; |
|
|
b = v; |
|
|
break; |
|
|
default: |
|
|
r = v; |
|
|
g = p; |
|
|
b = q; |
|
|
break; |
|
|
}; |
|
|
} |
|
|
|
|
|
return Colour(r, g, b); |
|
|
} |
|
|
|
|
|
inline Colour XYZToLinear(float x, float y, float z) |
|
|
{ |
|
|
float c[4]; |
|
|
c[0] = 3.240479f * x + -1.537150f * y + -0.498535f * z; |
|
|
c[1] = -0.969256f * x + 1.875991f * y + 0.041556f * z; |
|
|
c[2] = 0.055648f * x + -0.204043f * y + 1.057311f * z; |
|
|
c[3] = 1.0f; |
|
|
|
|
|
return Colour(c); |
|
|
} |
|
|
|
|
|
inline uint32_t ColourToRGBA8(const Colour& c) |
|
|
{ |
|
|
union SmallColor |
|
|
{ |
|
|
uint8_t u8[4]; |
|
|
uint32_t u32; |
|
|
}; |
|
|
|
|
|
SmallColor s; |
|
|
s.u8[0] = (uint8_t)(Clamp(c.r, 0.0f, 1.0f) * 255); |
|
|
s.u8[1] = (uint8_t)(Clamp(c.g, 0.0f, 1.0f) * 255); |
|
|
s.u8[2] = (uint8_t)(Clamp(c.b, 0.0f, 1.0f) * 255); |
|
|
s.u8[3] = (uint8_t)(Clamp(c.a, 0.0f, 1.0f) * 255); |
|
|
|
|
|
return s.u32; |
|
|
} |
|
|
|
|
|
inline Colour LinearToSrgb(const Colour& c) |
|
|
{ |
|
|
const float kInvGamma = 1.0f/2.2f; |
|
|
return Colour(powf(c.r, kInvGamma), powf(c.g, kInvGamma), powf(c.b, kInvGamma), c.a); |
|
|
} |
|
|
|
|
|
inline Colour SrgbToLinear(const Colour& c) |
|
|
{ |
|
|
const float kInvGamma = 2.2f; |
|
|
return Colour(powf(c.r, kInvGamma), powf(c.g, kInvGamma), powf(c.b, kInvGamma), c.a); |
|
|
} |
|
|
|
|
|
|
|
|
inline bool IntersectRaySphere(const Point3& sphereOrigin, float sphereRadius, const Point3& rayOrigin, const Vec3& rayDir, float& t, Vec3* hitNormal=NULL) |
|
|
{ |
|
|
Vec3 d(sphereOrigin-rayOrigin); |
|
|
float deltaSq = LengthSq(d); |
|
|
float radiusSq = sphereRadius*sphereRadius; |
|
|
|
|
|
|
|
|
if (deltaSq > radiusSq) |
|
|
{ |
|
|
float dprojr = Dot(d, rayDir); |
|
|
|
|
|
|
|
|
if (dprojr < 0.0f) |
|
|
return false; |
|
|
|
|
|
|
|
|
float dSq = deltaSq-dprojr*dprojr; |
|
|
|
|
|
if (dSq > radiusSq) |
|
|
return false; |
|
|
else |
|
|
{ |
|
|
|
|
|
float thc = sqrt(radiusSq-dSq); |
|
|
|
|
|
|
|
|
t = dprojr - thc; |
|
|
|
|
|
|
|
|
if (hitNormal) |
|
|
*hitNormal = Normalize((rayOrigin+rayDir*t)-sphereOrigin); |
|
|
|
|
|
return true; |
|
|
} |
|
|
} |
|
|
else |
|
|
{ |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
CUDA_CALLABLE inline bool SolveQuadratic(T a, T b, T c, T& minT, T& maxT) |
|
|
{ |
|
|
if (a == 0.0f && b == 0.0f) |
|
|
{ |
|
|
minT = maxT = 0.0f; |
|
|
return true; |
|
|
} |
|
|
|
|
|
T discriminant = b*b - T(4.0)*a*c; |
|
|
|
|
|
if (discriminant < 0.0f) |
|
|
{ |
|
|
return false; |
|
|
} |
|
|
|
|
|
|
|
|
T t = T(-0.5) * (b + Sign(b)*Sqrt(discriminant)); |
|
|
minT = t / a; |
|
|
maxT = c / t; |
|
|
|
|
|
if (minT > maxT) |
|
|
{ |
|
|
Swap(minT, maxT); |
|
|
} |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
|
|
|
inline bool IntersectRaySphere(const Point3& sphereOrigin, float sphereRadius, const Point3& rayOrigin, const Vector3& rayDir, float& minT, float &maxT, Vec3* hitNormal=NULL) |
|
|
{ |
|
|
Vector3 q = rayOrigin-sphereOrigin; |
|
|
|
|
|
float a = 1.0f; |
|
|
float b = 2.0f*Dot(q, rayDir); |
|
|
float c = Dot(q, q)-(sphereRadius*sphereRadius); |
|
|
|
|
|
bool r = SolveQuadratic(a, b, c, minT, maxT); |
|
|
|
|
|
if (minT < 0.0) |
|
|
minT = 0.0f; |
|
|
|
|
|
|
|
|
if (hitNormal && r) |
|
|
{ |
|
|
*hitNormal = Normalize((rayOrigin+rayDir*minT)-sphereOrigin); |
|
|
} |
|
|
|
|
|
return r; |
|
|
} |
|
|
|
|
|
inline bool IntersectRayPlane(const Point3& p, const Vector3& dir, const Plane& plane, float& t) |
|
|
{ |
|
|
float d = Dot(plane, dir); |
|
|
|
|
|
if (d == 0.0f) |
|
|
{ |
|
|
return false; |
|
|
} |
|
|
else |
|
|
{ |
|
|
t = -Dot(plane, p) / d; |
|
|
} |
|
|
|
|
|
return (t > 0.0f); |
|
|
} |
|
|
|
|
|
inline bool IntersectLineSegmentPlane(const Vec3& start, const Vec3& end, const Plane& plane, Vec3& out) |
|
|
{ |
|
|
Vec3 u(end - start); |
|
|
|
|
|
float dist = -Dot(plane, start) / Dot(plane, u); |
|
|
|
|
|
if (dist > 0.0f && dist < 1.0f) |
|
|
{ |
|
|
out = (start + u * dist); |
|
|
return true; |
|
|
} |
|
|
else |
|
|
return false; |
|
|
} |
|
|
|
|
|
|
|
|
inline bool IntersectRayTriTwoSided(const Vec3& p, const Vec3& dir, const Vec3& a, const Vec3& b, const Vec3& c, float& t, float& u, float& v, float& w, float& sign) |
|
|
{ |
|
|
Vector3 ab = b - a; |
|
|
Vector3 ac = c - a; |
|
|
Vector3 n = Cross(ab, ac); |
|
|
|
|
|
float d = Dot(-dir, n); |
|
|
float ood = 1.0f / d; |
|
|
Vector3 ap = p - a; |
|
|
|
|
|
t = Dot(ap, n) * ood; |
|
|
if (t < 0.0f) |
|
|
return false; |
|
|
|
|
|
Vector3 e = Cross(-dir, ap); |
|
|
v = Dot(ac, e) * ood; |
|
|
if (v < 0.0f || v > 1.0f) |
|
|
return false; |
|
|
w = -Dot(ab, e) * ood; |
|
|
if (w < 0.0f || v + w > 1.0f) |
|
|
return false; |
|
|
|
|
|
u = 1.0f - v - w; |
|
|
|
|
|
|
|
|
sign = d; |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inline bool IntersectRayTri(const Point3& p, const Vec3& dir, const Point3& a, const Point3& b, const Point3& c, float& t, float& u, float& v, float& w, Vec3* normal) |
|
|
{ |
|
|
const Vec3 ab = b-a; |
|
|
const Vec3 ac = c-a; |
|
|
|
|
|
|
|
|
Vec3 n = Cross(ab, ac); |
|
|
|
|
|
|
|
|
float d = Dot(-dir, n); |
|
|
|
|
|
|
|
|
if (d <= 0.0f) |
|
|
return false; |
|
|
|
|
|
Vec3 ap = p-a; |
|
|
t = Dot(ap, n); |
|
|
|
|
|
|
|
|
if (t < 0.0f) |
|
|
return false; |
|
|
|
|
|
|
|
|
Vec3 e = Cross(-dir, ap); |
|
|
v = Dot(ac, e); |
|
|
if (v < 0.0f || v > d) return false; |
|
|
|
|
|
w = -Dot(ab, e); |
|
|
if (w < 0.0f || v + w > d) return false; |
|
|
|
|
|
float ood = 1.0f / d; |
|
|
t *= ood; |
|
|
v *= ood; |
|
|
w *= ood; |
|
|
u = 1.0f-v-w; |
|
|
|
|
|
|
|
|
if (normal) |
|
|
*normal = n; |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline bool IntersectSegmentTri(const Vec3& p, const Vec3& q, const Vec3& a, const Vec3& b, const Vec3& c, float& t, float& u, float& v, float& w, Vec3* normal, float expand) |
|
|
{ |
|
|
const Vec3 ab = b-a; |
|
|
const Vec3 ac = c-a; |
|
|
const Vec3 qp = p-q; |
|
|
|
|
|
|
|
|
Vec3 n = Cross(ab, ac); |
|
|
|
|
|
|
|
|
float d = Dot(qp, n); |
|
|
|
|
|
|
|
|
if (d <= 0.0f) |
|
|
return false; |
|
|
|
|
|
Vec3 ap = p-a; |
|
|
t = Dot(ap, n); |
|
|
|
|
|
|
|
|
if (t < 0.0f) |
|
|
return false; |
|
|
|
|
|
|
|
|
if (t > d) |
|
|
return false; |
|
|
|
|
|
|
|
|
Vec3 e = Cross(qp, ap); |
|
|
v = Dot(ac, e); |
|
|
if (v < 0.0f || v > d) return false; |
|
|
|
|
|
w = -Dot(ab, e); |
|
|
if (w < 0.0f || v + w > d) return false; |
|
|
|
|
|
float ood = 1.0f / d; |
|
|
t *= ood; |
|
|
v *= ood; |
|
|
w *= ood; |
|
|
u = 1.0f-v-w; |
|
|
|
|
|
|
|
|
if (normal) |
|
|
*normal = n; |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline float ScalarTriple(const Vec3& a, const Vec3& b, const Vec3& c) { return Dot(Cross(a, b), c); } |
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline bool IntersectLineTri(const Vec3& p, const Vec3& q, const Vec3& a, const Vec3& b, const Vec3& c) |
|
|
{ |
|
|
const Vec3 pq = q-p; |
|
|
const Vec3 pa = a-p; |
|
|
const Vec3 pb = b-p; |
|
|
const Vec3 pc = c-p; |
|
|
|
|
|
Vec3 m = Cross(pq, pc); |
|
|
float u = Dot(pb, m); |
|
|
if (u< 0.0f) return false; |
|
|
|
|
|
float v = -Dot(pa, m); |
|
|
if (v < 0.0f) return false; |
|
|
|
|
|
float w = ScalarTriple(pq, pb, pa); |
|
|
if (w < 0.0f) return false; |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline Vec3 ClosestPointToAABB(const Vec3& p, const Vec3& lower, const Vec3& upper) |
|
|
{ |
|
|
Vec3 c; |
|
|
|
|
|
for (int i=0; i < 3; ++i) |
|
|
{ |
|
|
float v = p[i]; |
|
|
if (v < lower[i]) v = lower[i]; |
|
|
if (v > upper[i]) v = upper[i]; |
|
|
c[i] = v; |
|
|
} |
|
|
|
|
|
return c; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline Vec3 ClosestPointOnTriangle(const Vec3& a, const Vec3& b, const Vec3& c, const Vec3& p, float& v, float& w) |
|
|
{ |
|
|
Vec3 ab = b-a; |
|
|
Vec3 ac = c-a; |
|
|
Vec3 ap = p-a; |
|
|
|
|
|
float d1 = Dot(ab, ap); |
|
|
float d2 = Dot(ac, ap); |
|
|
if (d1 <= 0.0f && d2 <= 0.0f) |
|
|
{ |
|
|
v = 0.0f; |
|
|
w = 0.0f; |
|
|
return a; |
|
|
} |
|
|
|
|
|
Vec3 bp = p-b; |
|
|
float d3 = Dot(ab, bp); |
|
|
float d4 = Dot(ac, bp); |
|
|
if (d3 >= 0.0f && d4 <= d3) |
|
|
{ |
|
|
v = 1.0f; |
|
|
w = 0.0f; |
|
|
return b; |
|
|
} |
|
|
|
|
|
float vc = d1*d4 - d3*d2; |
|
|
if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) |
|
|
{ |
|
|
v = d1 / (d1-d3); |
|
|
w = 0.0f; |
|
|
return a + v*ab; |
|
|
} |
|
|
|
|
|
Vec3 cp =p-c; |
|
|
float d5 = Dot(ab, cp); |
|
|
float d6 = Dot(ac, cp); |
|
|
if (d6 >= 0.0f && d5 <= d6) |
|
|
{ |
|
|
v = 0.0f; |
|
|
w = 1.0f; |
|
|
return c; |
|
|
} |
|
|
|
|
|
float vb = d5*d2 - d1*d6; |
|
|
if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) |
|
|
{ |
|
|
v = 0.0f; |
|
|
w = d2 / (d2 - d6); |
|
|
return a + w * ac; |
|
|
} |
|
|
|
|
|
float va = d3*d6 - d5*d4; |
|
|
if (va <= 0.0f && (d4 -d3) >= 0.0f && (d5-d6) >= 0.0f) |
|
|
{ |
|
|
w = (d4-d3)/((d4-d3) + (d5-d6)); |
|
|
v = 1.0f-w; |
|
|
return b + w * (c-b); |
|
|
} |
|
|
|
|
|
float denom = 1.0f / (va + vb + vc); |
|
|
v = vb * denom; |
|
|
w = vc * denom; |
|
|
return a + ab*v + ac*w; |
|
|
} |
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline float SqDistPointSegment(Vec3 a, Vec3 b, Vec3 c) |
|
|
{ |
|
|
Vec3 ab = b-a, ac=c-a, bc=c-b; |
|
|
float e = Dot(ac, ab); |
|
|
|
|
|
if (e <= 0.0f) |
|
|
return Dot(ac, ac); |
|
|
float f = Dot(ab, ab); |
|
|
|
|
|
if (e >= f) |
|
|
return Dot(bc, bc); |
|
|
|
|
|
return Dot(ac, ac) - e*e/f; |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline bool PointInTriangle(Vec3 a, Vec3 b, Vec3 c, Vec3 p) |
|
|
{ |
|
|
a -= p; b -= p; c-= p; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Vec3 u = Cross(b, c); |
|
|
Vec3 v = Cross(c, a); |
|
|
|
|
|
if (Dot(u, v) <= 0.0f) |
|
|
return false; |
|
|
|
|
|
Vec3 w = Cross(a, b); |
|
|
|
|
|
if (Dot(u, w) <= 0.0f) |
|
|
return false; |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline void ClosestPointBetweenLineSegments(const Vec3& p, const Vec3& q, const Vec3& r, const Vec3& s, float& u, float& v) |
|
|
{ |
|
|
Vec3 d1 = q-p; |
|
|
Vec3 d2 = s-r; |
|
|
Vec3 rp = p-r; |
|
|
float a = Dot(d1, d1); |
|
|
float c = Dot(d1, rp); |
|
|
float e = Dot(d2, d2); |
|
|
float f = Dot(d2, rp); |
|
|
|
|
|
float b = Dot(d1, d2); |
|
|
float denom = a*e - b*b; |
|
|
if (denom != 0.0f) |
|
|
u = Clamp((b*f - c*e)/denom, 0.0f, 1.0f); |
|
|
else |
|
|
{ |
|
|
u = 0.0f; |
|
|
} |
|
|
|
|
|
v = (b*u + f)/e; |
|
|
|
|
|
if (v < 0.0f) |
|
|
{ |
|
|
v = 0.0f; |
|
|
u = Clamp(-c/a, 0.0f, 1.0f); |
|
|
} |
|
|
else if (v > 1.0f) |
|
|
{ |
|
|
v = 1.0f; |
|
|
u = Clamp((b-c)/a, 0.0f, 1.0f); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline float minf(const float a, const float b) { return a < b ? a : b; } |
|
|
CUDA_CALLABLE inline float maxf(const float a, const float b) { return a > b ? a : b; } |
|
|
|
|
|
CUDA_CALLABLE inline bool IntersectRayAABBOmpf(const Vec3& pos, const Vector3& rcp_dir, const Vector3& min, const Vector3& max, float& t) { |
|
|
|
|
|
float |
|
|
l1 = (min.x - pos.x) * rcp_dir.x, |
|
|
l2 = (max.x - pos.x) * rcp_dir.x, |
|
|
lmin = minf(l1,l2), |
|
|
lmax = maxf(l1,l2); |
|
|
|
|
|
l1 = (min.y - pos.y) * rcp_dir.y; |
|
|
l2 = (max.y - pos.y) * rcp_dir.y; |
|
|
lmin = maxf(minf(l1,l2), lmin); |
|
|
lmax = minf(maxf(l1,l2), lmax); |
|
|
|
|
|
l1 = (min.z - pos.z) * rcp_dir.z; |
|
|
l2 = (max.z - pos.z) * rcp_dir.z; |
|
|
lmin = maxf(minf(l1,l2), lmin); |
|
|
lmax = minf(maxf(l1,l2), lmax); |
|
|
|
|
|
|
|
|
|
|
|
bool hit = ((lmax >= 0.f) & (lmax >= lmin)); |
|
|
if (hit) |
|
|
t = lmin; |
|
|
return hit; |
|
|
} |
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline bool IntersectRayAABB(const Vec3& start, const Vector3& dir, const Vector3& min, const Vector3& max, float& t, Vector3* normal) |
|
|
{ |
|
|
|
|
|
float tx = -1.0f, ty = -1.0f, tz = -1.0f; |
|
|
bool inside = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (start.x < min.x) |
|
|
{ |
|
|
if (dir.x != 0.0f) |
|
|
tx = (min.x-start.x)/dir.x; |
|
|
inside = false; |
|
|
} |
|
|
else if (start.x > max.x) |
|
|
{ |
|
|
if (dir.x != 0.0f) |
|
|
tx = (max.x-start.x)/dir.x; |
|
|
inside = false; |
|
|
} |
|
|
|
|
|
|
|
|
if (start.y < min.y) |
|
|
{ |
|
|
if (dir.y != 0.0f) |
|
|
ty = (min.y-start.y)/dir.y; |
|
|
inside = false; |
|
|
} |
|
|
else if (start.y > max.y) |
|
|
{ |
|
|
if (dir.y != 0.0f) |
|
|
ty = (max.y-start.y)/dir.y; |
|
|
inside = false; |
|
|
} |
|
|
|
|
|
|
|
|
if (start.z < min.z) |
|
|
{ |
|
|
if (dir.z != 0.0f) |
|
|
tz = (min.z-start.z)/dir.z; |
|
|
inside = false; |
|
|
} |
|
|
else if (start.z > max.z) |
|
|
{ |
|
|
if (dir.z != 0.0f) |
|
|
tz = (max.z-start.z)/dir.z; |
|
|
inside = false; |
|
|
} |
|
|
|
|
|
|
|
|
if (inside) |
|
|
{ |
|
|
t = 0.0f; |
|
|
return true; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
float tmax = tx; |
|
|
int taxis = 0; |
|
|
|
|
|
if (ty > tmax) |
|
|
{ |
|
|
tmax = ty; |
|
|
taxis = 1; |
|
|
} |
|
|
if (tz > tmax) |
|
|
{ |
|
|
tmax = tz; |
|
|
taxis = 2; |
|
|
} |
|
|
|
|
|
if (tmax < 0.0f) |
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float eps = 0.0f; |
|
|
|
|
|
Vec3 hit = start + dir*tmax; |
|
|
|
|
|
if ((hit.x < min.x-eps || hit.x > max.x+eps) && taxis != 0) |
|
|
return false; |
|
|
if ((hit.y < min.y-eps || hit.y > max.y+eps) && taxis != 1) |
|
|
return false; |
|
|
if ((hit.z < min.z-eps || hit.z > max.z+eps) && taxis != 2) |
|
|
return false; |
|
|
|
|
|
|
|
|
t = tmax; |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline Vec4 PlaneFromPoints(const Vec3& p, const Vec3& q, const Vec3& r) |
|
|
{ |
|
|
Vec3 e0 = q-p; |
|
|
Vec3 e1 = r-p; |
|
|
|
|
|
Vec3 n = SafeNormalize(Cross(e0, e1)); |
|
|
|
|
|
return Vec4(n.x, n.y, n.z, -Dot(p, n)); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline bool IntersectPlaneAABB(const Vec4& plane, const Vec3& center, const Vec3& extents) |
|
|
{ |
|
|
float radius = Abs(extents.x*plane.x) + Abs(extents.y*plane.y) + Abs(extents.z*plane.z); |
|
|
float delta = Dot(center, Vec3(plane)) + plane.w; |
|
|
|
|
|
return Abs(delta) <= radius; |
|
|
} |
|
|
|
|
|
|
|
|
class Rect |
|
|
{ |
|
|
public: |
|
|
|
|
|
Rect() : m_left(0), m_right(0), m_top(0), m_bottom(0) {} |
|
|
|
|
|
Rect(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) : m_left(left), m_right(right), m_top(top), m_bottom(bottom) |
|
|
{ |
|
|
assert(left <= right); |
|
|
assert(top <= bottom); |
|
|
} |
|
|
|
|
|
uint32_t Width() const { return m_right - m_left; } |
|
|
uint32_t Height() const { return m_bottom - m_top; } |
|
|
|
|
|
|
|
|
void Expand(uint32_t x) |
|
|
{ |
|
|
m_left -= x; |
|
|
m_right += x; |
|
|
m_top -= x; |
|
|
m_bottom += x; |
|
|
} |
|
|
|
|
|
uint32_t Left() const { return m_left; } |
|
|
uint32_t Right() const { return m_right; } |
|
|
uint32_t Top() const { return m_top; } |
|
|
uint32_t Bottom() const { return m_bottom; } |
|
|
|
|
|
bool Contains(uint32_t x, uint32_t y) const |
|
|
{ |
|
|
return (x >= m_left) && (x <= m_right) && (y >= m_top) && (y <= m_bottom); |
|
|
} |
|
|
|
|
|
uint32_t m_left; |
|
|
uint32_t m_right; |
|
|
uint32_t m_top; |
|
|
uint32_t m_bottom; |
|
|
}; |
|
|
|
|
|
|
|
|
template <typename T> |
|
|
void RandomShuffle(T begin, T end) |
|
|
{ |
|
|
assert(end > begin); |
|
|
uint32_t n = distance(begin, end); |
|
|
|
|
|
for (uint32_t i=0; i < n; ++i) |
|
|
{ |
|
|
|
|
|
uint32_t r = Rand() % (n-i); |
|
|
|
|
|
|
|
|
swap(*(begin+i), *(begin+(i+r))); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline Quat QuatFromAxisAngle(const Vec3& axis, float angle) |
|
|
{ |
|
|
Vec3 v = Normalize(axis); |
|
|
|
|
|
float half = angle*0.5f; |
|
|
float w = cosf(half); |
|
|
|
|
|
const float sin_theta_over_two = sinf(half); |
|
|
v *= sin_theta_over_two; |
|
|
|
|
|
return Quat(v.x, v.y, v.z, w); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline Vec3 rotate(const Vec3& q, float w, const Vec3& x) |
|
|
{ |
|
|
return 2.0f*(x*(w*w-0.5f) + Cross(q, x)*w + q*Dot(q, x)); |
|
|
} |
|
|
|
|
|
|
|
|
CUDA_CALLABLE inline Vec3 rotateInv(const Vec3& q, float w, const Vec3& x) |
|
|
{ |
|
|
return 2.0f*(x*(w*w-0.5f) - Cross(q, x)*w + q*Dot(q, x)); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline void TransformBounds(const Quat& q, Vec3 extents, Vec3& newExtents) |
|
|
{ |
|
|
Matrix33 transform(q); |
|
|
|
|
|
transform.cols[0] *= extents.x; |
|
|
transform.cols[1] *= extents.y; |
|
|
transform.cols[2] *= extents.z; |
|
|
|
|
|
float ex = fabsf(transform.cols[0].x) + fabsf(transform.cols[1].x) + fabsf(transform.cols[2].x); |
|
|
float ey = fabsf(transform.cols[0].y) + fabsf(transform.cols[1].y) + fabsf(transform.cols[2].y); |
|
|
float ez = fabsf(transform.cols[0].z) + fabsf(transform.cols[1].z) + fabsf(transform.cols[2].z); |
|
|
|
|
|
newExtents = Vec3(ex, ey, ez); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline void TransformBounds(const Vec3& localLower, const Vec3& localUpper, const Vec3& translation, const Quat& rotation, float scale, Vec3& lower, Vec3& upper) |
|
|
{ |
|
|
Matrix33 transform(rotation); |
|
|
|
|
|
Vec3 extents = (localUpper-localLower)*scale; |
|
|
|
|
|
transform.cols[0] *= extents.x; |
|
|
transform.cols[1] *= extents.y; |
|
|
transform.cols[2] *= extents.z; |
|
|
|
|
|
float ex = fabsf(transform.cols[0].x) + fabsf(transform.cols[1].x) + fabsf(transform.cols[2].x); |
|
|
float ey = fabsf(transform.cols[0].y) + fabsf(transform.cols[1].y) + fabsf(transform.cols[2].y); |
|
|
float ez = fabsf(transform.cols[0].z) + fabsf(transform.cols[1].z) + fabsf(transform.cols[2].z); |
|
|
|
|
|
Vec3 center = (localUpper+localLower)*0.5f*scale; |
|
|
|
|
|
lower = rotation*center + translation - Vec3(ex, ey, ez)*0.5f; |
|
|
upper = rotation*center + translation + Vec3(ex, ey, ez)*0.5f; |
|
|
} |
|
|
|
|
|
|
|
|
inline int PoissonSample3D(float radius, float separation, Vec3* points, int maxPoints, int maxAttempts) |
|
|
{ |
|
|
|
|
|
int c = 0; |
|
|
while (c < maxPoints) |
|
|
{ |
|
|
int a = 0; |
|
|
while (a < maxAttempts) |
|
|
{ |
|
|
const Vec3 p = UniformSampleSphereVolume()*radius; |
|
|
|
|
|
|
|
|
int i=0; |
|
|
for (; i < c; ++i) |
|
|
{ |
|
|
Vec3 d = p-points[i]; |
|
|
|
|
|
|
|
|
if (LengthSq(d) < separation*separation) |
|
|
break; |
|
|
} |
|
|
|
|
|
|
|
|
if (i == c) |
|
|
{ |
|
|
points[c] = p; |
|
|
++c; |
|
|
break; |
|
|
} |
|
|
|
|
|
++a; |
|
|
} |
|
|
|
|
|
|
|
|
if (a == maxAttempts) |
|
|
break; |
|
|
} |
|
|
|
|
|
return c; |
|
|
} |
|
|
|
|
|
|
|
|
inline int TightPack3D(float radius, float separation, Vec3* points, int maxPoints) |
|
|
{ |
|
|
int dim = int(ceilf(radius/separation)); |
|
|
|
|
|
int c = 0; |
|
|
|
|
|
for (int z=-dim; z <= dim; ++z) |
|
|
{ |
|
|
for (int y=-dim; y <= dim; ++y) |
|
|
{ |
|
|
for (int x=-dim; x <= dim; ++x) |
|
|
{ |
|
|
float xpos = x*separation + (((y+z)&1)?separation*0.5f:0.0f); |
|
|
float ypos = y*sqrtf(0.75f)*separation; |
|
|
float zpos = z*sqrtf(0.75f)*separation; |
|
|
|
|
|
Vec3 p(xpos, ypos, zpos); |
|
|
|
|
|
|
|
|
if (LengthSq(p) == 0.0f) |
|
|
continue; |
|
|
|
|
|
if (c < maxPoints && Length(p) <= radius) |
|
|
{ |
|
|
points[c] = p; |
|
|
++c; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
return c; |
|
|
} |
|
|
|
|
|
|
|
|
struct Bounds |
|
|
{ |
|
|
CUDA_CALLABLE inline Bounds() : lower( FLT_MAX) |
|
|
, upper(-FLT_MAX) {} |
|
|
|
|
|
CUDA_CALLABLE inline Bounds(const Vec3& lower, const Vec3& upper) : lower(lower), upper(upper) {} |
|
|
|
|
|
CUDA_CALLABLE inline Vec3 GetCenter() const { return 0.5f*(lower+upper); } |
|
|
CUDA_CALLABLE inline Vec3 GetEdges() const { return upper-lower; } |
|
|
|
|
|
CUDA_CALLABLE inline void Expand(float r) |
|
|
{ |
|
|
lower -= Vec3(r); |
|
|
upper += Vec3(r); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline void Expand(const Vec3& r) |
|
|
{ |
|
|
lower -= r; |
|
|
upper += r; |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline bool Empty() const { return lower.x >= upper.x || lower.y >= upper.y || lower.z >= upper.z; } |
|
|
|
|
|
CUDA_CALLABLE inline bool Overlaps(const Vec3& p) const |
|
|
{ |
|
|
if (p.x < lower.x || |
|
|
p.y < lower.y || |
|
|
p.z < lower.z || |
|
|
p.x > upper.x || |
|
|
p.y > upper.y || |
|
|
p.z > upper.z) |
|
|
{ |
|
|
return false; |
|
|
} |
|
|
else |
|
|
{ |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline bool Overlaps(const Bounds& b) const |
|
|
{ |
|
|
if (lower.x > b.upper.x || |
|
|
lower.y > b.upper.y || |
|
|
lower.z > b.upper.z || |
|
|
upper.x < b.lower.x || |
|
|
upper.y < b.lower.y || |
|
|
upper.z < b.lower.z) |
|
|
{ |
|
|
return false; |
|
|
} |
|
|
else |
|
|
{ |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
Vec3 lower; |
|
|
Vec3 upper; |
|
|
}; |
|
|
|
|
|
CUDA_CALLABLE inline Bounds Union(const Bounds& a, const Vec3& b) |
|
|
{ |
|
|
return Bounds(Min(a.lower, b), Max(a.upper, b)); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline Bounds Union(const Bounds& a, const Bounds& b) |
|
|
{ |
|
|
return Bounds(Min(a.lower, b.lower), Max(a.upper, b.upper)); |
|
|
} |
|
|
|
|
|
CUDA_CALLABLE inline Bounds Intersection(const Bounds& a, const Bounds& b) |
|
|
{ |
|
|
return Bounds(Max(a.lower, b.lower), Min(a.upper, b.upper)); |
|
|
} |
|
|
|