首页 > 解决方案 > 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,但找不到有用的东西。

localPositionlocalScaleglm::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 的变换系统。我怎样才能解决这个问题?

标签: c++openglglm-math

解决方案


这是由于我的愚蠢错误。当我初始化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;
}

一切皆好。在韩国已经是午夜了。我终于可以睡觉了。对于和我面临同样问题的人,请不要愚蠢:(


推荐阅读