我有一个看起来像这样的球体结构
struct Sphere {
vec3 _center;
float _radius;
};
如何将 4x4 变换矩阵应用于该球体?该矩阵可能包含比例因子、旋转(这显然不会影响球体)和平移。
我当前使用的方法包含三个 length()
方法(其中包含 sqrt()
),速度非常慢。
glm::vec3 extractTranslation(const glm::mat4 &m)
{
glm::vec3 translation;
// Extract the translation
translation.x = m[3][0];
translation.y = m[3][1];
translation.z = m[3][2];
return translation;
}
glm::vec3 extractScale(const glm::mat4 &m) //should work only if matrix is calculated as M = T * R * S
{
glm::vec3 scale;
scale.x = glm::length( glm::vec3(m[0][0], m[0][1], m[0][2]) );
scale.y = glm::length( glm::vec3(m[1][0], m[1][1], m[1][2]) );
scale.z = glm::length( glm::vec3(m[2][0], m[2][1], m[2][2]) );
return scale;
}
float extractLargestScale(const glm::mat4 &m)
{
glm::vec3 scale = extractScale(m);
return glm::max(scale.x, glm::max(scale.y, scale.z));
}
void Sphere::applyTransformation(const glm::mat4 &transformation)
{
glm::vec4 center = transformation * glm::vec4(_center, 1.0f);
float largestScale = extractLargestScale(transformation);
set(glm::vec3(center)/* / center.w */, _radius * largestScale);
}
我想知道是否有人知道更有效的方法来做到这一点?
最佳答案
这是一个关于效率的问题,特别是为了避免求平方根。一个想法是将求平方根推迟到最后一刻。由于长度和长度平方是从 0 开始的递增函数,因此比较长度平方与比较长度相同。因此,您可以避免对 length
的三次调用,并将其设为一次。
#include <glm/gtx/norm.hpp>
#include <algorithm>
glm::vec3 extractScale(const glm::mat4 &m)
{
// length2 returns length squared i.e. v·v
// no square root involved
return glm::vec3(glm::length2( glm::vec3(m[0]) ),
glm::length2( glm::vec3(m[1]) ),
glm::length2( glm::vec3(m[2]) ));
}
void Sphere::applyTransformation(const glm::mat4 &transformation)
{
glm::vec4 center = transformation * glm::vec4(_center, 1.0f);
glm::vec3 scalesSq = extractScale(transformation);
float const maxScaleSq = std::max_element(&scalesSq[0], &scalesSq[0] + scalesSq.length()); // length gives the dimension here i.e. 3
// one sqrt when you know the largest of the three
float const largestScale = std::sqrt(maxScaleSq);
set(glm::vec3(center), _radius * largestScale);
}
旁白: 不均匀缩放意味着沿不同轴的缩放比例不相同。例如。 S1, 2, 4 是非均匀的,而 S2, 2, 2 是均匀的。请参阅this intuitive primer on transformations更好地理解他们;它有动画来展示这种差异。
比例也可以不均匀吗?从代码看来是可以的。用最大比例变换半径是不正确的。如果比例不均匀,球体实际上会变成椭球体,因此仅缩放半径是不正确的。您必须将球体转换为 ellipsoid具有不同长度的半主轴。
关于performance - 对球体应用矩阵变换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34220370/