使用笛卡尔坐标和欧拉角控制 OpenSceneGraph 相机 [英] Controling OpenSceneGraph camera with Cartesian coordinates and Euler angles

查看:142
本文介绍了使用笛卡尔坐标和欧拉角控制 OpenSceneGraph 相机的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用从文件中读取的笛卡尔坐标(X、Y、Z)和欧拉角(偏航、俯仰、滚动)来控制 osg::Camera.

I am attempting to control an osg::Camera with Cartesian coordinates (X, Y, Z) and Euler angles (Yaw, Pitch, Roll) that I read in from file.

第 1 部分

由于某种原因,设置我的滚动会导致相机围绕 z 轴旋转,而不是像预期的那样围绕 y 轴旋转.

For some reason setting my roll will cause the camera to rotate around the z-axis and not the y-axis as expected.

以下是我将位置数据输入到的先前编写的相机操纵器.

The following is the previously written camera manipulator that I am feeding my positional data to.

class EulerManipulator : public osgGA::CameraManipulator
{
    public:
        EulerManipulator(osg::ref_ptr<osg::View> x) :
            view(x),
            camView(new osg::CameraView)
        {
        }

        virtual ~EulerManipulator(){}

        virtual osg::Matrixd getMatrix() const
        {
            // Note: (x, y, z) and (yaw, pitch, roll) are read in from file and saved in memory

            // Position works fine
            this->camView->setPosition(osg::Vec3d(x, y, z));

            // Possibly something wrong with rotation
            osg::Quat rotationQuat;

            const osg::Vec3d headingAxis(0.0, 0.0, 1.0);
            const osg::Vec3d pitchAxis(1.0, 0.0, 0.0);
            const osg::Vec3d rollAxis(0.0, 1.0, 0.0);

            std::array<double, 3> rotation = {yaw, pitch, roll};

            rotationQuat.makeRotate(
                deg2rad(rotation[2]), rollAxis, 
                deg2rad(rotation[1] + 90.0f), pitchAxis, 
                -deg2rad(rotation[0]), headingAxis);

            this->camView->setAttitude(rotationQuat);

            // Not 100% sure what this does but assume it works as Heading and Pitch seem to work fine.
            auto nodePathList = this->camView->getParentalNodePaths();
            return osg::computeLocalToWorld(nodePathList[0]);
        }

    private:
        osg::ref_ptr<osg::View> view;
        osg::ref_ptr<osg::CameraView> camView;
};

注意:上面的代码不是我自己的,而是用来驱动相机的代码.我的目标是从我自己的相机中获取笛卡尔位置和欧拉角并写入文件.但在此之前,我需要弄清楚为什么这段代码没有按预期运行.

Note: The above code is not my own but is the code that is being used to drive the camera. My goal is to grab the Cartesian position and Euler angles from my own camera and write out to file. But before I can do this, I need to figure out why this code isn't behaving as expected.

上面的代码有什么明显的错误吗?

Is there anything obviously wrong with the above code?

第 2 部分

对于这个问题的第二部分,我正在捕获相机的位置数据并将其写入文件.

For the second part of this problem I am capturing the camera's positional data and writing it to a file.

我已经取得了一些成功,但它仍然不能正常工作.下面是我为附加到我的视图的事件处理程序编写的重载句柄函数.目标是在我在场景中移动相机时捕捉相机的位置数据.

I have had a little success but it still isn't working quite correctly. Below is the overloaded handle function I wrote for an event handler that is attached to my view. The goal is to capture the camera's positional data as I move the camera around within the scene.

在这里我运行我的程序并水平旋转相机(偏航)但由于某种原因俯仰角急剧下降.如果我从 0 度偏航转到 90 度偏航.我的俯仰角将从 0 度减小到大约 90 度.我原以为在水平旋转相机时我的音高大致保持不变.

Here I run my program and rotate the camera horizontally (yaw) but for some reason the pitch angle decreases drastically. If I go from 0 degree yaw to 90 degree yaw. My pitch angle will decrease from 0 to about 90 degrees. I would have expected my pitch to remain roughly the same as I rotate the camera horizontally.

    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter&, osg::Object*, osg::NodeVisitor*) override
    {
        switch(ea.getEventType())
        {
            case osgGA::GUIEventAdapter::FRAME:
                {
                    if((this->camera != nullptr))
                    {
                        osg::Vec3d center;
                        osg::Vec3d vecDontCare;
                        this->camera->getViewMatrixAsLookAt(vecDontCare, center, vecDontCare);

                        auto rotation = this->camera->getViewMatrix().getRotate();

                        std::array<double, 4> quat = {{rotation.x(), rotation.y(), rotation.z(), rotation.w()}};

                        // Assuming this conversion is correct
                        auto ypr = Quaternion2YawPitchRoll(quat);

                        // Convert the rotation into my coordinate system.
                        ypr[0] *= -1.0;
                        ypr[1] -= 90.0;

                        // The output angles for YPR don't appear to align with the manual rotation I perform with the camera
                        Debug << "Y: " << ypr[0] << " P: " << ypr[1] << " R: " << ypr[2];
                        // Write XYZ and YPR to file
                    }
                }
                break;

            default:
                break;
        }

问题是,我获取相机位置数据的方式有什么明显的问题吗?有没有更好的方法?

The question is, is there anything obviously wrong with the way i'm grabbing the camera's positional data? Is there a better way to do so?

推荐答案

第 1 部分

问题在于我将角度添加到四元数的顺序.

The issue was the order in which I added my angles to the quaternion.

rotationQuat.makeRotate(
    deg2rad(rotation[1] + 90.0f), pitchAxis,
    deg2rad(rotation[2]), rollAxis, 
    -deg2rad(rotation[0]), headingAxis);

在绕 X 轴旋转时必须首先添加 Pitch

Pitch had to be added first as it rotates around the X-Axis

第 2 部分

这里有几件事是错误的.

A couple of things were wrong here.

首先,我需要获取逆视图矩阵.我不是 100% 确定为什么,也许有更多知识的人可以发表评论,但它有效.

First, I needed to grab the inverse view matrix. I'm not 100% sure why, maybe someone with more knowledge can leave a comment, but it works.

auto rotation = this->camera->getViewInverseMatrix().getRotate();

其次,假设转换函数正确结果证明是错误的.我写了一个单元测试,但这个功能没有,结果证明是错误的.

Secondly, Assuming the conversion function was correct turned out to be bad. I wrote a unit test that was missing for this function and it turns out it was wrong.

// Assuming this conversion is correct
auto ypr = Quaternion2YawPitchRoll(quat);

这篇关于使用笛卡尔坐标和欧拉角控制 OpenSceneGraph 相机的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