浏览代码

Phase 1: Extract shared types & helpers (humanoid_specs, humanoid_math, palette)

Co-authored-by: djeada <[email protected]>
copilot-swe-agent[bot] 2 月之前
父节点
当前提交
2bcc3008c8
共有 7 个文件被更改,包括 175 次插入119 次删除
  1. 2 0
      render/CMakeLists.txt
  2. 14 119
      render/entity/archer_renderer.cpp
  3. 24 0
      render/humanoid_math.cpp
  4. 31 0
      render/humanoid_math.h
  5. 47 0
      render/humanoid_specs.h
  6. 38 0
      render/palette.cpp
  7. 19 0
      render/palette.h

+ 2 - 0
render/CMakeLists.txt

@@ -27,6 +27,8 @@ add_library(render_gl STATIC
     geom/flag.cpp
     geom/patrol_flags.cpp
     geom/transforms.cpp
+    humanoid_math.cpp
+    palette.cpp
 )
 
 target_include_directories(render_gl PUBLIC .)

+ 14 - 119
render/entity/archer_renderer.cpp

@@ -12,6 +12,9 @@
 #include "../gl/primitives.h"
 #include "../gl/resources.h"
 #include "../gl/texture.h"
+#include "../humanoid_math.h"
+#include "../humanoid_specs.h"
+#include "../palette.h"
 #include "registry.h"
 
 #include <QMatrix4x4>
@@ -33,46 +36,6 @@ using Render::Geom::coneFromTo;
 using Render::Geom::cylinderBetween;
 using Render::Geom::sphereAt;
 
