旋转对象以匹配向量
Posted
技术标签:
【中文标题】旋转对象以匹配向量【英文标题】:Rotating an object to match a vector 【发布时间】:2015-04-17 23:36:13 【问题描述】:我认为我做这件事的时间最长,但我相信我做这件事的方式可能非常错误。
我有一个带有世界地形的 3D 引擎,并且可以将对象放置在地面上,当它们被放置时,它们会定向到它们所在的地形(旋转)。我这样做的方式是这样的:
D3DXVECTOR3 tNormal = GetNormalFromFile( ... ); //Get the terrain's normal
placeItemData.placeMesh.meshRot.z = (acos(tNormal.x) - (D3DX_PI/2));
placeItemData.placeMesh.meshRot.x = -(acos(tNormal.z) - (D3DX_PI/2));
我将旋转存储为弧度中的向量:x,y,z 旋转,其中 Y 向上。所以我计算X和Z轴的旋转并相应地旋转。玩家可以在放置对象之前手动围绕 Y 轴旋转对象,据说所有这些都运行良好。
随着我不断改进我的物品放置代码,我意识到这不适用于近乎垂直的平面。例如,尝试将图片放在墙上。此代码似乎可以将物品放置在接近水平(平坦)的地形上,但对于垂直墙来说,旋转距离很远。
我在这里遗漏了一个简单的计算吗?我是否需要以某种方式计算 y 轴值?我也尝试使用 atan2 函数计算旋转:
placeItemData.placeMesh.meshRot.z = (atan2(finalNormal.x,finalNormal.y) );
placeItemData.placeMesh.meshRot.x = (atan2(finalNormal.z,finalNormal.y) );
但我遇到了类似的问题。
我需要使用四元数进行这些计算吗?我能否再次轻松地将最终旋转值存储在 3D 向量 (x,y,z) 中?
感谢您的帮助!
更新 1
这是使用此代码的图像:
meshRot.z = - atan2(sqrt(finalNormal.y^2 + finalNormal.z^2), finalNormal.x);
meshRot.x = - atan2(finalNormal.y, finalNormal.z);
(来源:crystaldragon.com)
当您将鼠标悬停在石头上时,会计算三角形的法线(对于图片,石头面的法线是 (0.637, -0.014, 0.770) )。当然你在石头里看到的木块,应该是直接铺在石头边上的(就像挂成画一样)。
更新 2
通过在我的世界中测试位于 z 轴上的“墙”,我似乎让代码适用于所有 y=0 的情况。我可以将对象放置在所有垂直墙壁上,但不能放置在墙壁的水平(顶部)上。
这是当前代码:
placeItemData.placeMesh.meshRot.x = -(atan2(finalNormal.y, sqrt((finalNormal.x * finalNormal.x ) + (finalNormal.z * finalNormal.z)) ) + (D3DX_PI/2));
placeItemData.placeMesh.meshRot.z = -(atan2(finalNormal.z, finalNormal.x ) + (D3DX_PI/2));
只要 y 法线的值为 0,对象就会附着在每个垂直的墙壁上,但不会附着在水平面上(因为 y 法线显然是非负数)。希望最后一步是找出我需要作为 y 值输入方程的最终计算,但我仍然想出失败的尝试。
【问题讨论】:
我知道旋转,但我不知道 Direct3D。旋转的两个值就足够了,但是当你使用meshrot
中的值来旋转对象时,你是用自己的代码来做还是调用 Direct3D 函数?
我只知道这将与atan2
在atan2(0, -x)
的不连续性有关。
这就是我做旋转矩阵的方式:D3DXMatrixRotationYawPitchRoll(&matRotate, 0.0f, meshRot.x, meshRot.z ); D3DXMatrixRotationYawPitchRoll(&matRotate2, meshRot.y, 0.0f, 0.0f ); D3DXMatrixMultiply(&matRotate, &matRotate2, &matRotate);
那张图真的不太清楚。我们说的是石头的哪一面?轴在哪里?那个黑色的斑点是木块吗?它应该有什么方向?
抱歉图片不佳。我试图说明的是算法没有与岩壁对齐,我给出的向量 (0.637, -0.014, 0.770) 是岩壁侧面的法线,物体(木块粘在上面) out) 应该对齐到。显然,旋转没有正确对齐该法线向量。
【参考方案1】:
对于接近水平(平坦)的地形,地形位于 X-Z 平面上,因此法线的 y 值很可能是 1.0,这应该会给您不使用 y 法线的正确旋转。
但是,当向墙壁添加对象时,需要 y 法线来计算旋转的 y 分量。您说玩家可以在放置对象之前手动围绕 Y 轴旋转对象。
那是您使用法线的 y 值计算旋转的 y 分量的地方吗?如果没有,请确保您也在计算它。否则,您将在 2D 中计算旋转,并以某种方式将其外推到 3D。
【讨论】:
所以对于展示位置,我目前没有在项目展示位置的任何计算中使用 y 组件。 y 旋转只是在事后添加为对象自己的“单独”旋转。我把轮换代码放到了上面的注释块里。【参考方案2】:我会推荐四元数。你可以在没有它们的情况下让它工作,但你的代码必须对零进行大量检查,如果你尝试为任何东西设置动画,就会出现不连续性。四元数有一点学习曲线,但一旦你有了:
一种旋转方式
从笛卡尔(或极坐标或其他)到四元数的转换
从四元数到笛卡尔(或其他)的转换
使用起来非常简单,它们是 3D 操作的正确选择。
老实说,您不必了解数学即可使其工作;你只需要能够遵循四元数的数学规则。
【讨论】:
谢谢。如果我不能让更“传统”的方法发挥作用,我可能会走这条路。【参考方案3】:我不知道 Direct3D,但是通过快速查看文档,看起来这就是您想要的:
meshRot.z = - atan2(sqrt(finalNormal.y^2 + finalNormal.z^2), finalNormal.x);
meshRot.x = - atan2(finalNormal.y, finalNormal.z);
(我不知道这是否是正确的语法,例如 sqrt
,但你知道我在做什么。)
关于 Y 轴的旋转(“偏航”)可以留给用户 - 它对应于将雕像从朝北旋转到朝东,或者将一幅画倒挂在墙上。
我假设旋转是关于对象固定轴的。如果不是这种情况,那么解决方案将看起来完全不同。试一试,如果不起作用,我们可以尝试几个简单的测试用例来确定它。
【讨论】:
非常感谢您的帮助!我已对我的原始帖子添加了更新,显示了代码的当前结果并附有一些解释。我也会继续做一些研究。以上是关于旋转对象以匹配向量的主要内容,如果未能解决你的问题,请参考以下文章