c++ - 将 vec3 乘以模型矩阵的问题(缩放问题)
问题描述
在我的 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 |
传入 as 的反函数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
:您还在应用倒置比例。虽然您可以通过再次乘以比例来解决此问题,但更简单的解决方案似乎是试图让上述五行解决方案发挥作用。
推荐阅读
- ios - SwiftUI - 如何将当前的强调色传递给工作表?
- swift - 选择按钮后,如何自动填充文本字段?
- javascript - 在 for 循环中生成变量
- spring - spring xml dsl中的Apache骆驼setHeader
- java - Java Timer.cancel() 不取消计时器
- javascript - _dirname 没有定义?app.use(express.static(path.join(_dirname, 'public')));
- python - 如何使用opencv python准确检测颜色
- html - 使用多个按钮组时保持按钮焦点
- python - Pandas:根据条件发生的实例数查询 DF
- python - 没有从存储的 sqlite 表中加载数据