29 return glm::rotate(glm::mat4(1.0f), glm::pi<float>(), glm::vec3(1.0f, 0.0f, 0.0f));
51 if (!arrowMesh || !basicShader)
return;
53 const auto& objects = sceneManager->
getObjects();
55 m_arrowScratch.clear();
56 const std::size_t n = objects.size();
57 if (m_arrowScratch.capacity() < n) {
58 m_arrowScratch.reserve(n);
63 bool haveSpan =
false;
65 for (
const auto& objPtr : objects) {
71 const float netMag = glm::length(net);
72 if (netMag < kForceEpsilon)
continue;
75 minMag = maxMag = netMag;
78 minMag = std::min(minMag, netMag);
79 maxMag = std::max(maxMag, netMag);
82 const float radius = glm::compMax(glm::abs(obj->
getScale())) * 0.5f;
83 const glm::vec3 dir = glm::normalize(net);
84 const glm::vec3 surfaceStart = body->getPosition(
BodyLock::LOCK) + dir * radius;
85 m_arrowScratch.push_back({obj->
getObjectID(), net, netMag, surfaceStart, std::max(radius, kArrowRadiusMin)});
88 if (m_arrowScratch.empty())
return;
92 const float magSpan = maxMag - minMag;
95 m_instanceScratch.clear();
96 if (m_instanceScratch.capacity() < m_arrowScratch.size()) {
97 m_instanceScratch.reserve(m_arrowScratch.size());
100 for (
const ArrowCpu& e : m_arrowScratch) {
101 glm::mat4 model(1.0f);
102 model = glm::translate(model, e.startPos - renderOrigin);
103 model = model * rotateFromYToDir(e.net);
105 float t = kDefaultArrowStrengthT;
106 if (magSpan > kMagSpanEpsilon) {
107 t = (e.netMag - minMag) / magSpan;
109 const float lengthFactor = kArrowStemMin + t * (kArrowStemMax - kArrowStemMin);
111 model = glm::scale(model, glm::vec3(e.radius * kArrowThicknessScale, e.radius * lengthFactor, e.radius * kArrowThicknessScale));
112 m_instanceScratch.emplace_back(model, e.objectID, kArrowColor);
115 arrowMesh->drawInstanced(m_instanceScratch);
glm::vec3 getNetForce(BodyLock lock) const