问题描述
在我的3D应用程序中,我有一个Object3D类,该类在创建时就是边界框,该边界框是一个简单的长方体,具有最小和最大点:
但是,当我翻译Object3D时,我想使用对象的模型矩阵来更新边界框:
BoundingBox& TransformBy(const glm::mat4& modelMatrice){
//extract position of my model matrix
glm::vec3 pos( modelMatrice[3] );
//extract scale of my model matrix
glm::vec3 scale( glm::length(glm::vec3(modelMatrice[0])),glm::length(glm::vec3(modelMatrice[1])),glm::length(glm::vec3(modelMatrice[2])));
//Creating vec4 min/max from vec3
glm::vec4 min_(min.x,min.y,min.z,1.0f);
glm::vec4 max_(max.x,max.y,max.z,1.0f);
//Inverting the matrice to multiply my vec4 with it in order to rotate my min max
glm::mat4 inverse = glm::inverse(modelMatrice);
min_ = min_ * inverse;
max_ = max_ * inverse;
//Scale my min_ max_
min_ *= glm::vec4(scale,1.0f);
max_ *= glm::vec4(scale,1.0f);
//adding model matrice translation to min_ and max_
min_ += glm::vec4(pos,0.0f);
max_ += glm::vec4(pos,0.0f);
//Redefining max and min
max = glm::vec3( (min_.x > max_.x)? min_.x:max_.x,(min_.y > max_.y)? min_.y: max_.y,(min_.z > max_.z)? min_.z : max_.z);
min = glm::vec3( (min_.x < max_.x)? min_.x:max_.x,(min_.y < max_.y)? min_.y: max_.y,(min_.z < max_.z)? min_.z : max_.z);
return *this;
}
这是我调用TransformBy函数的方式:
box.TransformBy(transform.GetModelMatrix());
由于某种原因,它会使我的最小点和最大点正确旋转,也会平移它,但是我的缩放比例未正确应用,这使我的边界框的缩放比例大于3D对象。
为什么我的缩放无法正常工作? 也许有一种不太复杂的方式来做我想做的事?
解决方法
如果我正确理解了GetModelMatrix()
的结果,即它只是一个普通的4x4转换矩阵,那么我想我可以猜到问题出在哪里。我发现用示例进行可视化/解释最容易,所以希望没事。
假设您的GetModelMatrix()
的结果如下,是一个简单的变换矩阵,没有旋转分量,只有[5 6 7]的平移。
| 1 0 0 5 |
| 0 1 0 6 |
| 0 0 1 7 |
| 0 0 0 1 |
以modelMatrice
的形式传递的倒数就是:
| 1 0 0 -5 |
| 0 1 0 -6 |
| 0 0 1 -7 |
| 0 0 0 1 |
调用glm::vec4 min_(min.x,min.y,min.z,1.0f);
后,让我们用向量min_
表示[x y z 1]
。然后min_ * modelMatrice
如下:
| 1 0 0 -5 |
| 0 1 0 -6 |
[x y z 1] * | 0 0 1 -7 | = [x y z (-5x-6y-7z+1)]
| 0 0 0 1 |
也就是说,x,y和z分量不会更改,因为在乘法中是应用于它们的|0 0 0 1|
行,而不是包含转换分量的列。
我想问一下,您是否有特定的原因(a)将GetModelMatrix()
求逆,并且(b)将矩阵乘以矢量而不是相反?我猜想也许您的代码应该如下所示:
BoundingBox& TransformBy(const glm::mat4 modelMatrice){
...
min_ = modelMatrice * min_;
max_ = modelMatrice * max_;
...
return *this;
}
以box.TransformBy(transform.GetModelMatrix());
呼叫
更新:
关于您的新代码,我质疑是否需要反转转换矩阵以进行旋转,是否需要将缩放/平移/旋转分解为三个单独的步骤,依此类推。在其他地方,该过程应该像获取对象的转换向量一样简单,将min_和max_乘以它,然后测试是否在函数末尾交换了当前已交换的最小/最大分量:
BoundingBox& TransformBy(const glm::mat4& modelMatrice){
min_ = modelMatrice * min_;
max_ = modelMatrice * max_;
max = glm::vec3( (min_.x > max_.x)? min_.x:max_.x,(min_.y > max_.y)? min_.y: max_.y,(min_.z > max_.z)? min_.z : max_.z);
min = glm::vec3( (min_.x < max_.x)? min_.x:max_.x,(min_.y < max_.y)? min_.y: max_.y,(min_.z < max_.z)? min_.z : max_.z);
return *this;
}
如果上述五行功能不起作用,请告诉我它是如何失败的;如果它不起作用,我认为问题可能出在代码的其他地方。
但是,要回答有关缩放为什么不起作用的最新问题:反转转换矩阵时,您也在反转缩放。因此,当您乘以inverse
时,您不仅旋转,而且还应用了反向比例。尽管您可以通过再次乘以比例来解决此问题,但似乎更简单的解决方案似乎正在尝试使上述五行解决方案正常工作。