performance - 对球体应用矩阵变换

标签 performance math graphics 3d linear-algebra

我有一个看起来像这样的球体结构

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/

相关文章:

android - 深度测试无法与模板测试一起正常工作

java - 测试井字游戏的获胜条件

c# - 谁能帮我解释一下这些方法的时间安排?

arrays - 如何在 ruby​​ 数组中仅添加正数?

java - 如何获得嵌入式图形组件的独特图形上下文?

r - lattice auto.key - 如何调整线和点?

c++ - 无竞争线程锁的实际成本

java - 什么是 "Stack Walking"

java - 计算 2d 线性 vector 上的下一个点

javascript - javascript 中 Math.cos 函数将度数转换为弧度时出现问题