c++ - OpenGL构建层次变换系统
问题描述
我正在尝试构建转换系统,模仿 Unity 的。查看我的代码:
void BaseObject::RecalculateTransform()
{
// For top object
if (parent.expired())
{
worldTransform = localTransform = glm::mat4(1);
return;
}
// bunch of shit
localTransform = glm::translate(glm::mat4(1), localPosition) * glm::scale(glm::mat4(1), localScale) * glm::mat4(localRotation);
worldTransform = parent.lock()->GetWorldTransform() * localTransform;
}
这就是我计算局部变换和世界变换的方式。我已经尝试了很多转换矩阵顺序的组合,但没有一个能正常工作。我试图参考 Unity3d,但找不到有用的东西。
localPosition
localScale
是glm::vec3
类型,是localRotation
类型glm::quat
。
由于它可能有帮助,我从上面的代码中选择了一个屏幕截图:
auto top = app->GetHierarchy()->GetTopObject();
auto childDepth1 = top->Instantiate().lock();
childDepth1->SetLocalPosition(glm::vec3(0, 1, 0));
// spiral one
auto mesh1 = childDepth1->AddComponent<RandomMesh>().lock();
mesh1->SetVerticeData("l 30");
auto childDepth2 = childDepth1->Instantiate().lock();
childDepth2->SetLocalPosition(glm::vec3(0, 1, 0));
// spherical one
auto mesh2 = childDepth2->AddComponent<RandomMesh>().lock();
mesh2->SetVerticeData("s 100 t");
截屏:
正如你所看到的,螺旋形的球体就像它的孩子一样。螺旋式的localPosition
是(0, 1, 0)
,所以也是worldPosition
。但它是在-y
现场渲染的。(我已经以其他方式确认该+y
位置在中线上方。)
此外,球体的 localPosition 也是(0, 1, 0)
,这使得它是worldPosition
(0, 2, 0)
。保持该+y
位置在中线下方的方向,它必须在螺旋线下方渲染,但它在球体上方渲染。通过打印调试,它说球体worldPosition
是(0, 0, 0)
,不是(0, 2, 0)
。
经过一些实验,我发现变换矩阵的应用正负取决于子深度的奇偶性。
我想要的只是类似 Unity 的变换系统。我怎样才能解决这个问题?
解决方案
这是由于我的愚蠢错误。当我初始化localRotation
四元数值时,我在做
localRotation = glm::quat(0, 0, 0, 1);
我不知道确切的原因,但是使用调试器,每次旋转矩阵相乘时,它都会否定位置值。
正确的初始化是
localRotation = glm::identity<glm::quat>();
顾名思义,这根本不会应用轮换。
这是我的解决方案:
void BaseObject::RecalculateTransform()
{
isTransformChanged = false;
// For top object
if (parent.expired())
{
worldTransform = localTransform = glm::mat4(1);
return;
}
const auto& scaled = glm::scale(glm::mat4(1), localScale);
const auto& rotated = glm::mat4(localRotation) * scaled;
const auto& translated = glm::translate(glm::mat4(1), localPosition) * rotated;
localTransform = translated;
worldTransform = parent.lock()->GetWorldTransform() * localTransform;
}
一切皆好。在韩国已经是午夜了。我终于可以睡觉了。对于和我面临同样问题的人,请不要愚蠢:(
推荐阅读
- node.js - 为什么 Node.js 扩展在 Linux 上有效,但在 Windows 上无效?
- c - 如何在 C 中测量 DNS 查找时间
- java - Java - WildcardFileFilter:适用于 Mac,不适用于 CentO
- jmeter - JMeter 网页测试 - 您的会话因不活动而过期
- email - 获取已发送邮件的 SOST 数据库 ID
- c++ - 客户端发送消息但服务器直到客户端结束程序才收到消息
- javascript - vue 包装另一个组件,传递道具和事件
- android - 在 FusedLocationProviderClient 中以编程方式设置模拟位置
- javascript - 当我已经有 onclick 事件时,如何添加按键事件?
- c# - iOS 上等效的 ScrollChange 事件