General Purpose library for Freestanding C++ and POSIX systems
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

113 righe
2.6 KiB

  1. #pragma once
  2. #include "gp_config.hpp"
  3. #include "gp/algorithm/min_of.hpp"
  4. #include "gp/allocator/buddy.hpp"
  5. #include "gp/function.hpp"
  6. #include "gp/indexed_array.hpp"
  7. #include "gp/math.hpp"
  8. using vec2 = gp::vec2_g<>;
  9. using vec3 = gp::vec3_g<>;
  10. using vec4 = gp::vec4_g<>;
  11. struct camera{
  12. vec3 position;
  13. vec3 normal;
  14. };
  15. using index_t = size_t;
  16. using distance_t = gp_config::rendering::default_type;
  17. using color_t = GP_CONFIG__RENDERING__COLOR_T;
  18. struct render_point{
  19. distance_t distance;
  20. index_t material;
  21. bool operator<(const render_point& rhs) {
  22. return distance < rhs.distance;
  23. }
  24. };
  25. using sdf_t = gp::function<render_point(vec3&)>;
  26. using material_t = gp::function<color_t(vec3&)>;
  27. /**
  28. * @brief A pure ray-marching renderer. Prints pixels on order.
  29. */
  30. class renderer {
  31. using g_t = gp_config::rendering::default_type;
  32. constexpr static auto epsilon = gp_config::rendering::epsilon;
  33. public:
  34. gp::indexed_array<sdf_t, 4096> scene_elements;
  35. gp::indexed_array<material_t, 4096> materials;
  36. gp::buddy<> allocator;
  37. material_t sky_box;
  38. vec2 _resolution{128,64};
  39. camera _camera{{0, 0, -1}, {0, 0, 0}};
  40. vec2 _fov{90, 45};
  41. distance_t projection_start = 1;
  42. distance_t projection_end = 50;
  43. size_t passes = 12;
  44. renderer(gp::buffer<char> allocation_buffer)
  45. : allocator(allocation_buffer.begin().data, allocation_buffer.size())
  46. , sky_box{gp::reference_wrapper<gp::buddy<>>{allocator}}
  47. {}
  48. render_point sdf(vec3& render_target) {
  49. return gp::min_of(
  50. scene_elements.begin(),
  51. scene_elements.end(),
  52. [&](auto& p){
  53. return p(render_target);
  54. }
  55. );
  56. }
  57. auto& get_allocator() {
  58. return allocator;
  59. }
  60. color_t render(vec2 pixel) {
  61. g_t depth = projection_start;
  62. vec3 target = _camera.normal;
  63. auto half_res = _resolution/vec2{2.0, 2.0};
  64. pixel = pixel - half_res;
  65. pixel = pixel / half_res;
  66. pixel = pixel * _fov;
  67. pixel = pixel / vec2{180, 180} * vec2{gp::pi<g_t>,gp::pi<g_t>};
  68. // Y-rot (adjusts x)
  69. target = vec3{
  70. target.x*gp::cos(pixel.x) + target.z*gp::sin(pixel.x),
  71. target.y,
  72. -target.x*gp::sin(pixel.x)+target.z*gp::cos(pixel.x)
  73. };
  74. // X-rot (adjusts y)
  75. target = vec3{
  76. target.x,
  77. target.y*gp::cos(pixel.y) - target.z*gp::sin(pixel.y),
  78. target.y*gp::sin(pixel.y) + target.z*gp::cos(pixel.y)
  79. };
  80. vec3 render_target{_camera.position};
  81. for(int i = 1; i < passes; ++i) {
  82. render_point distance = sdf(render_target);
  83. if(distance.distance < epsilon) {
  84. return materials[distance.material](render_target);
  85. }
  86. depth += distance.distance;
  87. if(depth >= projection_end) {
  88. break;
  89. }
  90. render_target = _camera.position+depth*target;
  91. }
  92. return sky_box(render_target);
  93. }
  94. };