Hermes
transform.h
Go to the documentation of this file.
1 
32 #ifndef HERMES_GEOMETRY_TRANSFORM_H
33 #define HERMES_GEOMETRY_TRANSFORM_H
34 
35 #include <hermes/geometry/bbox.h>
36 #include <hermes/geometry/matrix.h>
37 #include <hermes/geometry/normal.h>
38 #include <hermes/geometry/point.h>
39 #include <hermes/geometry/ray.h>
40 #include <hermes/common/debug.h>
42 
43 namespace hermes {
44 
47 enum class transform_options {
48  none = 0x0,
49  x_right = 0x1,
50  y_right = 0x2,
51  z_right = 0x4,
52  left_handed = 0x8,
53  x_left = 0x10,
54  y_left = 0x20,
55  z_left = 0x40,
56  right_handed = 0x80,
57  x_up = 0x100,
58  y_up = 0x200,
59  z_up = 0x400,
60  zero_to_one = 0x800,
61  x_down = 0x1000,
62  y_down = 0x2000,
63  z_down = 0x4000,
64  transpose = 0x8000,
65  flip_x = 0x10000,
66  flip_y = 0x20000,
67  flip_z = 0x40000,
68 };
69 HERMES_ENABLE_BITMASK_OPERATORS(transform_options);
70 
71 class Transform;
72 class Transform2;
73 // *********************************************************************************************************************
74 // EXTERNAL FUNCTIONS
75 // *********************************************************************************************************************
76 // algebra
80 HERMES_DEVICE_CALLABLE Transform inverse(const Transform &t);
84 Transform2 inverse(const Transform2 &t);
85 
86 // *********************************************************************************************************************
87 // Transform2
88 // *********************************************************************************************************************
90 class Transform2 {
91 public:
92  // *******************************************************************************************************************
93  // STATIC METHODS
94  // *******************************************************************************************************************
107  // *******************************************************************************************************************
108  // FRIEND FUNCTIONS
109  // *******************************************************************************************************************
110  // algebra
114  friend Transform2 inverse(const Transform2 &t) { return inverse(t.m); }
115  // *******************************************************************************************************************
116  // CONSTRUCTORS
117  // *******************************************************************************************************************
126  // *******************************************************************************************************************
127  // OPERATORS
128  // *******************************************************************************************************************
129  // transform
133  HERMES_DEVICE_CALLABLE void operator()(const point2 &p, point2 *r) const {
134  real_t x = p.x, y = p.y;
135  r->x = m[0][0] * x + m[0][1] * y + m[0][2];
136  r->y = m[1][0] * x + m[1][1] * y + m[1][2];
137  real_t wp = m[2][0] * x + m[2][1] * y + m[2][2];
138  if (wp != 1.f)
139  *r /= wp;
140  }
144  HERMES_DEVICE_CALLABLE void operator()(const vec2 &v, vec2 *r) const {
145  real_t x = v.x, y = v.y;
146  r->x = m[0][0] * x + m[0][1] * y;
147  r->y = m[1][0] * x + m[1][1] * y;
148  }
153  real_t x = v.x, y = v.y;
154  return vec2(m[0][0] * x + m[0][1] * y, m[1][0] * x + m[1][1] * y);
155  }
160  real_t x = p.x, y = p.y;
161  real_t xp = m[0][0] * x + m[0][1] * y + m[0][2];
162  real_t yp = m[1][0] * x + m[1][1] * y + m[1][2];
163  real_t wp = m[2][0] * x + m[2][1] * y + m[2][2];
164  if (wp == 1.f)
165  return point2(xp, yp);
166  return point2(xp / wp, yp / wp);
167  }
172  const Transform2 &M = *this;
173  bbox2 ret;
174  ret = make_union(ret, M(point2(b.lower.x, b.lower.y)));
175  ret = make_union(ret, M(point2(b.upper.x, b.lower.y)));
176  ret = make_union(ret, M(point2(b.upper.x, b.upper.y)));
177  ret = make_union(ret, M(point2(b.lower.x, b.upper.y)));
178  return ret;
179  }
184  Ray2 ret = r;
185  (*this)(ret.o, &ret.o);
186  (*this)(ret.d, &ret.d);
187  return ret;
188  }
189  // arithmetic
194  return m * t.m;
195  }
196  // *******************************************************************************************************************
197  // METHODS
198  // *******************************************************************************************************************
203  [[nodiscard]] HERMES_DEVICE_CALLABLE vec2 getTranslate() const { return vec2(m[0][2], m[1][2]); }
206  [[nodiscard]] HERMES_DEVICE_CALLABLE vec2 getScale() const { return {0, 0}; }
209  [[nodiscard]] HERMES_DEVICE_CALLABLE mat3 getMatrix() const { return m; }
210  // *******************************************************************************************************************
211  // ACCESS
212  // *******************************************************************************************************************
216  HERMES_DEVICE_CALLABLE const real_t *operator[](u32 row_index) const { return m[row_index]; }
220  HERMES_DEVICE_CALLABLE real_t *operator[](u32 row_index) { return m[row_index]; }
221  // *******************************************************************************************************************
222  // DEBUG
223  // *******************************************************************************************************************
227  return mat3::memoryDumpLayout();
228  }
229 private:
230  mat3 m;
231 };
232 
233 // *********************************************************************************************************************
234 // Transform
235 // *********************************************************************************************************************
237 class Transform {
238 public:
239  // *******************************************************************************************************************
240  // STATIC METHODS
241  // *******************************************************************************************************************
242  // projections
264  HERMES_DEVICE_CALLABLE static Transform lookAt(const point3 &eye, const point3 &target = {0, 0, 0},
265  const vec3 &up = {0, 1, 0},
266  transform_options options = transform_options::left_handed);
294  HERMES_DEVICE_CALLABLE static Transform ortho(real_t left, real_t right, real_t bottom, real_t top,
295  real_t near, real_t far,
296  transform_options options = transform_options::left_handed);
316  HERMES_DEVICE_CALLABLE static Transform perspective(real_t fovy_in_degrees,
317  real_t aspect_ratio,
318  real_t near,
319  real_t far,
320  transform_options options = transform_options::left_handed);
321  // transform
335  HERMES_DEVICE_CALLABLE static Transform rotateX(real_t angle_in_radians);
339  HERMES_DEVICE_CALLABLE static Transform rotateY(real_t angle_in_radians);
343  HERMES_DEVICE_CALLABLE static Transform rotateZ(real_t angle_in_radians);
348  HERMES_DEVICE_CALLABLE static Transform rotate(real_t angle_in_radians, const vec3 &axis);
353  HERMES_DEVICE_CALLABLE static Transform alignVectors(const vec3 &a, const vec3 &b);
354  // *******************************************************************************************************************
355  // FRIEND FUNCTIONS
356  // *******************************************************************************************************************
357  // algebra
362  // *******************************************************************************************************************
363  // CONSTRUCTORS
364  // *******************************************************************************************************************
372  HERMES_DEVICE_CALLABLE explicit Transform(const real_t mat[4][4]);
376  // *******************************************************************************************************************
377  // OPERATORS
378  // *******************************************************************************************************************
379  // transform
384  const Transform &M = *this;
385  bbox3 ret(M(point3(b.lower.x, b.lower.y, b.lower.z)));
386  ret = make_union(ret, M(point3(b.upper.x, b.lower.y, b.lower.z)));
387  ret = make_union(ret, M(point3(b.lower.x, b.upper.y, b.lower.z)));
388  ret = make_union(ret, M(point3(b.lower.x, b.lower.y, b.upper.z)));
389  ret = make_union(ret, M(point3(b.lower.x, b.upper.y, b.upper.z)));
390  ret = make_union(ret, M(point3(b.upper.x, b.upper.y, b.lower.z)));
391  ret = make_union(ret, M(point3(b.upper.x, b.lower.y, b.upper.z)));
392  ret = make_union(ret, M(point3(b.lower.x, b.upper.y, b.upper.z)));
393  return ret;
394  }
399  real_t x = p.x, y = p.y, z = 0.f;
400  real_t xp = m[0][0] * x + m[0][1] * y + m[0][2] * z + m[0][3];
401  real_t yp = m[1][0] * x + m[1][1] * y + m[1][2] * z + m[1][3];
402  real_t zp = m[2][0] * x + m[2][1] * y + m[2][2] * z + m[2][3];
403  real_t wp = m[3][0] * x + m[3][1] * y + m[3][2] * z + m[3][3];
404  if (wp == 1.f)
405  return point3(xp, yp, zp);
406  return point3(xp, yp, zp) / wp;
407  }
412  real_t x = p.x, y = p.y, z = p.z;
413  real_t xp = m[0][0] * x + m[0][1] * y + m[0][2] * z + m[0][3];
414  real_t yp = m[1][0] * x + m[1][1] * y + m[1][2] * z + m[1][3];
415  real_t zp = m[2][0] * x + m[2][1] * y + m[2][2] * z + m[2][3];
416  real_t wp = m[3][0] * x + m[3][1] * y + m[3][2] * z + m[3][3];
417  if (wp == 1.f)
418  return point3(xp, yp, zp);
419  return point3(xp, yp, zp) / wp;
420  }
424  HERMES_DEVICE_CALLABLE void operator()(const point3 &p, point3 *r) const {
425  real_t x = p.x, y = p.y, z = p.z;
426  r->x = m[0][0] * x + m[0][1] * y + m[0][2] * z + m[0][3];
427  r->y = m[1][0] * x + m[1][1] * y + m[1][2] * z + m[1][3];
428  r->z = m[2][0] * x + m[2][1] * y + m[2][2] * z + m[2][3];
429  real_t wp = m[3][0] * x + m[3][1] * y + m[3][2] * z + m[3][3];
430  if (wp != 1.f)
431  *r /= wp;
432  }
437  real_t x = v.x, y = v.y, z = v.z;
438  return vec3(m[0][0] * x + m[0][1] * y + m[0][2] * z,
439  m[1][0] * x + m[1][1] * y + m[1][2] * z,
440  m[2][0] * x + m[2][1] * y + m[2][2] * z);
441  }
446  real_t x = n.x, y = n.y, z = n.z;
447  auto m_inv = inverse(*this);
448  return normal3(m_inv[0][0] * x + m_inv[1][0] * y + m_inv[2][0] * z,
449  m_inv[0][1] * x + m_inv[1][1] * y + m_inv[2][1] * z,
450  m_inv[0][2] * x + m_inv[1][2] * y + m_inv[2][2] * z);
451  }
456  Ray3 ret = r;
457  (*this)(ret.o, &ret.o);
458  ret.d = (*this)(ret.d);
459  return ret;
460  }
464  HERMES_DEVICE_CALLABLE void operator()(const Ray3 &r, Ray3 *ret) const {
465  (*this)(r.o, &ret->o);
466  ret->d = (*this)(ret->d);
467  }
468  // arithmetic
473  m.setIdentity();
474  mat3 m3 = t.getMatrix();
475  m[0][0] = m3[0][0];
476  m[0][1] = m3[0][1];
477  m[0][3] = m3[0][2];
478 
479  m[1][0] = m3[1][0];
480  m[1][1] = m3[1][1];
481  m[1][3] = m3[1][2];
482  return *this;
483  }
488  mat4 m1 = m * t.m;
489  return {m1};
490  }
494  HERMES_DEVICE_CALLABLE point3 operator*(const point3 &p) const { return (*this)(p); }
495  // boolean
496  HERMES_DEVICE_CALLABLE bool operator==(const Transform &t) const { return t.m == m; }
497  HERMES_DEVICE_CALLABLE bool operator!=(const Transform &t) const { return t.m != m; }
498  // *******************************************************************************************************************
499  // METHODS
500  // *******************************************************************************************************************
506  [[nodiscard]] HERMES_DEVICE_CALLABLE bool swapsHandedness() const;
509  [[nodiscard]] HERMES_DEVICE_CALLABLE vec3 getTranslate() const { return vec3(m[0][3], m[1][3], m[2][3]); }
517  HERMES_DEVICE_CALLABLE void applyToPoint(const real_t *p, real_t *r, size_t d = 3) const {
518  real_t x = p[0], y = p[1], z = 0.f;
519  if (d == 3)
520  z = p[2];
521  r[0] = m[0][0] * x + m[0][1] * y + m[0][2] * z + m[0][3];
522  r[1] = m[1][0] * x + m[1][1] * y + m[1][2] * z + m[1][3];
523  if (d == 3)
524  r[2] = m[2][0] * x + m[2][1] * y + m[2][2] * z + m[2][3];
525  real_t wp = m[3][0] * x + m[3][1] * y + m[3][2] * z + m[3][3];
526  if (wp != 1.f) {
527  real_t invwp = 1.f / wp;
528  r[0] *= invwp;
529  r[1] *= invwp;
530  if (d == 3)
531  r[2] *= invwp;
532  }
533  }
534 
535  // *******************************************************************************************************************
536  // ACCESS
537  // *******************************************************************************************************************
540  [[nodiscard]] HERMES_DEVICE_CALLABLE const real_t *c_matrix() const { return &m[0][0]; }
542  [[nodiscard]] HERMES_DEVICE_CALLABLE const mat4 &matrix() const { return m; }
546  return mat3(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1],
547  m[1][2], m[2][0], m[2][1], m[2][2]);
548  }
552  HERMES_DEVICE_CALLABLE const real_t *operator[](u32 row_index) const { return m[row_index]; }
556  HERMES_DEVICE_CALLABLE real_t *operator[](u32 row_index) { return m[row_index]; }
557  // *******************************************************************************************************************
558  // DEBUG
559  // *******************************************************************************************************************
562  HERMES_DEVICE_CALLABLE [[nodiscard]] bool hasNaNs() const {
563  for (int i = 0; i < 4; ++i)
564  for (int j = 0; j < 4; ++j)
565  if (Check::is_nan(m[i][j]))
566  return true;
567  return false;
568  }
572  return mat4::memoryDumpLayout();
573  }
574 protected:
575  mat4 m;
576 };
577 
578 // *********************************************************************************************************************
579 // IO
580 // *********************************************************************************************************************
586 template<typename T>
587 std::ostream &operator<<(std::ostream &os, const Transform2 &m) {
588  for (int i = 0; i < 3; i++) {
589  for (int j = 0; j < 3; j++)
590  os << m[i][j] << " ";
591  os << std::endl;
592  }
593  return os;
594 }
600 template<typename T>
601 std::ostream &operator<<(std::ostream &os, const Transform &m) {
602  for (int i = 0; i < 4; i++) {
603  for (int j = 0; j < 4; j++)
604  os << m[i][j] << " ";
605  os << std::endl;
606  }
607  return os;
608 }
609 
610 } // namespace hermes
611 
612 #endif
613 
Support of bitwise operations for compatible enum classes.
#define HERMES_ENABLE_BITMASK_OPERATORS(x)
Adds bitwise operation support to a given enum class.
Definition: bitmask_operators.h:58
Definition: bbox.h:84
Definition: bbox.h:187
static MemoryDumper::RegionLayout memoryDumpLayout()
Gets memory layout.
Definition: math_element.h:56
HERMES_DEVICE_CALLABLE bool isIdentity() const
Definition: matrix.h:285
T x
0-th normal component
Definition: normal.h:172
T y
1-th normal component
Definition: normal.h:173
T z
2-th normal component
Definition: normal.h:174
T y
1-th component
Definition: point.h:140
T x
0-th component
Definition: point.h:139
T x
0-th component
Definition: point.h:270
T y
1-th component
Definition: point.h:271
T z
2-th component
Definition: point.h:272
Definition: ray.h:39
vec2 d
ray's direction
Definition: ray.h:64
point2 o
ray's origin
Definition: ray.h:63
Definition: ray.h:70
vec3 d
ray's direction
Definition: ray.h:95
point3 o
ray's origin
Definition: ray.h:94
Represents a 2-dimensional transformation.
Definition: transform.h:90
HERMES_DEVICE_CALLABLE mat3 getMatrix() const
Extracts rotation matrix.
Definition: transform.h:209
HERMES_DEVICE_CALLABLE vec2 getTranslate() const
Extracts translation vector.
Definition: transform.h:203
HERMES_DEVICE_CALLABLE point2 operator()(const point2 &p) const
Applies this transform to geometric point.
Definition: transform.h:159
HERMES_DEVICE_CALLABLE void reset()
Sets this transform back to identity.
Definition: transform.cpp:43
HERMES_DEVICE_CALLABLE vec2 getScale() const
Extracts scale vector.
Definition: transform.h:206
static HERMES_DEVICE_CALLABLE Transform2 scale(const vec2 &s)
Creates scale transform.
Definition: transform.cpp:85
HERMES_DEVICE_CALLABLE bbox2 operator()(const bbox2 &b) const
Applies this transform to geometric box.
Definition: transform.h:171
HERMES_DEVICE_CALLABLE Transform2()
Default constructor.
Definition: transform.cpp:31
HERMES_DEVICE_CALLABLE void operator()(const point2 &p, point2 *r) const
Applies this transform to geometric point.
Definition: transform.h:133
HERMES_DEVICE_CALLABLE vec2 operator()(const vec2 &v) const
Applies this transform to geometric vector.
Definition: transform.h:152
HERMES_DEVICE_CALLABLE const real_t * operator[](u32 row_index) const
Gets transform matrix row.
Definition: transform.h:216
static MemoryDumper::RegionLayout memoryDumpLayout()
Gets memory layout.
Definition: transform.h:226
static HERMES_DEVICE_CALLABLE Transform2 translate(const vec2 &v)
Creates translation transform.
Definition: transform.cpp:52
HERMES_DEVICE_CALLABLE Ray2 operator()(const Ray2 &r)
Applies this transform to geometric ray.
Definition: transform.h:183
friend Transform2 inverse(const Transform2 &t)
Gets inverse transform from t.
Definition: transform.h:114
HERMES_DEVICE_CALLABLE real_t * operator[](u32 row_index)
Gets transform matrix row.
Definition: transform.h:220
HERMES_DEVICE_CALLABLE Transform2 operator*(const Transform2 &t) const
Applies this transform to another transform.
Definition: transform.h:193
HERMES_DEVICE_CALLABLE void operator()(const vec2 &v, vec2 *r) const
Applies this transform to geometric vector.
Definition: transform.h:144
static HERMES_DEVICE_CALLABLE Transform2 rotate(real_t angle)
Creates rotation transform.
Definition: transform.cpp:45
Represents a 3-dimensional transformation.
Definition: transform.h:237
HERMES_DEVICE_CALLABLE void applyToPoint(const real_t *p, real_t *r, size_t d=3) const
Applies transform to point (array)
Definition: transform.h:517
HERMES_DEVICE_CALLABLE void operator()(const point3 &p, point3 *r) const
Applies this transform to geometric point.
Definition: transform.h:424
static HERMES_DEVICE_CALLABLE Transform rotateY(real_t angle_in_radians)
Creates a y-axis rotation transform.
Definition: transform.cpp:237
HERMES_DEVICE_CALLABLE Transform operator*(const Transform &t) const
Applies this transform to t.
Definition: transform.h:487
HERMES_DEVICE_CALLABLE Ray3 operator()(const Ray3 &r)
Applies this transform to geometric ray.
Definition: transform.h:455
HERMES_DEVICE_CALLABLE point3 operator()(const point3 &p) const
Applies this transform to geometric point.
Definition: transform.h:411
static HERMES_DEVICE_CALLABLE Transform rotateZ(real_t angle_in_radians)
Creates a z-axis rotation transform.
Definition: transform.cpp:246
static HERMES_DEVICE_CALLABLE Transform translate(const vec3 &d)
Creates a translation transform.
Definition: transform.cpp:214
HERMES_DEVICE_CALLABLE mat3 upperLeftMatrix() const
Gets upper left matrix.
Definition: transform.h:545
HERMES_DEVICE_CALLABLE vec3 getTranslate() const
Gets translation vector.
Definition: transform.h:509
HERMES_DEVICE_CALLABLE friend Transform inverse(const Transform &t)
Computes inverse of a given transform.
Definition: transform.cpp:101
static HERMES_DEVICE_CALLABLE Transform ortho(real_t left, real_t right, real_t bottom, real_t top, real_t near, real_t far, transform_options options=transform_options::left_handed)
Creates an Orthographic Projection.
Definition: transform.cpp:139
HERMES_DEVICE_CALLABLE bool hasNaNs() const
Check for nans.
Definition: transform.h:562
static HERMES_DEVICE_CALLABLE Transform alignVectors(const vec3 &a, const vec3 &b)
Creates a transform that aligns vector a to vector b.
Definition: transform.cpp:288
static HERMES_DEVICE_CALLABLE Transform rotate(real_t angle_in_radians, const vec3 &axis)
Creates a arbitrary-axis rotation transform.
Definition: transform.cpp:255
HERMES_DEVICE_CALLABLE real_t * operator[](u32 row_index)
Gets transformation matrix row.
Definition: transform.h:556
HERMES_DEVICE_CALLABLE void reset()
Sets this transform back to identity.
Definition: transform.cpp:76
HERMES_DEVICE_CALLABLE bool swapsHandedness() const
Checks if this transform swaps coordinate system handedness.
Definition: transform.cpp:78
HERMES_DEVICE_CALLABLE normal3 operator()(const normal3 &n) const
Applies this transform to geometric normal.
Definition: transform.h:445
HERMES_DEVICE_CALLABLE void operator()(const Ray3 &r, Ray3 *ret) const
Applies this transform to geometric ray.
Definition: transform.h:464
HERMES_DEVICE_CALLABLE const real_t * c_matrix() const
Gets raw matrix pointer.
Definition: transform.h:540
static HERMES_DEVICE_CALLABLE Transform scale(real_t x, real_t y, real_t z)
Creates a scale transform.
Definition: transform.cpp:222
HERMES_DEVICE_CALLABLE Transform()
Default constructor.
Definition: transform.cpp:57
mat4 m
transformation matrix
Definition: transform.h:575
HERMES_DEVICE_CALLABLE const real_t * operator[](u32 row_index) const
Gets transformation matrix row.
Definition: transform.h:552
HERMES_DEVICE_CALLABLE const mat4 & matrix() const
Gets transformation matrix.
Definition: transform.h:542
static HERMES_DEVICE_CALLABLE Transform lookAt(const point3 &eye, const point3 &target={0, 0, 0}, const vec3 &up={0, 1, 0}, transform_options options=transform_options::left_handed)
Creates a Look At Transform.
Definition: transform.cpp:103
static HERMES_DEVICE_CALLABLE Transform perspective(real_t fovy_in_degrees, real_t aspect_ratio, real_t near, real_t far, transform_options options=transform_options::left_handed)
Creates a Perspective Projection.
Definition: transform.cpp:178
HERMES_DEVICE_CALLABLE vec3 operator()(const vec3 &v) const
Applies this transform to geometric point.
Definition: transform.h:436
HERMES_DEVICE_CALLABLE point3 operator*(const point3 &p) const
Applies this transform to geometric vector.
Definition: transform.h:494
HERMES_DEVICE_CALLABLE Transform & operator=(const Transform2 &t)
Copy assign from 2d transform.
Definition: transform.h:472
HERMES_DEVICE_CALLABLE bool isIdentity()
Checks if this transform is identity.
Definition: transform.h:512
HERMES_DEVICE_CALLABLE bbox3 operator()(const bbox3 &b) const
Applies this transform to geometric box.
Definition: transform.h:383
static HERMES_DEVICE_CALLABLE Transform rotateX(real_t angle_in_radians)
Creates a x-axis rotation transform.
Definition: transform.cpp:228
HERMES_DEVICE_CALLABLE point3 operator()(const point2 &p) const
Applies this transform to geometric point.
Definition: transform.h:398
static MemoryDumper::RegionLayout memoryDumpLayout()
Gets memory layout.
Definition: transform.h:571
T x
0-th component
Definition: vector.h:155
T y
1-th component
Definition: vector.h:156
T x
0-th component
Definition: vector.h:415
T z
2-th component
Definition: vector.h:417
T y
1-th component
Definition: vector.h:416
Debug, logging and assertion macros.
@ none
default behaviour
float real_t
default floating point type
Definition: defs.h:75
#define HERMES_DEVICE_CALLABLE
Specifies that the function can be called from both host and device sides.
Definition: defs.h:45
uint32_t u32
32 bit size unsigned integer type
Definition: defs.h:88
Math matrix classes.
Geometric normal classes.
Geometric point classes.
static HERMES_DEVICE_CALLABLE std::enable_if_t< std::is_floating_point< T >::value, bool > is_nan(T v)
Checks if number representation is nan
Definition: numeric.h:884
Memory region description.
Definition: memory_dump.h:97
transform_options
Options for transform functions.
Definition: transform.h:47
@ y_up
set y-axis to up
@ y_right
set y-axis to right
@ x_right
set x-axis to right
@ z_up
set z-axis to up
@ z_left
set z-axis to left
@ z_right
set z-axis to right
@ zero_to_one
maps projection range to [0,1], instead of [-1,1]
@ y_down
set y-axis to down
@ left_handed
use left-handed coordinate system
@ x_down
set x-axis to down
@ y_left
set y-axis to left
@ z_down
set z-axis to down
@ x_left
set x-axis to left
@ x_up
set x-axis to up
@ right_handed
use right-handed coordinate system