osg的四元数连乘

实验中,xquat是竖直的那个,yquat是与屏幕平行的那个,zquat是水平的那个。如果是vec2 = quatxquatyquatZ*vec1,则先转xquat,再转yquat,再转zquat,
问题来了,如果多个步骤,该怎么办?顺序的不同,会导致结果的不同
那就设定一个数组,

struct DataRange : public osg::Referenced
{
//四元数数组
std::vectorosg::Quat _quatVector = std::vectorosg::Quat();
//六个面的法线
std::vectorosg::Vec3d _normalVector = std::vectorosg::Vec3d();
//中心点初始坐标(可能没在原点上)
osg::Vec3d _center;
//当前旋转的dir,也就是哪个dragger在起作用
RotateCutDirection _dir = None;
};

在release时,把该四元数加入到数组中

bool MyRotateCylinderDragger::handle(
const osgManipulator::PointerInfo& pointer,
const osgGA::GUIEventAdapter& ea,
osgGA::GUIActionAdapter& aa)
{
// Check if the dragger node is in the nodepath.
if (!pointer.contains(this)) return false;

switch (ea.getEventType())
{
	// Pick start.
case (osgGA::GUIEventAdapter::PUSH):
{
	_bRelease = false;
	_dataRange->_dir = _dir;
	// Get the LocalToWorld matrix for this node and set it for the projector.
	osg::NodePath nodePathToRoot;
	computeNodePathToRoot(*this, nodePathToRoot);
	osg::Matrix localToWorld = osg::computeLocalToWorld(nodePathToRoot);
	_projector->setLocalToWorld(localToWorld);

	_startLocalToWorld = _projector->getLocalToWorld();
	_startWorldToLocal = _projector->getWorldToLocal();

	if (_projector->isPointInFront(pointer, _startLocalToWorld))
		_projector->setFront(true);
	else
		_projector->setFront(false);

	osg::Vec3d projectedPoint;
	if (_projector->project(pointer, projectedPoint))
	{
		// Generate the motion command.
		osg::ref_ptr<osgManipulator::Rotate3DCommand> cmd = new osgManipulator::Rotate3DCommand();
		cmd->setStage(osgManipulator::MotionCommand::START);
		cmd->setLocalToWorldAndWorldToLocal(_startLocalToWorld, _startWorldToLocal);

		// Dispatch command.
		dispatch(*cmd);

		// Set color to pick color.
		setMaterialColor(_pickColor, *this);

		_prevWorldProjPt = projectedPoint * _projector->getLocalToWorld();
		_prevRotation = osg::Quat();

		aa.requestRedraw();
	}
	return true;
}

// Pick move.
case (osgGA::GUIEventAdapter::DRAG):
{
	_bRelease = false;
	_dataRange->_dir = _dir;

	// Get the LocalToWorld matrix for this node and set it for the projector.
	osg::Matrix localToWorld = osg::Matrix(_prevRotation) * _startLocalToWorld;
	_projector->setLocalToWorld(localToWorld);

	osg::Vec3d projectedPoint;
	if (_projector->project(pointer, projectedPoint))
	{
		osg::Vec3d prevProjectedPoint = _prevWorldProjPt * _projector->getWorldToLocal();
		osg::Quat  deltaRotation = _projector->getRotation(prevProjectedPoint,
			projectedPoint);
		osg::Quat rotation = deltaRotation * _prevRotation;

		// Generate the motion command.
		osg::ref_ptr<osgManipulator::Rotate3DCommand> cmd = new osgManipulator::Rotate3DCommand();
		cmd->setStage(osgManipulator::MotionCommand::MOVE);
		cmd->setLocalToWorldAndWorldToLocal(_startLocalToWorld, _startWorldToLocal);
		cmd->setRotation(rotation);

		// Dispatch command.
		dispatch(*cmd);

		_prevWorldProjPt = projectedPoint * _projector->getLocalToWorld();
		_prevRotation = rotation;
		aa.requestRedraw();
	}
	return true;
}

// Pick finish.
case (osgGA::GUIEventAdapter::RELEASE):
{
	osg::ref_ptr<osgManipulator::Rotate3DCommand> cmd = new osgManipulator::Rotate3DCommand();

	cmd->setStage(osgManipulator::MotionCommand::FINISH);
	cmd->setLocalToWorldAndWorldToLocal(_startLocalToWorld, _startWorldToLocal);

	// Dispatch command.
	dispatch(*cmd);

	// Reset color.
	setMaterialColor(_color, *this);

	aa.requestRedraw();

	_bRelease = true;
	_dataRange->_dir = _dir;
	_dataRange->_quatVector.push_back(_prevRotation);
	return true;
}
default:
	return false;
}

}
其中每个dragger对应一个旋转轴,可以用枚举

MyCylinderPlaneProjector::MyCylinderPlaneProjector(RotateCutDirection dir)
:osgManipulator::CylinderPlaneProjector()
{
switch (dir)
{
case xAxis:
_cylinderAxis = osg::Vec3d(1.0, 0.0, 0.0);
break;
case yAxis:
_cylinderAxis = osg::Vec3d(0.0, 1.0, 0.0);
break;
case zAxis:
_cylinderAxis = osg::Vec3d(0.0, 0.0, 1.0);
break;
default:
break;
}
}
每帧返回当前四元数

osg::Quat MyRotateCylinderDragger::getRotation()
{
osg::Quat currentSegmentBeginQuat = osg::Quat();
for (int i = 0; i < _dataRange->_quatVector.size(); i++)
{
osg::Quat theQuat = _dataRange->_quatVector[i];
currentSegmentBeginQuat = currentSegmentBeginQuat * theQuat;
}
if (_bRelease)
{
return currentSegmentBeginQuat;
}
return currentSegmentBeginQuat * _prevRotation;
}
使用时通过回调函数每帧更改

osg::Quat theQuat = dragger->getRotation();
if (_lastQuat == theQuat)
{
	return;
}
_lastQuat = theQuat;
创建到顶点的Geode
_lineGroup->removeChild(0, _lineGroup->getNumChildren());
for (int i = 0; i < _lineVec.size(); i++)
{
	osg::Vec3d pos = _lineVec[i];
	osg::Vec3d lineVec = theQuat* pos;
	osg::ref_ptr<osg::Geode> linegeode = CreateRedLine(lineVec);
	//_lineGroup->addChild(linegeode);
}
创建到法线点的Geode
osg::Vec3d center = theQuat * _dataRange->_center;
_normalGroup->removeChild(0, _normalGroup->getNumChildren());
for (int i = 0; i < _startNormalVec.size(); i++)
{
	osg::Vec3d pos = _startNormalVec[i];
	_dataRange->_normalVector[i] = theQuat * pos;
	osg::ref_ptr<osg::Geode> normalgeode = CreateNormalLine(center,_dataRange->_normalVector[i]);
	_normalGroup->addChild(normalgeode);
	UpdateClipRender(_clipNode, _dataRange->_normalVector[i], center -_dataRange->_normalVector[i], i);
}

如下图所示
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其实,进一步想,四元数代表旋转矩阵,用矩阵数组也可以,

好处在哪里呢?
1,这样可以考虑把平移也加到矩阵数组里,
2,从vec2 = quat1quat2quat3*vec1来看,总觉得不舒服,因为,最后的应该最后相乘。如果换成矩阵呢?
vec2 = vec1 * matrix1 * matrix2 * matrix3,这样符合矩阵结合律。顺序是自然的

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值