Controling OpenSceneGraph camera with Cartesian coordinates and Euler angles

巧了我就是萌 提交于 2019-12-06 12:26:13

问题


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.

Part 1

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?

Part 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.

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:


Part 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);

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

Part 2

A couple of things were wrong here.

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);


来源:https://stackoverflow.com/questions/32595198/controling-openscenegraph-camera-with-cartesian-coordinates-and-euler-angles

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!