Based on the answer from @DMGregory here is my implementation:
glm::vec3 GetAnyPerpendicularUnitVector(const glm::vec3& vec)
{
if (vec.y != 0.0f || vec.z != 0.0f)
return glm::vec3(1, 0, 0);
else
return glm::vec3(0, 1, 0);
}
void DebugManager::drawCapsule(const Capsule& c, const glm::vec4& color)
{
const glm::vec3 axis = c.end - c.start;
const float length = glm::length(axis);
const glm::vec3 localZ = axis / length;
const glm::vec3 localX = GetAnyPerpendicularUnitVector(localZ);
const glm::vec3 localY = glm::cross(localZ, localX);
using glm::cos;
using glm::sin;
constexpr float pi = glm::pi<float>();
const glm::vec3 start(0.0f);
const glm::vec3 end(1.0f);
const float resolution = 16.0f;
const glm::vec3 step = (end - start) / resolution;
auto cylinder = [localX, localY, localZ, c, length](const float u,
const float v) {
return c.start //
+ localX * cos(2.0f * pi * u) * c.radius //
+ localY * sin(2.0f * pi * u) * c.radius //
+ localZ * v * length; //
};
auto sphereStart = [localX, localY, localZ, c](const float u,
const float v) -> glm::vec3 {
const float latitude = (pi / 2.0f) * (v - 1);
return c.start //
+ localX * cos(2.0f * pi * u) * cos(latitude) * c.radius //
+ localY * sin(2.0f * pi * u) * cos(latitude) * c.radius //
+ localZ * sin(latitude) * c.radius;
};
auto sphereEnd = [localX, localY, localZ, c](const float u, const float v) {
const float latitude = (pi / 2.0f) * v;
return c.end //
+ localX * cos(2.0f * pi * u) * cos(latitude) * c.radius //
+ localY * sin(2.0f * pi * u) * cos(latitude) * c.radius //
+ localZ * sin(latitude) * c.radius;
};
for (float i = 0; i < resolution; ++i) {
for (float j = 0; j < resolution; ++j) {
const float u = i * step.x + start.x;
const float v = j * step.y + start.y;
const float un =
(i + 1 == resolution) ? end.x : (i + 1) * step.x + start.x;
const float vn =
(j + 1 == resolution) ? end.y : (j + 1) * step.y + start.y;
// Draw Cylinder
{
const glm::vec3 p0 = cylinder(u, v);
const glm::vec3 p1 = cylinder(u, vn);
const glm::vec3 p2 = cylinder(un, v);
const glm::vec3 p3 = cylinder(un, vn);
drawTriangle(p0, p1, p2, color);
drawTriangle(p3, p1, p2, color);
}
// Draw Sphere start
{
const glm::vec3 p0 = sphereStart(u, v);
const glm::vec3 p1 = sphereStart(u, vn);
const glm::vec3 p2 = sphereStart(un, v);
const glm::vec3 p3 = sphereStart(un, vn);
drawTriangle(p0, p1, p2, color);
drawTriangle(p3, p1, p2, color);
}
// Draw Sphere end
{
const glm::vec3 p0 = sphereEnd(u, v);
const glm::vec3 p1 = sphereEnd(u, vn);
const glm::vec3 p2 = sphereEnd(un, v);
const glm::vec3 p3 = sphereEnd(un, vn);
drawTriangle(p0, p1, p2, color);
drawTriangle(p3, p1, p2, color);
}
}
}
}