shield_renderer.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #include "shield_renderer.h"
  2. #include "../../geom/transforms.h"
  3. #include "../../gl/primitives.h"
  4. #include "../../humanoid/rig.h"
  5. #include "../../submitter.h"
  6. #include <QMatrix4x4>
  7. #include <QVector3D>
  8. #include <algorithm>
  9. #include <cmath>
  10. #include <numbers>
  11. namespace Render::GL {
  12. using Render::Geom::cylinder_between;
  13. using Render::Geom::sphere_at;
  14. ShieldRenderer::ShieldRenderer(ShieldRenderConfig config)
  15. : m_config(std::move(config)) {}
  16. void ShieldRenderer::render(const DrawContext &ctx, const BodyFrames &frames,
  17. const HumanoidPalette &palette,
  18. const HumanoidAnimationContext &,
  19. ISubmitter &submitter) {
  20. constexpr float k_scale_factor = 2.5F;
  21. constexpr float k_shield_yaw_degrees = -70.0F;
  22. QMatrix4x4 rot;
  23. rot.rotate(k_shield_yaw_degrees, 0.0F, 1.0F, 0.0F);
  24. const QVector3D n = rot.map(QVector3D(0.0F, 0.0F, 1.0F));
  25. const QVector3D axis_x = rot.map(QVector3D(1.0F, 0.0F, 0.0F));
  26. const QVector3D axis_y = rot.map(QVector3D(0.0F, 1.0F, 0.0F));
  27. float const base_extent = m_config.shield_radius * k_scale_factor;
  28. float const shield_width = base_extent;
  29. float const shield_height = base_extent * m_config.shield_aspect;
  30. float const min_extent = std::min(shield_width, shield_height);
  31. QVector3D shield_center = frames.hand_l.origin +
  32. axis_x * (-shield_width * 0.55F) +
  33. axis_y * (-0.20F) + n * (0.06F);
  34. const float plate_half = 0.0015F;
  35. const float plate_full = plate_half * 2.0F;
  36. {
  37. QMatrix4x4 m = ctx.model;
  38. m.translate(shield_center + n * plate_half);
  39. m.rotate(k_shield_yaw_degrees, 0.0F, 1.0F, 0.0F);
  40. m.scale(shield_width, shield_height, plate_full);
  41. submitter.mesh(get_unit_cylinder(), m, m_config.shield_color, nullptr, 1.0F,
  42. m_config.material_id);
  43. }
  44. {
  45. QMatrix4x4 m = ctx.model;
  46. m.translate(shield_center - n * plate_half);
  47. m.rotate(k_shield_yaw_degrees, 0.0F, 1.0F, 0.0F);
  48. m.scale(shield_width * 0.985F, shield_height * 0.985F, plate_full);
  49. submitter.mesh(get_unit_cylinder(), m, palette.leather * 0.8F, nullptr,
  50. 1.0F, m_config.material_id);
  51. }
  52. auto draw_ring_rotated = [&](float width, float height, float thickness,
  53. const QVector3D &color) {
  54. constexpr int k_segments = 18;
  55. for (int i = 0; i < k_segments; ++i) {
  56. float const a0 = (float)i / k_segments * 2.0F * std::numbers::pi_v<float>;
  57. float const a1 =
  58. (float)(i + 1) / k_segments * 2.0F * std::numbers::pi_v<float>;
  59. QVector3D const v0(width * std::cos(a0), height * std::sin(a0), 0.0F);
  60. QVector3D const v1(width * std::cos(a1), height * std::sin(a1), 0.0F);
  61. QVector3D const p0 = shield_center + rot.map(v0);
  62. QVector3D const p1 = shield_center + rot.map(v1);
  63. submitter.mesh(get_unit_cylinder(),
  64. cylinder_between(ctx.model, p0, p1, thickness), color,
  65. nullptr, 1.0F, m_config.material_id);
  66. }
  67. };
  68. draw_ring_rotated(shield_width, shield_height, min_extent * 0.010F,
  69. m_config.trim_color * 0.95F);
  70. draw_ring_rotated(shield_width * 0.72F, shield_height * 0.72F,
  71. min_extent * 0.006F, palette.leather * 0.90F);
  72. {
  73. QMatrix4x4 m = ctx.model;
  74. m.translate(shield_center + n * (0.02F * k_scale_factor));
  75. m.scale(0.045F * k_scale_factor);
  76. submitter.mesh(get_unit_sphere(), m, m_config.metal_color, nullptr, 1.0F,
  77. m_config.material_id);
  78. }
  79. {
  80. QVector3D const grip_a = shield_center - axis_x * 0.035F - n * 0.030F;
  81. QVector3D const grip_b = shield_center + axis_x * 0.035F - n * 0.030F;
  82. submitter.mesh(get_unit_cylinder(),
  83. cylinder_between(ctx.model, grip_a, grip_b, 0.010F),
  84. palette.leather, nullptr, 1.0F, m_config.material_id);
  85. }
  86. if (m_config.has_cross_decal) {
  87. QVector3D const center_front =
  88. shield_center + n * (plate_full * 0.5F + 0.0015F);
  89. float const bar_radius = min_extent * 0.10F;
  90. QVector3D const top = center_front + axis_y * (shield_height * 0.90F);
  91. QVector3D const bot = center_front - axis_y * (shield_height * 0.90F);
  92. submitter.mesh(get_unit_cylinder(),
  93. cylinder_between(ctx.model, top, bot, bar_radius),
  94. m_config.trim_color, nullptr, 1.0F, m_config.material_id);
  95. QVector3D const left = center_front - axis_x * (shield_width * 0.90F);
  96. QVector3D const right = center_front + axis_x * (shield_width * 0.90F);
  97. submitter.mesh(get_unit_cylinder(),
  98. cylinder_between(ctx.model, left, right, bar_radius),
  99. m_config.trim_color, nullptr, 1.0F, m_config.material_id);
  100. }
  101. }
  102. } // namespace Render::GL