💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

362 lines
10 KiB

  1. /*
  2. * Copyright (C) 2017 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper Source Code.
  5. *
  6. * Antkeeper Source Code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper Source Code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper Source Code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "ant.hpp"
  20. #include "colony.hpp"
  21. #include "pheromone-matrix.hpp"
  22. #include <cmath>
  23. float FRAMES_PER_SECOND = 60;
  24. float TIMESTEP = 1.0f / FRAMES_PER_SECOND;
  25. float ANT_LENGTH = 0.5f; // 0.5 cm, head to abdomen (not including legs / antennae)
  26. float ANT_COLLISION_RADIUS = ANT_LENGTH * 1.25f;
  27. float RECEPTOR_RADIUS = 0.4f;
  28. float RECEPTOR_SEPARATION = 0.882f;
  29. float RECEPTOR_DISTANCE = 0.588f;
  30. float MOUTH_DISTANCE = 0.2646f;
  31. float BITE_RADIUS = 0.0294f;
  32. float FOOD_PARTICLE_RADIUS = 0.1176f;
  33. float MAX_RECEPTOR_NOISE = 0.05f; // essentially an epsilon
  34. float MAX_EXCITEMENT = 1.0f;
  35. float MAX_PHEROMONE_TURNING_ANGLE = glm::radians(8.5f);
  36. float MIN_WALK_TIME = 0.5f; // seconds
  37. float MAX_WALK_TIME = 8.0f; // seconds
  38. float MIN_REST_TIME = 0.15f;
  39. float MAX_REST_TIME = 0.7f;
  40. float MIN_CHEW_TIME = 0.25f;
  41. float MAX_CHEW_TIME = 0.5f;
  42. float DEEXCITEMENT_FACTOR = 0.999f; // This should probably always be less than the evaporation factor
  43. float CALM_FACTOR = 0.995f;
  44. float MAX_WALK_FORCE = 1.5;
  45. float MAX_PANIC_FORCE = 0.1029f;
  46. float MAX_WALK_SPEED = 3.0f; // cm/s
  47. float MAX_PANIC_SPEED = 8.82f; // cm/s
  48. float PANIC_RADIUS = 7.35f;
  49. float WANDER_CIRCLE_DISTANCE = 0.441f;
  50. float WANDER_CIRCLE_RADIUS = 0.0294f;
  51. float MAX_WANDER_ANGLE = 0.15f;
  52. inline float fwrap(float angle, float limit)
  53. {
  54. return angle - std::floor(angle / limit) * limit;
  55. }
  56. Ant::Ant(Colony* colony):
  57. colony(colony),
  58. state(Ant::State::IDLE),
  59. transform(Transform::getIdentity()),
  60. pose(nullptr)
  61. {
  62. pose = new Pose(colony->getAntModel()->getSkeleton());
  63. pose->reset();
  64. pose->concatenate();
  65. modelInstance.setModel(colony->getAntModel());
  66. modelInstance.setPose(pose);
  67. animationTime = frand(0.0f, 60.0f);
  68. velocity = Vector3(0);
  69. acceleration = Vector3(0);
  70. wanderDirection = getForward();
  71. excitement = MAX_EXCITEMENT;
  72. }
  73. Ant::~Ant()
  74. {
  75. delete pose;
  76. }
  77. void Ant::animate()
  78. {
  79. colony->getTripodGaitAnimation()->animate(pose, animationTime);
  80. pose->concatenate();
  81. animationTime = fwrap(animationTime + 4.0f, colony->getTripodGaitAnimation()->getEndTime());
  82. }
  83. void Ant::suspend(const Vector3& suspensionPoint, const Quaternion& suspensionRotation)
  84. {
  85. transform.translation = suspensionPoint;
  86. transform.rotation = suspensionRotation;
  87. modelInstance.setTransform(transform);
  88. }
  89. void Ant::move(const Vector3& velocity)
  90. {
  91. std::vector<Navmesh::Step> traversal;
  92. Navmesh::traverse(getNavmeshTriangle(), getBarycentricPosition(), velocity, &traversal);
  93. if (!traversal.empty())
  94. {
  95. const Navmesh::Step& step = traversal.back();
  96. if (step.start != step.end)
  97. {
  98. if (step.triangle != getNavmeshTriangle())
  99. {
  100. Quaternion alignment = glm::rotation(getNavmeshTriangle()->normal, step.triangle->normal);
  101. Vector3 newForward = glm::normalize(project_on_plane(alignment * getForward(), Vector3(0.0f), step.triangle->normal));
  102. setOrientation(newForward, step.triangle->normal);
  103. }
  104. }
  105. setPosition(step.triangle, step.end);
  106. }
  107. }
  108. void Ant::turn(float angle)
  109. {
  110. // Rotate forward vector
  111. Vector3 newForward = glm::normalize(glm::angleAxis(angle, getUp()) * getForward());
  112. setOrientation(newForward, getUp());
  113. }
  114. void Ant::update(float dt)
  115. {
  116. float probeLateralOffset = 0.1f;
  117. float probeForwardOffset = 0.3f;
  118. animate();
  119. // Calculate positions of receptors
  120. receptorL = getPosition() + getForward() * RECEPTOR_DISTANCE;
  121. receptorR = receptorL;
  122. receptorL -= getRight() * RECEPTOR_SEPARATION * 0.5f;
  123. receptorR += getRight() * RECEPTOR_SEPARATION * 0.5f;
  124. // Steering
  125. if (state == Ant::State::WANDER)
  126. {
  127. //setWanderCircleDistance(4.0f);
  128. //setWanderCircleRadius(0.3f);
  129. //setWanderRate(glm::radians(90.0f));
  130. //setSeparationRadius(0.5f);
  131. //setMaxSpeed(0.025f);
  132. // Calculate wander force
  133. Vector3 wanderForce = wander() * 1.5f;
  134. Vector3 followForce = follow() * 3.0f;
  135. // Setup containment probes
  136. //Vector3 leftProbe = getForward() * probeForwardOffset - getRight() * probeLateralOffset;
  137. //Vector3 rightProbe = getForward() * probeForwardOffset + getRight() * probeLateralOffset;
  138. // Calculate containment force
  139. //Vector3 containmentForce = containment(leftProbe) + containment(rightProbe);
  140. // Determine neighbors
  141. //float neighborhoodSize = 2.0f;
  142. //AABB neighborhoodAABB(getPosition() - Vector3(neighborhoodSize * 0.5f), getPosition() + Vector3(neighborhoodSize * 0.5f));
  143. //std::list<Agent*> neighbors;
  144. //colony->queryAnts(neighborhoodAABB, &neighbors);
  145. // Calculate separation force
  146. //Vector3 separationForce = separation(neighbors);
  147. applyForce(wanderForce);
  148. applyForce(followForce);
  149. float maxSpeed = MAX_WALK_SPEED * TIMESTEP;
  150. // Limit acceleration
  151. float accelerationMagnitudeSquared = glm::dot(acceleration, acceleration);
  152. if (accelerationMagnitudeSquared > MAX_WALK_FORCE * MAX_WALK_FORCE)
  153. {
  154. acceleration = glm::normalize(acceleration) * MAX_WALK_FORCE;
  155. }
  156. // Accelerate
  157. velocity += acceleration;
  158. // Limit speed
  159. float speedSquared = glm::dot(velocity, velocity);
  160. if (speedSquared > maxSpeed * maxSpeed)
  161. {
  162. velocity = glm::normalize(velocity) * maxSpeed;
  163. }
  164. Vector3 direction = glm::normalize(velocity);
  165. setOrientation(direction, getUp());
  166. // Deposit pheromones
  167. Vector2 position2D = Vector2(getPosition().x, getPosition().z);
  168. colony->getHomingMatrix()->deposit(position2D, excitement);
  169. excitement *= DEEXCITEMENT_FACTOR;
  170. // Move ant
  171. move(velocity);
  172. }
  173. else if (state == Ant::State::IDLE)
  174. {
  175. velocity = Vector3(0.0f);
  176. // Move ant
  177. move(velocity);
  178. }
  179. // Update transform
  180. if (state == Ant::State::WANDER || state == Ant::State::IDLE)
  181. {
  182. transform.translation = getPosition();
  183. transform.rotation = getRotation();
  184. // Update model instance
  185. modelInstance.setTransform(transform);
  186. }
  187. // Locomotion
  188. /*
  189. As the ant moves forward, legs in the stance phase are kept grounded via IK. If IK constraints are violated, the swinging legs are grounded
  190. and the grounded legs begin swinging.
  191. Two poses are loaded from the model file: midswing and touchdown.
  192. touchdown is the pose in which all legs are at the end of their swing phases and need to be grounded
  193. midswing is the pose in which all legs are at the highest point in their swing phases
  194. when a grounded leg enters the swing phases, its current pose is saved as the liftoff pose, then an animation is created using the liftoff pose, midswing pose, and touchdown pose.
  195. */
  196. }
  197. /*
  198. Vector3 Ant::forage(const Vector3& leftReceptor, const Vector3& rightReceptor)
  199. {
  200. float leftSignal = 0.0f;
  201. float rightSignal = 0.0f;
  202. // Detect pheromones with left receptor
  203. std::list<Pheromone*> leftPheromones;
  204. colony->getPheromoneOctree()->query(AABB(leftReceptor, leftReceptor), &leftPheromones);
  205. for (Pheromone* pheromone: leftPheromones)
  206. {
  207. Vector3 difference = pheromone->getPosition() - rightReceptor;
  208. float distanceSquared = glm::dot(difference, difference);
  209. if (distanceSquared <= pheromone->getRadiusSquared())
  210. {
  211. // Calculate attenuated pheromone strength using inverse-square law
  212. float strength = pheromone->getStrength() / ((distanceSquared == 0.0f) ? 1.0f : distanceSquared);
  213. leftSignal += strength;
  214. }
  215. }
  216. // Detect pheromones with right receptor
  217. std::list<Pheromone*> rightPheromones;
  218. colony->getPheromoneOctree()->query(AABB(rightReceptor, rightReceptor), &rightPheromones);
  219. for (Pheromone* pheromone: rightPheromones)
  220. {
  221. Vector3 difference = pheromone->getPosition() - rightReceptor;
  222. float distanceSquared = glm::dot(difference, difference);
  223. if (distanceSquared <= pheromone->getRadiusSquared())
  224. {
  225. // Calculate attenuated pheromone strength using inverse-square law
  226. float strength = pheromone->getStrength() / ((distanceSquared == 0.0f) ? 1.0f : distanceSquared);
  227. rightSignal += strength;
  228. }
  229. }
  230. // Add noise
  231. const float maxNoise = 0.1f;
  232. leftSignal += frand(0.0f, maxNoise);
  233. rightSignal += frand(0.0f, maxNoise);
  234. if (leftSignal + rightSignal > 0.0f)
  235. {
  236. const float maxPheromoneTurningAngle = 0.1f;
  237. // Use Weber's law (Perna et al.) to calculate turning angle based on pheromone signals
  238. float turningAngle = maxPheromoneTurningAngle * ((leftSignal - rightSignal) / (leftSignal + rightSignal));
  239. }
  240. return Vector3(0.0f);
  241. }
  242. */
  243. void Ant::setState(Ant::State state)
  244. {
  245. this->state = state;
  246. }
  247. Vector3 Ant::seek(const Vector3& target)
  248. {
  249. Vector3 steer(0.0f);
  250. Vector3 difference = target - getPosition();
  251. float distanceSquared = glm::dot(difference, difference);
  252. if (distanceSquared > 0.0f)
  253. {
  254. float maxForce = MAX_WALK_FORCE;
  255. steer = glm::normalize(difference) * maxForce - velocity;
  256. }
  257. return steer;
  258. }
  259. Vector3 Ant::flee(const Vector3& target)
  260. {
  261. return -seek(target);
  262. }
  263. Vector3 Ant::wander()
  264. {
  265. // Determine center of wander circle
  266. Vector3 center = getPosition() + getForward() * WANDER_CIRCLE_DISTANCE;
  267. // Calculate wander target
  268. Vector3 target = center + wanderDirection * WANDER_CIRCLE_RADIUS;
  269. // Rotate wander direction by a random displacement angle
  270. float displacement = frand(-MAX_WANDER_ANGLE, MAX_WANDER_ANGLE);
  271. wanderDirection = glm::normalize(glm::angleAxis(displacement, getUp()) * wanderDirection);
  272. return seek(target);
  273. }
  274. Vector3 Ant::follow()
  275. {
  276. const PheromoneMatrix* pheromoneMatrix = colony->getRecruitmentMatrix();
  277. Vector2 receptorL2D = Vector2(receptorL.x, receptorL.z);
  278. Vector2 receptorR2D = Vector2(receptorR.x, receptorR.z);
  279. float signalL = pheromoneMatrix->query(receptorL2D, RECEPTOR_RADIUS);
  280. signalL += frand(0.0f, MAX_RECEPTOR_NOISE);
  281. float signalR = pheromoneMatrix->query(receptorR2D, RECEPTOR_RADIUS);
  282. signalR += frand(0.0f, MAX_RECEPTOR_NOISE);
  283. if (signalL + signalR > 0.0f)
  284. {
  285. float angle = -MAX_PHEROMONE_TURNING_ANGLE * ((signalL - signalR) / (signalL + signalR));
  286. Vector3 steer = glm::normalize(glm::angleAxis(angle, getUp()) * getForward());
  287. return steer;
  288. }
  289. return Vector3(0.0f);
  290. }
  291. void Ant::applyForce(const Vector3& force)
  292. {
  293. acceleration += force;
  294. }