texturemap.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. * DoRayMe - a quick and dirty Raytracer
  3. * Texture Map header
  4. *
  5. * Created by Manoël Trapier
  6. * Copyright (c) 2020 986-Studio.
  7. *
  8. */
  9. #ifndef DORAYME_TEXTUREMAP_H
  10. #define DORAYME_TEXTUREMAP_H
  11. #include <math.h>
  12. #include <tuple.h>
  13. #include <uv_pattern.h>
  14. #include <colour.h>
  15. enum TextureMapType
  16. {
  17. SPHERICAL_MAP,
  18. PLANAR_MAP,
  19. CYLINDRICAL_MAP,
  20. CUBIC_MAP
  21. };
  22. class TextureMap : public Pattern
  23. {
  24. private:
  25. TextureMapType type;
  26. UVPattern *pattern;
  27. UVPattern *frontPat, *leftPat, *rightPat, *backPat, *upPat, *downPat;
  28. public:
  29. TextureMap(TextureMapType type, UVPattern *pattern) : Pattern(Colour(0, 0, 0), Colour(0, 0, 0)),
  30. type(type), pattern(pattern) { };
  31. static void sphericalMap(Tuple point, double &u, double &v) {
  32. /* First compute the azimuthal angle
  33. * -π < theta <= π
  34. * angle increases clockwise as viewed from above,
  35. * which is opposite of what we want, but we'll fix it later.
  36. */
  37. double theta = atan2(point.x, point.z);
  38. /* vec is the vector pointing from the sphere's origin (the world origin)
  39. * to the point, which will also happen to be exactly equal to the sphere's
  40. * radius.
  41. */
  42. Tuple vec = Vector(point.x, point.y, point.z);
  43. double radius = vec.magnitude();
  44. /* Let's compute the polar angle
  45. * 0 <= phi <= π
  46. */
  47. double phi = acos(point.y / radius);
  48. /* -0.5 < raw_u <= 0.5 */
  49. double raw_u = theta / (2 * M_PI);
  50. /* 0 <= u < 1
  51. * here's also where we fix the direction of u. Subtract it from 1,
  52. * so that it increases counterclockwise as viewed from above.
  53. */
  54. u = 1 - (raw_u + 0.5);
  55. /* We want v to be 0 at the south pole of the sphere,
  56. * and 1 at the north pole, so we have to "flip it over"
  57. * by subtracting it from 1.
  58. */
  59. v = 1 - phi / M_PI;
  60. }
  61. static void planarMap(Tuple point, double &u, double &v) {
  62. u = modulo(point.x, 1.0);
  63. v = modulo(point.z, 1.0);
  64. }
  65. static void cylindricalMap(Tuple point, double &u, double &v) {
  66. /* Let's get the azimuthal angle, same as with the spherical mapping */
  67. double theta = atan2(point.x , point.z);
  68. double raw_u = theta / (2 * M_PI);
  69. u = 1 - (raw_u + 0.5);
  70. v = modulo(point.y, 1.0);
  71. }
  72. enum CubeFaces {
  73. CUBE_LEFT,
  74. CUBE_RIGHT,
  75. CUBE_FRONT,
  76. CUBE_BACK,
  77. CUBE_UP,
  78. CUBE_DOWN,
  79. };
  80. static CubeFaces faceFromPoint(Tuple point) {
  81. double abs_x = fabs(point.x);
  82. double abs_y = fabs(point.y);
  83. double abs_z = fabs(point.z);
  84. double coord = max3(abs_x, abs_y, abs_z);
  85. if (coord == point.x) { return CUBE_RIGHT; }
  86. if (coord == -point.x) { return CUBE_LEFT; }
  87. if (coord == point.y) { return CUBE_UP; }
  88. if (coord == -point.y) { return CUBE_DOWN; }
  89. if (coord == point.z) { return CUBE_FRONT; }
  90. return CUBE_BACK;
  91. }
  92. static void cubeUBFront(Tuple point, double &u, double &v) {
  93. u = modulo(point.x + 1, 2.0) / 2.0;
  94. v = modulo(point.y + 1, 2.0) / 2.0;
  95. }
  96. static void cubeUBBack(Tuple point, double &u, double &v) {
  97. u = modulo(1 - point.x, 2.0) / 2.0;
  98. v = modulo(point.y + 1, 2.0) / 2.0;
  99. }
  100. static void cubeUBLeft(Tuple point, double &u, double &v) {
  101. u = modulo(point.z + 1, 2.0) / 2.0;
  102. v = modulo(point.y + 1, 2.0) / 2.0;
  103. }
  104. static void cubeUBRight(Tuple point, double &u, double &v) {
  105. u = modulo(1 - point.z, 2.0) / 2.0;
  106. v = modulo(point.y + 1, 2.0) / 2.0;
  107. }
  108. static void cubeUBUp(Tuple point, double &u, double &v) {
  109. u = modulo(point.x + 1, 2.0) / 2.0;
  110. v = modulo(1 - point.z, 2.0) / 2.0;
  111. }
  112. static void cubeUBDown(Tuple point, double &u, double &v) {
  113. u = modulo(point.x + 1, 2.0) / 2.0;
  114. v = modulo(point.z + 1, 2.0) / 2.0;
  115. }
  116. void setCubePattern(UVPattern *front, UVPattern *left, UVPattern *right,
  117. UVPattern *back, UVPattern *up, UVPattern *down)
  118. {
  119. this->frontPat = front;
  120. this->leftPat = left;
  121. this->rightPat = right;
  122. this->backPat = back;
  123. this->upPat = up;
  124. this->downPat = down;
  125. }
  126. Colour patternAt(Tuple point)
  127. {
  128. double u,v;
  129. if (this->type == CUBIC_MAP)
  130. {
  131. CubeFaces face = TextureMap::faceFromPoint(point);
  132. UVPattern *facePat;
  133. switch(face)
  134. {
  135. default:
  136. case CUBE_LEFT: facePat = this->leftPat; TextureMap::cubeUBLeft(point, u, v); break;
  137. case CUBE_RIGHT: facePat = this->rightPat; TextureMap::cubeUBRight(point, u, v); break;
  138. case CUBE_FRONT: facePat = this->frontPat; TextureMap::cubeUBFront(point, u, v); break;
  139. case CUBE_BACK: facePat = this->backPat; TextureMap::cubeUBBack(point, u, v); break;
  140. case CUBE_UP: facePat = this->upPat; TextureMap::cubeUBUp(point, u, v); break;
  141. case CUBE_DOWN: facePat = this->downPat; TextureMap::cubeUBDown(point, u, v); break;
  142. }
  143. return facePat->uvPatternAt(u, v);
  144. }
  145. else
  146. {
  147. switch (this->type)
  148. {
  149. default:
  150. case SPHERICAL_MAP:
  151. this->sphericalMap(point, u, v);
  152. break;
  153. case PLANAR_MAP:
  154. this->planarMap(point, u, v);
  155. break;
  156. case CYLINDRICAL_MAP:
  157. this->cylindricalMap(point, u, v);
  158. break;
  159. }
  160. return this->pattern->uvPatternAt(u, v);
  161. }
  162. }
  163. void dumpMe(FILE *fp) {
  164. fprintf(fp, "\"Type\": \"TextureMap\",\n");
  165. Pattern::dumpMe(fp);
  166. }
  167. };
  168. #endif /* DORAYME_TEXTUREMAP_H */