roman_armor.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #include "roman_armor.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::cone_from_to;
  15. using Render::Geom::cylinder_between;
  16. using Render::Geom::sphere_at;
  17. using Render::GL::Humanoid::saturate_color;
  18. void RomanHeavyArmorRenderer::render(const DrawContext &ctx,
  19. const BodyFrames &frames,
  20. const HumanoidPalette &palette,
  21. const HumanoidAnimationContext &anim,
  22. ISubmitter &submitter) {
  23. (void)anim;
  24. const AttachmentFrame &torso = frames.torso;
  25. const AttachmentFrame &waist = frames.waist;
  26. const AttachmentFrame &head = frames.head;
  27. if (torso.radius <= 0.0F) {
  28. return;
  29. }
  30. using HP = HumanProportions;
  31. QVector3D const steel_color =
  32. saturate_color(palette.metal * QVector3D(0.88F, 0.92F, 1.08F));
  33. QVector3D const brass_color =
  34. saturate_color(palette.metal * QVector3D(1.25F, 1.05F, 0.62F));
  35. QVector3D const leather_color =
  36. saturate_color(palette.leather * QVector3D(0.58F, 0.38F, 0.26F));
  37. auto safeNormal = [](const QVector3D &v, const QVector3D &fallback) {
  38. return (v.lengthSquared() > 1e-6F) ? v.normalized() : fallback;
  39. };
  40. QVector3D up = safeNormal(torso.up, QVector3D(0.0F, 1.0F, 0.0F));
  41. QVector3D right = safeNormal(torso.right, QVector3D(1.0F, 0.0F, 0.0F));
  42. QVector3D forward = safeNormal(torso.forward, QVector3D(0.0F, 0.0F, 1.0F));
  43. QVector3D waist_up = safeNormal(waist.up, up);
  44. QVector3D head_up = safeNormal(head.up, up);
  45. float const torso_r = torso.radius;
  46. float const torso_depth =
  47. (torso.depth > 0.0F) ? torso.depth : torso_r * 0.75F;
  48. auto depth_scale_for = [&](float base) {
  49. float const ratio = torso_depth / std::max(0.001F, torso_r);
  50. return std::max(0.08F, base * ratio);
  51. };
  52. float const waist_r =
  53. waist.radius > 0.0F ? waist.radius : torso.radius * 0.88F;
  54. float const head_r = head.radius > 0.0F ? head.radius : torso.radius * 0.58F;
  55. QVector3D top = torso.origin + up * (torso_r * 0.60F);
  56. QVector3D head_guard = head.origin - head_up * (head_r * 1.30F);
  57. if (QVector3D::dotProduct(top - head_guard, up) > 0.0F) {
  58. top = head_guard - up * (torso_r * 0.05F);
  59. }
  60. QVector3D bottom = waist.origin - waist_up * (waist_r * 0.45F);
  61. top += forward * (torso_r * 0.010F);
  62. bottom += forward * (torso_r * 0.010F);
  63. QMatrix4x4 plates = cylinder_between(ctx.model, top, bottom, torso_r * 1.24F);
  64. plates.scale(1.18F, 1.0F, depth_scale_for(1.10F));
  65. Mesh *torso_mesh = torso_mesh_without_bottom_cap();
  66. submitter.mesh(torso_mesh != nullptr ? torso_mesh : get_unit_torso(), plates,
  67. steel_color, nullptr, 1.0F, 1);
  68. auto renderShoulderGuard = [&](const QVector3D &shoulder_pos,
  69. const QVector3D &outward) {
  70. QVector3D upper_pos = shoulder_pos + outward * 0.03F + forward * 0.01F;
  71. QMatrix4x4 upper = ctx.model;
  72. upper.translate(upper_pos);
  73. upper.scale(HP::UPPER_ARM_R * 1.90F, HP::UPPER_ARM_R * 0.42F,
  74. HP::UPPER_ARM_R * 1.65F);
  75. submitter.mesh(get_unit_sphere(), upper, steel_color * 0.98F, nullptr, 1.0F,
  76. 1);
  77. QVector3D lower_pos = upper_pos - up * 0.06F + outward * 0.02F;
  78. QMatrix4x4 lower = ctx.model;
  79. lower.translate(lower_pos);
  80. lower.scale(HP::UPPER_ARM_R * 1.68F, HP::UPPER_ARM_R * 0.38F,
  81. HP::UPPER_ARM_R * 1.48F);
  82. submitter.mesh(get_unit_sphere(), lower, steel_color * 0.94F, nullptr, 1.0F,
  83. 1);
  84. QMatrix4x4 rivet = ctx.model;
  85. rivet.translate(upper_pos + forward * 0.04F);
  86. rivet.scale(0.012F);
  87. submitter.mesh(get_unit_sphere(), rivet, brass_color, nullptr, 1.0F);
  88. };
  89. renderShoulderGuard(frames.shoulder_l.origin, -right);
  90. renderShoulderGuard(frames.shoulder_r.origin, right);
  91. }
  92. void RomanLightArmorRenderer::render(const DrawContext &ctx,
  93. const BodyFrames &frames,
  94. const HumanoidPalette &palette,
  95. const HumanoidAnimationContext &anim,
  96. ISubmitter &submitter) {
  97. (void)anim;
  98. (void)palette;
  99. const AttachmentFrame &torso = frames.torso;
  100. const AttachmentFrame &waist = frames.waist;
  101. const AttachmentFrame &head = frames.head;
  102. if (torso.radius <= 0.0F) {
  103. return;
  104. }
  105. QVector3D leather_color = QVector3D(0.44F, 0.30F, 0.19F);
  106. QVector3D leather_shadow = leather_color * 0.90F;
  107. QVector3D leather_highlight = leather_color * 1.08F;
  108. QVector3D up = torso.up.normalized();
  109. QVector3D right = torso.right.normalized();
  110. QVector3D forward = torso.forward.normalized();
  111. float const torso_r = torso.radius;
  112. float const torso_depth =
  113. (torso.depth > 0.0F) ? torso.depth : torso_r * 0.75F;
  114. float const waist_r =
  115. waist.radius > 0.0F ? waist.radius : torso.radius * 0.85F;
  116. float const head_r = head.radius > 0.0F ? head.radius : torso.radius * 0.6F;
  117. QVector3D head_up =
  118. (head.up.lengthSquared() > 1e-6F) ? head.up.normalized() : up;
  119. QVector3D waist_up =
  120. (waist.up.lengthSquared() > 1e-6F) ? waist.up.normalized() : up;
  121. QVector3D top = torso.origin + up * (torso_r * 0.50F);
  122. QVector3D head_guard =
  123. head.origin -
  124. head_up * ((head_r > 0.0F ? head_r : torso_r * 0.6F) * 1.45F);
  125. if (QVector3D::dotProduct(top - head_guard, up) > 0.0F) {
  126. top = head_guard - up * (torso_r * 0.05F);
  127. }
  128. QVector3D bottom = waist.origin - waist_up * (waist_r * 0.24F);
  129. top += forward * (torso_r * 0.010F);
  130. bottom += forward * (torso_r * 0.010F);
  131. float main_radius = torso_r * 1.26F;
  132. float const main_depth = torso_depth * 1.24F;
  133. QMatrix4x4 cuirass = cylinder_between(ctx.model, top, bottom, main_radius);
  134. cuirass.scale(1.0F, 1.0F, std::max(0.15F, main_depth / main_radius));
  135. Mesh *torso_mesh = torso_mesh_without_bottom_cap();
  136. submitter.mesh(torso_mesh != nullptr ? torso_mesh : get_unit_torso(), cuirass,
  137. leather_highlight, nullptr, 1.0F, 1);
  138. auto strap = [&](float side) {
  139. QVector3D shoulder_anchor =
  140. top + right * (torso_r * 0.54F * side) - up * (torso_r * 0.04F);
  141. QVector3D chest_anchor =
  142. shoulder_anchor - up * (torso_r * 0.82F) + forward * (torso_r * 0.22F);
  143. submitter.mesh(get_unit_cylinder(),
  144. cylinder_between(ctx.model, shoulder_anchor, chest_anchor,
  145. torso_r * 0.10F),
  146. leather_highlight * 0.95F, nullptr, 1.0F, 1);
  147. };
  148. strap(1.0F);
  149. strap(-1.0F);
  150. QVector3D front_panel_top =
  151. top + forward * (torso_depth * 0.35F) - up * (torso_r * 0.06F);
  152. QVector3D front_panel_bottom =
  153. bottom + forward * (torso_depth * 0.38F) + up * (torso_r * 0.03F);
  154. QMatrix4x4 front_panel = cylinder_between(
  155. ctx.model, front_panel_top, front_panel_bottom, torso_r * 0.48F);
  156. front_panel.scale(1.18F, 1.0F,
  157. std::max(0.22F, (torso_depth * 0.76F) / (torso_r * 0.76F)));
  158. submitter.mesh(torso_mesh != nullptr ? torso_mesh : get_unit_torso(),
  159. front_panel, leather_highlight, nullptr, 1.0F, 1);
  160. QVector3D back_panel_top =
  161. top - forward * (torso_depth * 0.32F) - up * (torso_r * 0.05F);
  162. QVector3D back_panel_bottom =
  163. bottom - forward * (torso_depth * 0.34F) + up * (torso_r * 0.02F);
  164. QMatrix4x4 back_panel = cylinder_between(ctx.model, back_panel_top,
  165. back_panel_bottom, torso_r * 0.50F);
  166. back_panel.scale(1.18F, 1.0F,
  167. std::max(0.22F, (torso_depth * 0.74F) / (torso_r * 0.80F)));
  168. submitter.mesh(torso_mesh != nullptr ? torso_mesh : get_unit_torso(),
  169. back_panel, leather_shadow, nullptr, 1.0F, 1);
  170. }
  171. } // namespace Render::GL