Browse Source

improve helmet rendering for carthage

djeada 1 month ago
parent
commit
bf485314f8

+ 3 - 3
render/entity/nations/carthage/archer_renderer.cpp

@@ -83,14 +83,14 @@ class ArcherRenderer : public HumanoidRendererBase {
 public:
 public:
   auto get_proportion_scaling() const -> QVector3D override {
   auto get_proportion_scaling() const -> QVector3D override {
 
 
-    return {0.95F, 1.08F, 0.92F};
+    return {1.03F, 1.08F, 0.98F};
   }
   }
 
 
   void adjust_variation(const DrawContext &, uint32_t,
   void adjust_variation(const DrawContext &, uint32_t,
                         VariationParams &variation) const override {
                         VariationParams &variation) const override {
     variation.height_scale *= 1.06F;
     variation.height_scale *= 1.06F;
-    variation.bulk_scale *= 0.72F;
-    variation.stance_width *= 0.80F;
+    variation.bulk_scale *= 0.90F;
+    variation.stance_width *= 0.90F;
     variation.arm_swing_amp *= 0.92F;
     variation.arm_swing_amp *= 0.92F;
   }
   }
 
 

+ 1 - 1
render/entity/nations/carthage/swordsman_renderer.cpp

@@ -98,7 +98,7 @@ struct KnightExtras {
 class KnightRenderer : public HumanoidRendererBase {
 class KnightRenderer : public HumanoidRendererBase {
 public:
 public:
   auto get_proportion_scaling() const -> QVector3D override {
   auto get_proportion_scaling() const -> QVector3D override {
-    return {1.20F, 1.05F, 1.10F};
+    return {0.95F, 1.05F, 0.95F};
   }
   }
 
 
 private:
 private:

+ 55 - 28
render/equipment/helmets/carthage_light_helmet.cpp

@@ -16,6 +16,18 @@ namespace Render::GL {
 using Render::Geom::cylinderBetween;
 using Render::Geom::cylinderBetween;
 using Render::Geom::sphereAt;
 using Render::Geom::sphereAt;
 
 
+static constexpr float kHelmetVerticalLift = 0.14F;
+
+static inline auto helmetLiftVector(const AttachmentFrame &head) -> QVector3D {
+  QVector3D up = head.up;
+  if (up.lengthSquared() < 1e-6F) {
+    up = QVector3D(0.0F, 1.0F, 0.0F);
+  } else {
+    up.normalize();
+  }
+  return up * (head.radius * kHelmetVerticalLift);
+}
+
 static inline void submit_disk(ISubmitter &submitter, const DrawContext &ctx,
 static inline void submit_disk(ISubmitter &submitter, const DrawContext &ctx,
                                const QVector3D &center,
                                const QVector3D &center,
                                const QVector3D &normal_dir, float radius,
                                const QVector3D &normal_dir, float radius,
@@ -72,11 +84,8 @@ void CarthageLightHelmetRenderer::render_bowl(const DrawContext &ctx,
                                               const AttachmentFrame &head,
                                               const AttachmentFrame &head,
                                               ISubmitter &submitter) {
                                               ISubmitter &submitter) {
   const float baseR = head.radius;
   const float baseR = head.radius;
-  const float helmetScale = 1.2F;
+  const float helmetScale = 1.26F;
   const float R = baseR * helmetScale;
   const float R = baseR * helmetScale;
-  auto headPoint = [&](const QVector3D &n) {
-    return HumanoidRendererBase::frameLocalPosition(head, n);
-  };
 
 
   QVector3D up = head.up;
   QVector3D up = head.up;
   if (up.lengthSquared() < 1e-6F) {
   if (up.lengthSquared() < 1e-6F) {
@@ -96,27 +105,32 @@ void CarthageLightHelmetRenderer::render_bowl(const DrawContext &ctx,
   } else {
   } else {
     forward.normalize();
     forward.normalize();
   }
   }
+  QVector3D const helmet_offset = helmetLiftVector(head);
+  QVector3D const helmet_origin = head.origin + helmet_offset;
+  auto headPoint = [&](const QVector3D &n) {
+    return HumanoidRendererBase::frameLocalPosition(head, n) + helmet_offset;
+  };
 
 
-  QVector3D cap_center = head.origin + up * (R * 0.62F);
+  QVector3D cap_center = helmet_origin + up * (R * 0.62F);
   QMatrix4x4 bowl = ctx.model;
   QMatrix4x4 bowl = ctx.model;
   bowl.translate(cap_center);
   bowl.translate(cap_center);
   bowl.scale(R * 0.88F, R * 0.82F, R * 0.88F);
   bowl.scale(R * 0.88F, R * 0.82F, R * 0.88F);
   submitter.mesh(getUnitSphere(), bowl, m_config.leather_color * 0.94F, nullptr,
   submitter.mesh(getUnitSphere(), bowl, m_config.leather_color * 0.94F, nullptr,
                  0.9F);
                  0.9F);
 
 
-  QVector3D taper_top = head.origin + up * (R * 0.48F);
-  QVector3D taper_bot = head.origin + up * (R * 0.26F);
+  QVector3D taper_top = helmet_origin + up * (R * 0.48F);
+  QVector3D taper_bot = helmet_origin + up * (R * 0.26F);
   submitter.mesh(getUnitCylinder(),
   submitter.mesh(getUnitCylinder(),
                  cylinderBetween(ctx.model, taper_top, taper_bot, R * 0.78F),
                  cylinderBetween(ctx.model, taper_top, taper_bot, R * 0.78F),
                  m_config.leather_color * 0.86F, nullptr, 0.92F);
                  m_config.leather_color * 0.86F, nullptr, 0.92F);
 
 
-  QVector3D band_top = head.origin + up * (R * 0.18F);
-  QVector3D band_bot = head.origin + up * (R * 0.06F);
+  QVector3D band_top = helmet_origin + up * (R * 0.24F);
+  QVector3D band_bot = helmet_origin + up * (R * 0.10F);
   submitter.mesh(getUnitCylinder(),
   submitter.mesh(getUnitCylinder(),
                  cylinderBetween(ctx.model, band_top, band_bot, R * 0.92F),
                  cylinderBetween(ctx.model, band_top, band_bot, R * 0.92F),
                  m_config.leather_color * 0.72F, nullptr, 0.95F);
                  m_config.leather_color * 0.72F, nullptr, 0.95F);
 
 
-  QVector3D crest_base = head.origin + up * (R * 0.82F);
+  QVector3D crest_base = helmet_origin + up * (R * 0.82F);
   QVector3D crest_tip = crest_base + up * (R * 0.55F);
   QVector3D crest_tip = crest_base + up * (R * 0.55F);
   submitter.mesh(getUnitCylinder(),
   submitter.mesh(getUnitCylinder(),
                  cylinderBetween(ctx.model, crest_base, crest_tip, R * 0.35F),
                  cylinderBetween(ctx.model, crest_base, crest_tip, R * 0.35F),
@@ -128,27 +142,27 @@ void CarthageLightHelmetRenderer::render_bowl(const DrawContext &ctx,
                  nullptr, 0.93F);
                  nullptr, 0.93F);
 
 
   QVector3D strap_front_top =
   QVector3D strap_front_top =
-      head.origin + up * (R * 0.44F) + forward * (R * 0.60F);
+      helmet_origin + up * (R * 0.44F) + forward * (R * 0.60F);
   QVector3D strap_front_bot =
   QVector3D strap_front_bot =
-      head.origin + up * (R * 0.20F) + forward * (R * 0.70F);
+      helmet_origin + up * (R * 0.20F) + forward * (R * 0.70F);
   submitter.mesh(
   submitter.mesh(
       getUnitCylinder(),
       getUnitCylinder(),
       cylinderBetween(ctx.model, strap_front_top, strap_front_bot, R * 0.20F),
       cylinderBetween(ctx.model, strap_front_top, strap_front_bot, R * 0.20F),
       m_config.bronze_color * 0.85F, nullptr, 0.92F);
       m_config.bronze_color * 0.85F, nullptr, 0.92F);
 
 
   QVector3D strap_left_top =
   QVector3D strap_left_top =
-      head.origin + up * (R * 0.38F) - right * (R * 0.66F);
+      helmet_origin + up * (R * 0.38F) - right * (R * 0.66F);
   QVector3D strap_left_bot =
   QVector3D strap_left_bot =
-      head.origin + up * (R * 0.16F) - right * (R * 0.72F);
+      helmet_origin + up * (R * 0.16F) - right * (R * 0.72F);
   submitter.mesh(
   submitter.mesh(
       getUnitCylinder(),
       getUnitCylinder(),
       cylinderBetween(ctx.model, strap_left_top, strap_left_bot, R * 0.16F),
       cylinderBetween(ctx.model, strap_left_top, strap_left_bot, R * 0.16F),
       m_config.bronze_color * 0.90F, nullptr, 0.95F);
       m_config.bronze_color * 0.90F, nullptr, 0.95F);
 
 
   QVector3D strap_right_top =
   QVector3D strap_right_top =
-      head.origin + up * (R * 0.38F) + right * (R * 0.66F);
+      helmet_origin + up * (R * 0.38F) + right * (R * 0.66F);
   QVector3D strap_right_bot =
   QVector3D strap_right_bot =
-      head.origin + up * (R * 0.16F) + right * (R * 0.72F);
+      helmet_origin + up * (R * 0.16F) + right * (R * 0.72F);
   submitter.mesh(
   submitter.mesh(
       getUnitCylinder(),
       getUnitCylinder(),
       cylinderBetween(ctx.model, strap_right_top, strap_right_bot, R * 0.16F),
       cylinderBetween(ctx.model, strap_right_top, strap_right_bot, R * 0.16F),
@@ -159,10 +173,11 @@ void CarthageLightHelmetRenderer::render_brim(const DrawContext &ctx,
                                               const AttachmentFrame &head,
                                               const AttachmentFrame &head,
                                               ISubmitter &submitter) {
                                               ISubmitter &submitter) {
   const float baseR = head.radius;
   const float baseR = head.radius;
-  const float helmetScale = 1.2F;
+  const float helmetScale = 1.26F;
   const float R = baseR * helmetScale;
   const float R = baseR * helmetScale;
+  QVector3D const helmet_offset = helmetLiftVector(head);
   auto headPoint = [&](const QVector3D &n) {
   auto headPoint = [&](const QVector3D &n) {
-    return HumanoidRendererBase::frameLocalPosition(head, n);
+    return HumanoidRendererBase::frameLocalPosition(head, n) + helmet_offset;
   };
   };
 
 
   auto blade = [&](float sx) {
   auto blade = [&](float sx) {
@@ -176,21 +191,30 @@ void CarthageLightHelmetRenderer::render_brim(const DrawContext &ctx,
   blade(-1.0f);
   blade(-1.0f);
   blade(+1.0f);
   blade(+1.0f);
 
 
-  QVector3D L = headPoint(QVector3D(-0.48f, 0.66f, 0.83f));
-  QVector3D Rg = headPoint(QVector3D(0.48f, 0.66f, 0.83f));
-  submitter.mesh(getUnitCylinder(),
-                 cylinderBetween(ctx.model, L, Rg, R * 0.09f),
-                 m_config.bronze_color * 1.08f, nullptr, 0.95f);
+  // Rebuild the brow arch so it sits above the eyes instead of blocking them.
+  auto connect_brow = [&](const QVector3D &a, const QVector3D &b,
+                          float radius_scale) {
+    submitter.mesh(getUnitCylinder(),
+                   cylinderBetween(ctx.model, a, b, R * radius_scale),
+                   m_config.bronze_color * 1.08f, nullptr, 0.95f);
+  };
+
+  QVector3D brow_left = headPoint(QVector3D(-0.54f, 0.86f, 0.64f));
+  QVector3D brow_mid = headPoint(QVector3D(0.0f, 0.94f, 0.70f));
+  QVector3D brow_right = headPoint(QVector3D(0.54f, 0.86f, 0.64f));
+  connect_brow(brow_left, brow_mid, 0.07f);
+  connect_brow(brow_mid, brow_right, 0.07f);
 }
 }
 
 
 void CarthageLightHelmetRenderer::render_cheek_guards(
 void CarthageLightHelmetRenderer::render_cheek_guards(
     const DrawContext &ctx, const AttachmentFrame &head,
     const DrawContext &ctx, const AttachmentFrame &head,
     ISubmitter &submitter) {
     ISubmitter &submitter) {
   const float baseR = head.radius;
   const float baseR = head.radius;
-  const float helmetScale = 1.2F;
+  const float helmetScale = 1.26F;
   const float R = baseR * helmetScale;
   const float R = baseR * helmetScale;
+  QVector3D const helmet_offset = helmetLiftVector(head);
   auto headPoint = [&](const QVector3D &n) {
   auto headPoint = [&](const QVector3D &n) {
-    return HumanoidRendererBase::frameLocalPosition(head, n);
+    return HumanoidRendererBase::frameLocalPosition(head, n) + helmet_offset;
   };
   };
 
 
   auto side = [&](float sx) {
   auto side = [&](float sx) {
@@ -230,8 +254,9 @@ void CarthageLightHelmetRenderer::render_nasal_guard(
     const DrawContext &ctx, const AttachmentFrame &head,
     const DrawContext &ctx, const AttachmentFrame &head,
     ISubmitter &submitter) {
     ISubmitter &submitter) {
   const float R = head.radius;
   const float R = head.radius;
+  QVector3D const helmet_offset = helmetLiftVector(head);
   auto headPoint = [&](const QVector3D &n) {
   auto headPoint = [&](const QVector3D &n) {
-    return HumanoidRendererBase::frameLocalPosition(head, n);
+    return HumanoidRendererBase::frameLocalPosition(head, n) + helmet_offset;
   };
   };
 
 
   QVector3D top = headPoint(QVector3D(0.0f, 0.70f, 0.80f));
   QVector3D top = headPoint(QVector3D(0.0f, 0.70f, 0.80f));
@@ -260,8 +285,9 @@ void CarthageLightHelmetRenderer::render_crest(const DrawContext &ctx,
                                                const AttachmentFrame &head,
                                                const AttachmentFrame &head,
                                                ISubmitter &submitter) {
                                                ISubmitter &submitter) {
   const float R = head.radius;
   const float R = head.radius;
+  QVector3D const helmet_offset = helmetLiftVector(head);
   auto headPoint = [&](const QVector3D &n) {
   auto headPoint = [&](const QVector3D &n) {
-    return HumanoidRendererBase::frameLocalPosition(head, n);
+    return HumanoidRendererBase::frameLocalPosition(head, n) + helmet_offset;
   };
   };
 
 
   QVector3D left = headPoint(QVector3D(-0.95f, 1.02f, 0.02f));
   QVector3D left = headPoint(QVector3D(-0.95f, 1.02f, 0.02f));
@@ -293,8 +319,9 @@ void CarthageLightHelmetRenderer::render_rivets(const DrawContext &ctx,
                                                 const AttachmentFrame &head,
                                                 const AttachmentFrame &head,
                                                 ISubmitter &submitter) {
                                                 ISubmitter &submitter) {
   const float R = head.radius;
   const float R = head.radius;
+  QVector3D const helmet_offset = helmetLiftVector(head);
   auto headPoint = [&](const QVector3D &n) {
   auto headPoint = [&](const QVector3D &n) {
-    return HumanoidRendererBase::frameLocalPosition(head, n);
+    return HumanoidRendererBase::frameLocalPosition(head, n) + helmet_offset;
   };
   };
   QVector3D col = m_config.bronze_color * 1.25f;
   QVector3D col = m_config.bronze_color * 1.25f;
 
 

+ 5 - 5
render/humanoid/humanoid_specs.h

@@ -22,15 +22,15 @@ struct HumanProportions {
   static constexpr float LOWER_LEG_LEN = 0.47F;
   static constexpr float LOWER_LEG_LEN = 0.47F;
   static constexpr float KNEE_Y = WAIST_Y - UPPER_LEG_LEN;
   static constexpr float KNEE_Y = WAIST_Y - UPPER_LEG_LEN;
 
 
-  static constexpr float SHOULDER_WIDTH = HEAD_HEIGHT * 2.05F;
+  static constexpr float SHOULDER_WIDTH = HEAD_HEIGHT * 1.82F;
   static constexpr float HEAD_RADIUS = HEAD_HEIGHT * 0.41F;
   static constexpr float HEAD_RADIUS = HEAD_HEIGHT * 0.41F;
   static constexpr float NECK_RADIUS = HEAD_RADIUS * 0.39F;
   static constexpr float NECK_RADIUS = HEAD_RADIUS * 0.39F;
-  static constexpr float TORSO_TOP_R = HEAD_RADIUS * 1.20F;
-  static constexpr float TORSO_BOT_R = HEAD_RADIUS * 1.08F;
-  static constexpr float UPPER_ARM_R = HEAD_RADIUS * 0.38F;
+  static constexpr float TORSO_TOP_R = HEAD_RADIUS * 1.25F;
+  static constexpr float TORSO_BOT_R = HEAD_RADIUS * 1.12F;
+  static constexpr float UPPER_ARM_R = HEAD_RADIUS * 0.45F;
   static constexpr float FORE_ARM_R = HEAD_RADIUS * 0.32F;
   static constexpr float FORE_ARM_R = HEAD_RADIUS * 0.32F;
   static constexpr float HAND_RADIUS = HEAD_RADIUS * 0.28F;
   static constexpr float HAND_RADIUS = HEAD_RADIUS * 0.28F;
-  static constexpr float UPPER_LEG_R = HEAD_RADIUS * 0.54F;
+  static constexpr float UPPER_LEG_R = HEAD_RADIUS * 0.64F;
   static constexpr float LOWER_LEG_R = HEAD_RADIUS * 0.44F;
   static constexpr float LOWER_LEG_R = HEAD_RADIUS * 0.44F;
 
 
   static constexpr float UPPER_ARM_LEN = 0.32F;
   static constexpr float UPPER_ARM_LEN = 0.32F;

+ 2 - 1
render/humanoid/rig.cpp

@@ -324,8 +324,9 @@ void HumanoidRendererBase::drawCommonBody(const DrawContext &ctx,
 
 
   const float torso_r = torso_r_base * width_scale;
   const float torso_r = torso_r_base * width_scale;
   float const depth_scale = scaling.z();
   float const depth_scale = scaling.z();
+  // Encourage a fuller chest profile by default while still respecting scaling.
   const float torso_depth_factor =
   const float torso_depth_factor =
-      std::clamp(0.38F + (depth_scale - 1.0F) * 0.15F, 0.30F, 0.62F);
+      std::clamp(0.55F + (depth_scale - 1.0F) * 0.20F, 0.40F, 0.85F);
   const float torso_depth = torso_r * torso_depth_factor;
   const float torso_depth = torso_r * torso_depth_factor;
 
 
   const float y_top_cover = std::max(y_shoulder + 0.04F, y_neck + 0.00F);
   const float y_top_cover = std::max(y_shoulder + 0.04F, y_neck + 0.00F);