2015-12-11 4 views
0

У меня есть структура Sphere, которая выглядит, как этотПрименить преобразование матрицы в сфере

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

«Интересно, знает ли кто-нибудь более эффективный способ сделать это?» http://codereview.stackexchange.com/ поможет – bholagabbar

+0

Что вы подразумеваете под «неравномерным»? Почему преобразование радиуса с наибольшим масштабом не является правильным? – Pilpel

+0

См. Ответ, который я дал. – legends2k

ответ

1

Это вопрос об эффективности и, в частности, избегать использования квадратного корня. Одной из идей было бы отложить выполнение квадратного корня до последнего момента. Поскольку квадраты длины и длины увеличивают функции начиная с 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); 
} 

Кроме: Неравномерная шкала означает, что коэффициенты масштабирования вдоль различных осей не являются одинаковыми. Например. S 1, 2, 4 неравномерен, а S 2, 2, 2 является однородным. См. this intuitive primer on transformations, чтобы лучше понять их; у него есть анимации, чтобы продемонстрировать такие различия.

Может ли шкала быть неравномерной? Из кода он выглядит так, как мог. Неправильное преобразование радиуса с наибольшим масштабом. Если бы вы имели неравномерный масштаб, сфера фактически стала эллипсоидом, и поэтому просто масштабирование радиуса было бы неверным. Вам нужно будет превратить сферу в ellipsoid с полуосновными осями различной длины.

+0

Шкала действительно может быть неоднородной. Дело в том, что я не хочу иметь эллипсоид, но вместо этого имею немного неточную сферу. Спасибо за решение, кстати! – Pilpel

Смежные вопросы