将 vec3 乘以模型矩阵的问题(缩放问题)
Posted
技术标签:
【中文标题】将 vec3 乘以模型矩阵的问题(缩放问题)【英文标题】:Problem multiplying vec3 by model matrice (scaling problem) 【发布时间】:2020-08-12 18:39:46 【问题描述】:在我的 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 对象具有更大的比例。
为什么我的缩放不能正常工作? 也许有一种不那么复杂的方式来做我想做的事?
【问题讨论】:
【参考方案1】:如果我正确理解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);
之后,让我们用向量[x y z 1]
来表示min_
。然后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_ 乘以它,然后测试您当前在函数结束时是否交换了任何 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
时,您不仅仅是在旋转:您还在应用倒置比例。虽然您可以通过再次乘以比例来解决此问题,但更简单的解决方案似乎是试图让上述五行解决方案发挥作用。
【讨论】:
您好 FilmCoder,感谢您的回复,我的模型矩阵有点复杂,它有变换、旋转和缩放。 (a)(b) 我正在反转我的模型矩阵,通过将它们与矩阵相乘来将旋转应用于我的最小值和最大值(它确实有效)。我将用更多数据和我找到的东西来编辑我的问题 嗨,Xemuth。我相信,尽管有反转,但旋转起作用的原因是因为旋转矩阵的逆是它的转置,并且通过在乘法中切换向量和矩阵的顺序,您实际上是将向量乘以旋转矩阵的逆矩阵的转置,即逆矩阵的逆,即原始旋转矩阵。不过,翻译不会发生类似的巧合。我想如果您对其进行测试,缩放也可能会“反转”,即当您的模型增长时,您的边界框会缩小。 感谢截图。我会考虑一下可能是什么问题。这是通过采用您的新代码获得的,其中缩放/平移/旋转都被隔离并一一应用,并且根本不反转旋转矩阵?如果是这样,我可以看到为什么你可能会得到你截图的结果。还是更接近我更新原始答案的五行版本?因为那时我认为它应该可以工作。 好吧,它完美地工作,甚至解决了规模问题。感谢您的帮助,这真的很奇怪,事情很简单(我的意思是,当我编写函数时,我不明白我如何不先尝试将向量乘以模型,也许我将向量与矩阵相乘而不是再次将我的矩阵与向量相乘)井槽。 太棒了!很高兴听到它现在有效!很高兴我能帮上忙!以上是关于将 vec3 乘以模型矩阵的问题(缩放问题)的主要内容,如果未能解决你的问题,请参考以下文章