-struct HumanProportions {
-
-  static constexpr float TOTAL_HEIGHT = 1.80f;
-  static constexpr float HEAD_HEIGHT = 0.23f;
-
-  static constexpr float GROUND_Y = 0.0f;
-  static constexpr float HEAD_TOP_Y = GROUND_Y + TOTAL_HEIGHT;
-  static constexpr float CHIN_Y = HEAD_TOP_Y - HEAD_HEIGHT;
-  static constexpr float NECK_BASE_Y = CHIN_Y - 0.08f;
-  static constexpr float SHOULDER_Y = NECK_BASE_Y - 0.12f;
-  static constexpr float CHEST_Y = SHOULDER_Y - 0.42f;
-  static constexpr float WAIST_Y = CHEST_Y - 0.30f;
-
-  static constexpr float UPPER_LEG_LEN = 0.35f;
-  static constexpr float LOWER_LEG_LEN = 0.35f;
-  static constexpr float KNEE_Y = WAIST_Y - UPPER_LEG_LEN;
-
-  static constexpr float SHOULDER_WIDTH = HEAD_HEIGHT * 1.85f;
-  static constexpr float HEAD_RADIUS = HEAD_HEIGHT * 0.42f;
-  static constexpr float NECK_RADIUS = HEAD_RADIUS * 0.38f;
-  static constexpr float TORSO_TOP_R = HEAD_RADIUS * 1.15f;
-  static constexpr float TORSO_BOT_R = HEAD_RADIUS * 1.05f;
-  static constexpr float UPPER_ARM_R = HEAD_RADIUS * 0.38f;
-  static constexpr float FORE_ARM_R = HEAD_RADIUS * 0.30f;
-  static constexpr float HAND_RADIUS = HEAD_RADIUS * 0.28f;
-  static constexpr float UPPER_LEG_R = HEAD_RADIUS * 0.50f;
-  static constexpr float LOWER_LEG_R = HEAD_RADIUS * 0.42f;
-
-  static constexpr float UPPER_ARM_LEN = 0.28f;
-  static constexpr float FORE_ARM_LEN = 0.30f;
-};
-
-enum class MaterialType : uint8_t {
-  Cloth = 0,
-  Leather = 1,
-  Metal = 2,
-  Wood = 3,
-  Skin = 4
-};
-
 struct ArcherColors {
   QVector3D tunic, skin, leather, leatherDark, wood, metal, metalHead,
       stringCol, fletch;
@@ -109,13 +72,6 @@ static inline ArcherPose makePose(uint32_t seed, float animTime, bool isMoving,
 
   using HP = HumanProportions;
 
-  auto hash01 = [](uint32_t x) {
-    x ^= x << 13;
-    x ^= x >> 17;
-    x ^= x << 5;
-    return (x & 0x00FFFFFF) / float(0x01000000);
-  };
-
   float footAngleJitter = (hash01(seed ^ 0x5678u) - 0.5f) * 0.12f;
   float footDepthJitter = (hash01(seed ^ 0x9ABCu) - 0.5f) * 0.08f;
   float armHeightJitter = (hash01(seed ^ 0xABCDu) - 0.5f) * 0.03f;
@@ -252,27 +208,6 @@ static inline ArcherPose makePose(uint32_t seed, float animTime, bool isMoving,
   QVector3D outwardL = -rightAxis;
   QVector3D outwardR = rightAxis;
 
-  auto elbowBendTorso = [&](const QVector3D &shoulder, const QVector3D &hand,
-                            const QVector3D &outwardDir, float alongFrac,
-                            float lateralOffset, float yBias,
-                            float outwardSign) {
-    QVector3D dir = hand - shoulder;
-    float dist = std::max(dir.length(), 1e-5f);
-    dir /= dist;
-
-    QVector3D lateral =
-        outwardDir - dir * QVector3D::dotProduct(outwardDir, dir);
-    if (lateral.lengthSquared() < 1e-8f) {
-      lateral = QVector3D::crossProduct(dir, QVector3D(0, 1, 0));
-    }
-    if (QVector3D::dotProduct(lateral, outwardDir) < 0.0f)
-      lateral = -lateral;
-    lateral.normalize();
-
-    return shoulder + dir * (dist * alongFrac) +
-           lateral * (lateralOffset * outwardSign) + QVector3D(0, yBias, 0);
-  };
-
   P.elbowL = elbowBendTorso(P.shoulderL, P.handL, outwardL, 0.45f, 0.15f,
                             -0.08f, +1.0f);
   P.elbowR = elbowBendTorso(P.shoulderR, P.handR, outwardR, 0.48f, 0.12f, 0.02f,
@@ -285,42 +220,23 @@ static inline ArcherColors makeColors(const QVector3D &teamTint,
                                       uint32_t seed) {
   ArcherColors C;
 
-  auto hash01 = [](uint32_t x) {
-    x ^= x << 13;
-    x ^= x >> 17;
-    x ^= x << 5;
-    return (x & 0x00FFFFFF) / float(0x01000000);
-  };
+  HumanoidPalette base = makeHumanoidPalette(teamTint, seed);
+  C.tunic = base.cloth;
+  C.skin = base.skin;
+  C.leather = base.leather;
+  C.leatherDark = base.leatherDark;
+  C.wood = base.wood;
+  C.metal = base.metal;
+
+  C.metalHead = clampVec01(C.metal * 1.15f);
+  C.stringCol = QVector3D(0.30f, 0.30f, 0.32f);
 
   auto tint = [&](float k) {
     return QVector3D(clamp01(teamTint.x() * k), clamp01(teamTint.y() * k),
                      clamp01(teamTint.z() * k));
   };
-
-  float variation = (hash01(seed) - 0.5f) * 0.08f;
-
-  C.tunic = clampVec01(teamTint * (1.0f + variation));
-  C.skin = QVector3D(0.96f, 0.80f, 0.69f);
-
-  float leatherVar = (hash01(seed ^ 0x1234u) - 0.5f) * 0.06f;
-  float r = teamTint.x();
-  float g = teamTint.y();
-  float b = teamTint.z();
-  float saturation = 0.6f;
-  float brightness = 0.5f;
-  QVector3D desaturated(r * saturation + (1.0f - saturation) * brightness,
-                        g * saturation + (1.0f - saturation) * brightness,
-                        b * saturation + (1.0f - saturation) * brightness);
-  C.leather = clampVec01(desaturated * (0.7f + leatherVar));
-  C.leatherDark = C.leather * 0.85f;
-
-  C.wood = QVector3D(0.16f, 0.10f, 0.05f);
-
-  QVector3D neutralGray(0.70f, 0.70f, 0.70f);
-  C.metal = clampVec01(teamTint * 0.25f + neutralGray * 0.75f);
-  C.metalHead = clampVec01(C.metal * 1.15f);
-  C.stringCol = QVector3D(0.30f, 0.30f, 0.32f);
   C.fletch = tint(0.9f);
+
   return C;
 }
 
@@ -344,13 +260,6 @@ static inline void drawTunicSkirt(const DrawContext &p, ISubmitter &out,
                                   uint32_t seed) {
   using HP = HumanProportions;
 
-  auto hash01 = [](uint32_t x) {
-    x ^= x << 13;
-    x ^= x >> 17;
-    x ^= x << 5;
-    return (x & 0x00FFFFFF) / float(0x01000000);
-  };
-
   const float waistY = HP::WAIST_Y;
   const float skirtLength = 0.25f;
   const float hemY = waistY - skirtLength;
@@ -673,13 +582,6 @@ static inline void drawQuiver(const DrawContext &p, ISubmitter &out,
                               uint32_t seed) {
   using HP = HumanProportions;
 
-  auto hash01 = [](uint32_t x) {
-    x ^= x << 13;
-    x ^= x >> 17;
-    x ^= x << 5;
-    return (x & 0x00FFFFFF) / float(0x01000000);
-  };
-
   QVector3D qTop(-0.08f, HP::SHOULDER_Y + 0.10f, -0.25f);
   QVector3D qBase(-0.10f, HP::CHEST_Y, -0.22f);
 
@@ -900,13 +802,6 @@ void registerArcherRenderer(Render::GL::EntityRendererRegistry &registry) {
 
       uint32_t instSeed = seed ^ uint32_t(idx * 9176u);
 
-      auto hash01 = [](uint32_t x) {
-        x ^= x << 13;
-        x ^= x >> 17;
-        x ^= x << 5;
-        return (x & 0x00FFFFFF) / float(0x01000000);
-      };
-
       float posJitterX = (hash01(instSeed) - 0.5f) * 0.05f;
       float posJitterZ = (hash01(instSeed ^ 0x12345u) - 0.5f) * 0.05f;
       float verticalJitter = (hash01(instSeed ^ 0x9E37u) - 0.5f) * 0.03f;

+ 24 - 0
render/humanoid_math.cpp

@@ -0,0 +1,24 @@
+#include "humanoid_math.h"
+
+namespace Render::GL {
+
+QVector3D elbowBendTorso(const QVector3D &shoulder, const QVector3D &hand,
+                         const QVector3D &outwardDir, float alongFrac,
+                         float lateralOffset, float yBias, float outwardSign) {
+  QVector3D dir = hand - shoulder;
+  float dist = std::max(dir.length(), 1e-5f);
+  dir /= dist;
+
+  QVector3D lateral = outwardDir - dir * QVector3D::dotProduct(outwardDir, dir);
+  if (lateral.lengthSquared() < 1e-8f) {
+    lateral = QVector3D::crossProduct(dir, QVector3D(0, 1, 0));
+  }
+  if (QVector3D::dotProduct(lateral, outwardDir) < 0.0f)
+    lateral = -lateral;
+  lateral.normalize();
+
+  return shoulder + dir * (dist * alongFrac) +
+         lateral * (lateralOffset * outwardSign) + QVector3D(0, yBias, 0);
+}
+
+}

+ 31 - 0
render/humanoid_math.h

@@ -0,0 +1,31 @@
+#pragma once
+
+#include <QVector3D>
+#include <cmath>
+#include <cstdint>
+
+namespace Render::GL {
+
+inline float hash01(uint32_t x) {
+  x ^= x << 13;
+  x ^= x >> 17;
+  x ^= x << 5;
+  return (x & 0x00FFFFFF) / float(0x01000000);
+}
+
+inline QVector3D rotY(const QVector3D &v, float angleRad) {
+  const float c = std::cos(angleRad);
+  const float s = std::sin(angleRad);
+  return QVector3D(c * v.x() + s * v.z(), v.y(), -s * v.x() + c * v.z());
+}
+
+inline QVector3D rightOf(const QVector3D &fwd) {
+  const QVector3D UP(0.0f, 1.0f, 0.0f);
+  return QVector3D::crossProduct(UP, fwd).normalized();
+}
+
+QVector3D elbowBendTorso(const QVector3D &shoulder, const QVector3D &hand,
+                         const QVector3D &outwardDir, float alongFrac,
+                         float lateralOffset, float yBias, float outwardSign);
+
+}

+ 47 - 0
render/humanoid_specs.h

@@ -0,0 +1,47 @@
+#pragma once
+
+#include <cstdint>
+
+namespace Render::GL {
+
+struct HumanProportions {
+
+  static constexpr float TOTAL_HEIGHT = 1.80f;
+  static constexpr float HEAD_HEIGHT = 0.23f;
+
+  static constexpr float GROUND_Y = 0.0f;
+  static constexpr float HEAD_TOP_Y = GROUND_Y + TOTAL_HEIGHT;
+  static constexpr float CHIN_Y = HEAD_TOP_Y - HEAD_HEIGHT;
+  static constexpr float NECK_BASE_Y = CHIN_Y - 0.08f;
+  static constexpr float SHOULDER_Y = NECK_BASE_Y - 0.12f;
+  static constexpr float CHEST_Y = SHOULDER_Y - 0.42f;
+  static constexpr float WAIST_Y = CHEST_Y - 0.30f;
+
+  static constexpr float UPPER_LEG_LEN = 0.35f;
+  static constexpr float LOWER_LEG_LEN = 0.35f;
+  static constexpr float KNEE_Y = WAIST_Y - UPPER_LEG_LEN;
+
+  static constexpr float SHOULDER_WIDTH = HEAD_HEIGHT * 1.85f;
+  static constexpr float HEAD_RADIUS = HEAD_HEIGHT * 0.42f;
+  static constexpr float NECK_RADIUS = HEAD_RADIUS * 0.38f;
+  static constexpr float TORSO_TOP_R = HEAD_RADIUS * 1.15f;
+  static constexpr float TORSO_BOT_R = HEAD_RADIUS * 1.05f;
+  static constexpr float UPPER_ARM_R = HEAD_RADIUS * 0.38f;
+  static constexpr float FORE_ARM_R = HEAD_RADIUS * 0.30f;
+  static constexpr float HAND_RADIUS = HEAD_RADIUS * 0.28f;
+  static constexpr float UPPER_LEG_R = HEAD_RADIUS * 0.50f;
+  static constexpr float LOWER_LEG_R = HEAD_RADIUS * 0.42f;
+
+  static constexpr float UPPER_ARM_LEN = 0.28f;
+  static constexpr float FORE_ARM_LEN = 0.30f;
+};
+
+enum class MaterialType : uint8_t {
+  Cloth = 0,
+  Leather = 1,
+  Metal = 2,
+  Wood = 3,
+  Skin = 4
+};
+
+}

+ 38 - 0
render/palette.cpp

@@ -0,0 +1,38 @@
+#include "palette.h"
+#include "geom/math_utils.h"
+#include "humanoid_math.h"
+
+namespace Render::GL {
+
+using Render::Geom::clamp01;
+using Render::Geom::clampVec01;
+
+HumanoidPalette makeHumanoidPalette(const QVector3D &teamTint, uint32_t seed) {
+  HumanoidPalette p;
+
+  float variation = (hash01(seed) - 0.5f) * 0.08f;
+  p.cloth = clampVec01(teamTint * (1.0f + variation));
+
+  p.skin = QVector3D(0.96f, 0.80f, 0.69f);
+
+  float leatherVar = (hash01(seed ^ 0x1234u) - 0.5f) * 0.06f;
+  float r = teamTint.x();
+  float g = teamTint.y();
+  float b = teamTint.z();
+  float saturation = 0.6f;
+  float brightness = 0.5f;
+  QVector3D desaturated(r * saturation + (1.0f - saturation) * brightness,
+                        g * saturation + (1.0f - saturation) * brightness,
+                        b * saturation + (1.0f - saturation) * brightness);
+  p.leather = clampVec01(desaturated * (0.7f + leatherVar));
+  p.leatherDark = p.leather * 0.85f;
+
+  p.wood = QVector3D(0.16f, 0.10f, 0.05f);
+
+  QVector3D neutralGray(0.70f, 0.70f, 0.70f);
+  p.metal = clampVec01(teamTint * 0.25f + neutralGray * 0.75f);
+
+  return p;
+}
+
+}

+ 19 - 0
render/palette.h

@@ -0,0 +1,19 @@
+#pragma once
+
+#include <QVector3D>
+#include <cstdint>
+
+namespace Render::GL {
+
+struct HumanoidPalette {
+  QVector3D cloth;
+  QVector3D skin;
+  QVector3D leather;
+  QVector3D leatherDark;
+  QVector3D wood;
+  QVector3D metal;
+};
+
+HumanoidPalette makeHumanoidPalette(const QVector3D &teamTint, uint32_t seed);
+
+}