roman_scutum.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #include "roman_scutum.h"
  2. #include "../../geom/transforms.h"
  3. #include "../../gl/primitives.h"
  4. #include "../../humanoid/humanoid_math.h"
  5. #include "../../humanoid/humanoid_specs.h"
  6. #include "../../humanoid/rig.h"
  7. #include "../../humanoid/style_palette.h"
  8. #include "../../submitter.h"
  9. #include <QMatrix4x4>
  10. #include <QVector3D>
  11. #include <cmath>
  12. #include <numbers>
  13. namespace Render::GL {
  14. using Render::Geom::cylinder_between;
  15. using Render::Geom::sphere_at;
  16. using Render::GL::Humanoid::saturate_color;
  17. void RomanScutumRenderer::render(const DrawContext &ctx,
  18. const BodyFrames &frames,
  19. const HumanoidPalette &palette,
  20. const HumanoidAnimationContext &anim,
  21. ISubmitter &submitter) {
  22. (void)anim;
  23. const AttachmentFrame &hand_l = frames.hand_l;
  24. if (hand_l.radius <= 0.0F) {
  25. return;
  26. }
  27. using HP = HumanProportions;
  28. QVector3D const shield_red =
  29. saturate_color(palette.cloth * QVector3D(1.5F, 0.3F, 0.3F));
  30. QVector3D const bronze_color =
  31. saturate_color(palette.metal * QVector3D(1.3F, 1.0F, 0.5F));
  32. QVector3D const wood_color = saturate_color(QVector3D(0.5F, 0.35F, 0.25F));
  33. constexpr float shield_height = 1.2F;
  34. constexpr float shield_width = 0.65F;
  35. constexpr float shield_curve = 0.25F;
  36. constexpr float rim_thickness = 0.015F;
  37. constexpr float boss_radius = 0.12F;
  38. QVector3D const shield_center = hand_l.origin + hand_l.forward * 0.15F;
  39. QVector3D const shield_up = hand_l.up;
  40. QVector3D const shield_right = hand_l.right;
  41. QVector3D const shield_forward = hand_l.forward;
  42. constexpr int vertical_segments = 12;
  43. constexpr int horizontal_segments = 16;
  44. for (int v = 0; v < vertical_segments; ++v) {
  45. for (int h = 0; h < horizontal_segments; ++h) {
  46. float const v_t =
  47. static_cast<float>(v) / static_cast<float>(vertical_segments);
  48. float const h_t =
  49. static_cast<float>(h) / static_cast<float>(horizontal_segments);
  50. float const y_local = (v_t - 0.5F) * shield_height;
  51. float const x_local = (h_t - 0.5F) * shield_width;
  52. float const curve_offset =
  53. shield_curve * (1.0F - std::abs(x_local / (shield_width * 0.5F)));
  54. QVector3D segment_pos = shield_center + shield_up * y_local +
  55. shield_right * x_local +
  56. shield_forward * curve_offset;
  57. QMatrix4x4 m = ctx.model;
  58. m.translate(segment_pos);
  59. m.scale(0.03F, 0.05F, 0.01F);
  60. QVector3D segment_color = shield_red * (1.0F + (v % 2) * 0.05F - 0.025F);
  61. submitter.mesh(get_unit_sphere(), m, segment_color, nullptr, 1.0F, 4);
  62. }
  63. }
  64. constexpr int ridge_segments = 10;
  65. for (int i = 0; i < ridge_segments; ++i) {
  66. float const t =
  67. static_cast<float>(i) / static_cast<float>(ridge_segments - 1);
  68. float const y_local = (t - 0.5F) * shield_height * 0.9F;
  69. QVector3D ridge_pos = shield_center + shield_up * y_local +
  70. shield_forward * (shield_curve + 0.02F);
  71. QMatrix4x4 m = ctx.model;
  72. m.translate(ridge_pos);
  73. m.scale(0.025F, 0.06F, 0.015F);
  74. submitter.mesh(get_unit_sphere(), m, bronze_color * 0.9F, nullptr, 1.0F, 4);
  75. }
  76. QVector3D const boss_center =
  77. shield_center + shield_forward * (shield_curve + 0.08F);
  78. for (int i = 0; i < 12; ++i) {
  79. float const angle =
  80. (static_cast<float>(i) / 12.0F) * 2.0F * std::numbers::pi_v<float>;
  81. QVector3D ring_pos = boss_center +
  82. shield_right * (boss_radius * std::cos(angle)) +
  83. shield_up * (boss_radius * std::sin(angle));
  84. QMatrix4x4 m = ctx.model;
  85. m.translate(ring_pos);
  86. m.scale(0.018F);
  87. submitter.mesh(get_unit_sphere(), m, bronze_color, nullptr, 1.0F, 4);
  88. }
  89. submitter.mesh(get_unit_sphere(),
  90. sphere_at(ctx.model, boss_center, boss_radius * 0.8F),
  91. bronze_color * 1.1F, nullptr, 1.0F, 4);
  92. float const y_pos = shield_height * 0.48F;
  93. for (int i = 0; i < 10; ++i) {
  94. float const t = static_cast<float>(i) / 9.0F;
  95. float const x_local = (t - 0.5F) * shield_width * 0.95F;
  96. float const curve_off =
  97. shield_curve * (1.0F - std::abs(x_local / (shield_width * 0.5F)));
  98. QVector3D rim_pos = shield_center + shield_up * y_pos +
  99. shield_right * x_local + shield_forward * curve_off;
  100. QMatrix4x4 m = ctx.model;
  101. m.translate(rim_pos);
  102. m.scale(rim_thickness);
  103. submitter.mesh(get_unit_sphere(), m, bronze_color * 0.95F, nullptr, 1.0F,
  104. 4);
  105. }
  106. float const y_pos_bot = -shield_height * 0.48F;
  107. for (int i = 0; i < 10; ++i) {
  108. float const t = static_cast<float>(i) / 9.0F;
  109. float const x_local = (t - 0.5F) * shield_width * 0.95F;
  110. float const curve_off =
  111. shield_curve * (1.0F - std::abs(x_local / (shield_width * 0.5F)));
  112. QVector3D rim_pos = shield_center + shield_up * y_pos_bot +
  113. shield_right * x_local + shield_forward * curve_off;
  114. QMatrix4x4 m = ctx.model;
  115. m.translate(rim_pos);
  116. m.scale(rim_thickness);
  117. submitter.mesh(get_unit_sphere(), m, bronze_color * 0.95F, nullptr, 1.0F,
  118. 4);
  119. }
  120. for (int side = 0; side < 2; ++side) {
  121. float const x_pos_side = (side == 0 ? -1.0F : 1.0F) * shield_width * 0.48F;
  122. float const curve_off =
  123. shield_curve * (1.0F - std::abs(x_pos_side / (shield_width * 0.5F)));
  124. for (int i = 0; i < 12; ++i) {
  125. float const t = static_cast<float>(i) / 11.0F;
  126. float const y_local = (t - 0.5F) * shield_height * 0.95F;
  127. QVector3D rim_pos = shield_center + shield_up * y_local +
  128. shield_right * x_pos_side +
  129. shield_forward * curve_off;
  130. QMatrix4x4 m = ctx.model;
  131. m.translate(rim_pos);
  132. m.scale(rim_thickness);
  133. submitter.mesh(get_unit_sphere(), m, bronze_color * 0.95F, nullptr, 1.0F,
  134. 4);
  135. }
  136. }
  137. for (int i = 0; i < 8; ++i) {
  138. float const angle =
  139. (static_cast<float>(i) / 8.0F) * 2.0F * std::numbers::pi_v<float>;
  140. float const rivet_dist = boss_radius * 1.3F;
  141. QVector3D rivet_pos = boss_center +
  142. shield_right * (rivet_dist * std::cos(angle)) +
  143. shield_up * (rivet_dist * std::sin(angle));
  144. QMatrix4x4 m = ctx.model;
  145. m.translate(rivet_pos);
  146. m.scale(0.012F);
  147. submitter.mesh(get_unit_sphere(), m, bronze_color * 1.15F, nullptr, 1.0F,
  148. 4);
  149. }
  150. }
  151. } // namespace Render::GL