OpenGL 构建层次变换系统
OpenGL building hierarchy transform system
我正在尝试构建转换系统,模仿 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;
}
这就是我计算局部变换和世界变换的方式。我已经尝试了很多变换矩阵顺序的组合,但其中 none 可以正常工作。我试图引用 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;
}
一切都很好。在韩国已经是午夜了。我终于可以去睡觉了。
和我遇到同样问题的人,请不要犯傻:(
我正在尝试构建转换系统,模仿 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;
}
这就是我计算局部变换和世界变换的方式。我已经尝试了很多变换矩阵顺序的组合,但其中 none 可以正常工作。我试图引用 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;
}
一切都很好。在韩国已经是午夜了。我终于可以去睡觉了。 和我遇到同样问题的人,请不要犯傻:(