我想了解如何测量两个3D对象之间的距离,我们称它们为父对象和子对象。把父母想象成一辆车的车身,把孩子想象成车的轮子。
我理解如何根据物体在世界空间中的位置获得差异,但我希望根据父母相对物体空间获得差异。
E。g如果父母面朝东,孩子离父母2X, 3Y,以相对意义来衡量。这样,如果父对象旋转60度,子对象的相对位置在对象空间中保持2x, 3y的距离。而在世界空间的意义上,子对象作为Vector3的测量将是完全不同的。
基本上,我只是想要一种可预测的方式来获得差异,以便位于专利右侧的子对象可以始终保持在父对象的右侧。
这是父组件,这个更新每帧运行一次:
[Serializable]
public class Component_Parent : BaseComponentAutoSerialization<ISceneEntity>
{
public override void OnUpdate(GameTime gameTime)
{
PassThrough.ParentMatrix = ParentObject.World;
PassThrough.ParentTranslation = ParentObject.World.Translation;
}
}
下一部分是子组件:
[Serializable]
public class Component_Child : BaseComponentAutoSerialization<ISceneEntity>
{
Vector3 _parentOffset;
Quaternion _parentQuaternionOffset;
public override void OnUpdate(GameTime gameTime)
{
// Get a sceneobject from the ParentObject
SceneObject sceneobject = (SceneObject)ParentObject;
// This relies on the position never being at 0,0,0 for setup, so please don't do that
// or change it with more look ups so that you don't need to rely on a Zero Vector3 :-)
if (PassThrough.GroupSetupMode || _parentOffset == Vector3.Zero)
{
if (PassThrough.ParentTranslation != Vector3.Zero)
{
_parentOffset = sceneobject.World.Translation - PassThrough.ParentTranslation;
// Decompose World Matrix (Parent)
Quaternion parentQ = new Quaternion();
Vector3 parentSpot = new Vector3();
Vector3 parentScale = new Vector3();
PassThrough.ParentMatrix.Decompose(out parentScale, out parentQ, out parentSpot);
Matrix identity = Matrix.Identity;
// Decompose Identity Matrix (Parent)
Quaternion identityQ = new Quaternion();
Vector3 identitySpot = new Vector3();
Vector3 identityScale = new Vector3();
identity.Decompose(out identityScale, out identityQ, out identitySpot);
_parentQuaternionOffset = identityQ - parentQ;
}
}
else
{
if (_parentOffset != Vector3.Zero)
{
// Decompose World Matrix (Child)
Quaternion rotationQ = new Quaternion();
Vector3 spot = new Vector3();
Vector3 scale = new Vector3();
sceneobject.World.Decompose(out scale, out rotationQ, out spot);
// Decompose World Matrix (Parent)
Quaternion parentQ = new Quaternion();
Vector3 parentSpot = new Vector3();
Vector3 parentScale = new Vector3();
PassThrough.ParentMatrix.Decompose(out parentScale, out parentQ, out parentSpot);
Matrix location = Matrix.CreateTranslation(PassThrough.ParentTranslation);
Matrix rotation = Matrix.CreateFromQuaternion(parentQ);
Matrix rotation2 = Matrix.CreateFromQuaternion(_parentQuaternionOffset);
Matrix newWorld = rotation * location;
Vector3 testTranslation = newWorld.Translation + ((newWorld.Left * _parentOffset.X) + (newWorld.Up * _parentOffset.Y) + (newWorld.Forward * _parentOffset.Z));
Matrix scaleM = Matrix.CreateScale(scale);
//sceneobject.World = scaleM * (rotation * (Matrix.CreateTranslation(testTranslation)));
sceneobject.World = (Matrix.CreateTranslation(testTranslation));
}
}
}
}
我认为这与跟踪偏移旋转有关,从单位矩阵开始,我已经开始尝试添加一些代码来达到这种效果,但真的不确定接下来要做什么。
附加:
如果我让父对象面向世界空间的方向,一切正常,如果它面向不同的方向,那么这是一个问题,当它们组合在一起时,子对象似乎旋转了相同的量。
我上传了一个演示视频来尝试解释:
http://www.youtube.com/watch?v=BzAKW4WBWYs我还粘贴了组件、静态通道和场景实体的完整代码。
http://pastebin.com/5hEmiVx9谢谢
想想汽车的轮子。我希望正确的轮子永远在同一个地方相对于车身的位置
听起来你想要能够在汽车的任何方向或位置上定位车轮的位置。XNA必须在这里提供帮助的一个内置方法是Model.CopyAbsoluteBoneTransformsTo(Matrix[]);但是,您的代码看起来像是要手动处理父子关系。这里有一种不使用内置方法的方法。它假定在加载时确实有偏移信息:
在游戏循环开始之前(例如,在LoadContent方法中),在加载汽车之后;假设它们加载到正确的位置,你就可以创建你的偏移向量(_parentOffset)
Vector3 _parentOffset = wheel.meshes[?].ParentBone.Transform.Translation - car.meshes[?].ParentBone.Transform.Translation;//where ? is the mesh index of the mesh you are setting up.
保存矢量,不要修改。
之后,在汽车的矩阵进行了旋转和/或位置位移后,像这样设置车轮的矩阵:
Matrix wheelMatrix = carMatrix;
wheelMatrix.Translation += (wheelMatrix.Right * _parentOffset.X) +
(wheelMatrix.Up * _parentOffset.Y) +
(wheelMatrix.Backward * _parentOffset.Z);
这允许车轮矩阵将继承来自汽车的任何旋转和动信息,但无论汽车的方向/位置如何,车轮的位置都会适当地移位。
两个物体之间的距离不是任何方向的函数。
你想要的基本上是子对象到父对象方向线的距离。假设你有一个全局笛卡尔坐标系,这可以简单地计算为h=sqrt(x^2+y^2)*sin(Theta), x和y是子节点相对于父节点的相对坐标,Theta是父节点从x轴开始的方向。
但是这个问题还是让我有点困惑。如果你只是想确保孩子在父母的右边,为什么不直接检查相对x呢?如果它是正的,它在右边如果它是负的,它在左边?
问题是我试图使用世界空间的偏移量的方式。由于从#XNA在EFnet上闪过,这段代码工作得很完美:
[Serializable]
public class Component_Child_fromxna : BaseComponentAutoSerialization<ISceneEntity>
{
Vector3 _parentOffset;
Matrix _ParentMatrixOffset;
public override void OnUpdate(GameTime gameTime)
{
// Get a sceneobject from the ParentObject
SceneObject sceneObject = (SceneObject)ParentObject;
// This relies on the position never being at 0,0,0 for setup, so please don't do that
// or change it with more look ups so that you don't need to rely on a Zero Vector3 :-)
if (PassThrough.GroupSetupMode || _parentOffset == Vector3.Zero)
{
if (PassThrough.ParentTranslation != Vector3.Zero)
{
// The old offset - This is just in world space though...
_parentOffset = sceneObject.World.Translation - PassThrough.ParentTranslation;
// Get the distance between the child and the parent which we keep as the offset
// Inversing the ParentMatrix and multiplying it by the childs matrix gives an offset
// The offset is stored as a relative xyz, based on the parents object space
_ParentMatrixOffset = sceneObject.World * Matrix.Invert(PassThrough.ParentMatrix);
}
}
else
{
if (_parentOffset != Vector3.Zero)
{
//Matrix pLocation = Matrix.CreateTranslation(_parentOffset);
//sceneObject.World = Matrix.Multiply(pLocation, PassThrough.ParentMatrix);
sceneObject.World = Matrix.Multiply(_ParentMatrixOffset, PassThrough.ParentMatrix);
}
}
}
}